Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_mp4_module.c @ 4662:979e0f5b196d stable-1.2
Merge of r4616: r->state fix.
Added r->state reset on fastcgi/scgi/uwsgi request start.
Failing to do so results in problems if 400 or 414 requests are
redirected to fastcgi/scgi/uwsgi upstream, as well as after invalid
headers got from upstream. This was already fixed for proxy in r3478,
but fastcgi (the only affected protocol at that time) was missed.
Reported by Matthieu Tourne.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 04 Jun 2012 10:54:48 +0000 |
parents | f12d474f0d5e |
children | 7f50a4063100 1c7616100797 |
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 | |
589 if (ngx_http_set_content_type(r) != NGX_OK) { | |
590 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
591 } | |
592 | |
593 if (mp4 == NULL) { | |
594 b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); | |
595 if (b == NULL) { | |
596 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
597 } | |
598 | |
599 b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); | |
600 if (b->file == NULL) { | |
601 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
602 } | |
603 } | |
604 | |
605 rc = ngx_http_send_header(r); | |
606 | |
607 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { | |
608 return rc; | |
609 } | |
610 | |
611 if (mp4) { | |
612 return ngx_http_output_filter(r, mp4->out); | |
613 } | |
614 | |
615 b->file_pos = 0; | |
616 b->file_last = of.size; | |
617 | |
618 b->in_file = b->file_last ? 1 : 0; | |
4659
f12d474f0d5e
Merge of r4612: proper subrequest handling in various modules.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4585
diff
changeset
|
619 b->last_buf = (r == r->main) ? 1 : 0; |
4085 | 620 b->last_in_chain = 1; |
621 | |
622 b->file->fd = of.fd; | |
623 b->file->name = path; | |
624 b->file->log = log; | |
625 b->file->directio = of.is_directio; | |
626 | |
627 out.buf = b; | |
628 out.next = NULL; | |
629 | |
630 return ngx_http_output_filter(r, &out); | |
631 } | |
632 | |
633 | |
634 static ngx_int_t | |
635 ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) | |
636 { | |
637 off_t start_offset, adjustment; | |
638 ngx_int_t rc; | |
639 ngx_uint_t i, j; | |
640 ngx_chain_t **prev; | |
641 ngx_http_mp4_trak_t *trak; | |
642 ngx_http_mp4_conf_t *conf; | |
643 | |
644 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
645 "mp4 start:%ui", mp4->start); | |
646 | |
647 conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module); | |
648 | |
649 mp4->buffer_size = conf->buffer_size; | |
650 | |
651 rc = ngx_http_mp4_read_atom(mp4, ngx_http_mp4_atoms, mp4->end); | |
652 if (rc != NGX_OK) { | |
653 return rc; | |
654 } | |
655 | |
656 if (mp4->trak.nelts == 0) { | |
657 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
658 "no mp4 trak atoms were found in \"%s\"", | |
659 mp4->file.name.data); | |
660 return NGX_ERROR; | |
661 } | |
662 | |
663 if (mp4->mdat_atom.buf == NULL) { | |
664 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
665 "no mp4 mdat atom was found in \"%s\"", | |
666 mp4->file.name.data); | |
667 return NGX_ERROR; | |
668 } | |
669 | |
670 prev = &mp4->out; | |
671 | |
672 if (mp4->ftyp_atom.buf) { | |
673 *prev = &mp4->ftyp_atom; | |
674 prev = &mp4->ftyp_atom.next; | |
675 } | |
676 | |
677 *prev = &mp4->moov_atom; | |
678 prev = &mp4->moov_atom.next; | |
679 | |
680 if (mp4->mvhd_atom.buf) { | |
681 mp4->moov_size += mp4->mvhd_atom_buf.last - mp4->mvhd_atom_buf.pos; | |
682 *prev = &mp4->mvhd_atom; | |
683 prev = &mp4->mvhd_atom.next; | |
684 } | |
685 | |
686 start_offset = mp4->end; | |
687 trak = mp4->trak.elts; | |
688 | |
689 for (i = 0; i < mp4->trak.nelts; i++) { | |
690 | |
691 if (ngx_http_mp4_update_stts_atom(mp4, &trak[i]) != NGX_OK) { | |
692 return NGX_ERROR; | |
693 } | |
694 | |
695 if (ngx_http_mp4_update_stss_atom(mp4, &trak[i]) != NGX_OK) { | |
696 return NGX_ERROR; | |
697 } | |
698 | |
699 ngx_http_mp4_update_ctts_atom(mp4, &trak[i]); | |
700 | |
701 if (ngx_http_mp4_update_stsc_atom(mp4, &trak[i]) != NGX_OK) { | |
702 return NGX_ERROR; | |
703 } | |
704 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
705 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
|
706 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
707 } |
4085 | 708 |
4112 | 709 if (trak[i].out[NGX_HTTP_MP4_CO64_DATA].buf) { |
710 if (ngx_http_mp4_update_co64_atom(mp4, &trak[i]) != NGX_OK) { | |
711 return NGX_ERROR; | |
712 } | |
713 | |
714 } else { | |
715 if (ngx_http_mp4_update_stco_atom(mp4, &trak[i]) != NGX_OK) { | |
716 return NGX_ERROR; | |
717 } | |
4085 | 718 } |
719 | |
720 ngx_http_mp4_update_stbl_atom(mp4, &trak[i]); | |
721 ngx_http_mp4_update_minf_atom(mp4, &trak[i]); | |
722 trak[i].size += trak[i].mdhd_size; | |
723 trak[i].size += trak[i].hdlr_size; | |
724 ngx_http_mp4_update_mdia_atom(mp4, &trak[i]); | |
725 trak[i].size += trak[i].tkhd_size; | |
726 ngx_http_mp4_update_trak_atom(mp4, &trak[i]); | |
727 | |
728 mp4->moov_size += trak[i].size; | |
729 | |
730 if (start_offset > trak[i].start_offset) { | |
731 start_offset = trak[i].start_offset; | |
732 } | |
733 | |
734 *prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM]; | |
735 prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM].next; | |
736 | |
737 for (j = 0; j < NGX_HTTP_MP4_LAST_ATOM + 1; j++) { | |
738 if (trak[i].out[j].buf) { | |
739 *prev = &trak[i].out[j]; | |
740 prev = &trak[i].out[j].next; | |
741 } | |
742 } | |
743 } | |
744 | |
745 mp4->moov_size += 8; | |
746 | |
747 ngx_mp4_set_32value(mp4->moov_atom_header, mp4->moov_size); | |
748 ngx_mp4_set_atom_name(mp4->moov_atom_header, 'm', 'o', 'o', 'v'); | |
749 mp4->content_length += mp4->moov_size; | |
750 | |
751 *prev = &mp4->mdat_atom; | |
752 | |
753 adjustment = mp4->ftyp_size + mp4->moov_size | |
754 + ngx_http_mp4_update_mdat_atom(mp4, start_offset) | |
755 - start_offset; | |
756 | |
4088
8fe1da7b8386
bugfix of r4086: nginx could not be built without debug log.
Igor Sysoev <igor@sysoev.ru>
parents:
4087
diff
changeset
|
757 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
4579 | 758 "mp4 adjustment:%O", adjustment); |
4085 | 759 |
760 for (i = 0; i < mp4->trak.nelts; i++) { | |
4112 | 761 if (trak[i].out[NGX_HTTP_MP4_CO64_DATA].buf) { |
762 ngx_http_mp4_adjust_co64_atom(mp4, &trak[i], adjustment); | |
763 } else { | |
764 ngx_http_mp4_adjust_stco_atom(mp4, &trak[i], (int32_t) adjustment); | |
765 } | |
4085 | 766 } |
767 | |
768 return NGX_OK; | |
769 } | |
770 | |
771 | |
772 typedef struct { | |
773 u_char size[4]; | |
774 u_char name[4]; | |
775 } ngx_mp4_atom_header_t; | |
776 | |
777 typedef struct { | |
778 u_char size[4]; | |
779 u_char name[4]; | |
780 u_char size64[8]; | |
781 } ngx_mp4_atom_header64_t; | |
782 | |
783 | |
784 static ngx_int_t | |
785 ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4, | |
786 ngx_http_mp4_atom_handler_t *atom, uint64_t atom_data_size) | |
787 { | |
788 off_t end; | |
789 size_t atom_header_size; | |
790 u_char *atom_header, *atom_name; | |
791 uint64_t atom_size; | |
792 ngx_int_t rc; | |
793 ngx_uint_t n; | |
794 | |
795 end = mp4->offset + atom_data_size; | |
796 | |
797 while (mp4->offset < end) { | |
798 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
799 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
|
800 return NGX_ERROR; |
4085 | 801 } |
802 | |
803 atom_header = mp4->buffer_pos; | |
804 atom_size = ngx_mp4_get_32value(atom_header); | |
805 atom_header_size = sizeof(ngx_mp4_atom_header_t); | |
806 | |
807 if (atom_size == 0) { | |
808 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
809 "mp4 atom end"); | |
810 return NGX_OK; | |
811 } | |
812 | |
813 if (atom_size < sizeof(ngx_mp4_atom_header_t)) { | |
814 | |
815 if (atom_size == 1) { | |
816 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
817 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
|
818 != NGX_OK) |
4085 | 819 { |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
820 return NGX_ERROR; |
4085 | 821 } |
822 | |
823 /* 64-bit atom size */ | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
824 atom_header = mp4->buffer_pos; |
4085 | 825 atom_size = ngx_mp4_get_64value(atom_header + 8); |
826 atom_header_size = sizeof(ngx_mp4_atom_header64_t); | |
827 | |
828 } else { | |
829 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
830 "\"%s\" mp4 atom is too small:%uL", | |
831 mp4->file.name.data, atom_size); | |
832 return NGX_ERROR; | |
833 } | |
834 } | |
835 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
836 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
|
837 return NGX_ERROR; |
4085 | 838 } |
839 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
840 atom_header = mp4->buffer_pos; |
4085 | 841 atom_name = atom_header + sizeof(uint32_t); |
842 | |
4088
8fe1da7b8386
bugfix of r4086: nginx could not be built without debug log.
Igor Sysoev <igor@sysoev.ru>
parents:
4087
diff
changeset
|
843 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
4085 | 844 "mp4 atom: %*s @%O:%uL", |
845 4, atom_name, mp4->offset, atom_size); | |
846 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
847 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
|
848 || mp4->offset + (off_t) atom_size > end) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
849 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
850 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
851 "\"%s\" mp4 atom too large:%uL", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
852 mp4->file.name.data, atom_size); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
853 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
854 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
855 |
4085 | 856 for (n = 0; atom[n].name; n++) { |
857 | |
858 if (ngx_strncmp(atom_name, atom[n].name, 4) == 0) { | |
859 | |
860 ngx_mp4_atom_next(mp4, atom_header_size); | |
861 | |
862 rc = atom[n].handler(mp4, atom_size - atom_header_size); | |
863 if (rc != NGX_OK) { | |
864 return rc; | |
865 } | |
866 | |
867 goto next; | |
868 } | |
869 } | |
870 | |
871 ngx_mp4_atom_next(mp4, atom_size); | |
872 | |
873 next: | |
874 continue; | |
875 } | |
876 | |
877 return NGX_OK; | |
878 } | |
879 | |
880 | |
881 static ngx_int_t | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
882 ngx_http_mp4_read(ngx_http_mp4_file_t *mp4, size_t size) |
4085 | 883 { |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
884 ssize_t n; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
885 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
886 if (mp4->buffer_pos + size <= mp4->buffer_end) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
887 return NGX_OK; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
888 } |
4085 | 889 |
890 if (mp4->offset + (off_t) mp4->buffer_size > mp4->end) { | |
891 mp4->buffer_size = (size_t) (mp4->end - mp4->offset); | |
892 } | |
893 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
894 if (mp4->buffer_size < size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
895 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
896 "\"%s\" mp4 file truncated", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
897 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
898 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
899 |
4085 | 900 if (mp4->buffer == NULL) { |
901 mp4->buffer = ngx_palloc(mp4->request->pool, mp4->buffer_size); | |
902 if (mp4->buffer == NULL) { | |
903 return NGX_ERROR; | |
904 } | |
905 | |
906 mp4->buffer_start = mp4->buffer; | |
907 } | |
908 | |
909 n = ngx_read_file(&mp4->file, mp4->buffer_start, mp4->buffer_size, | |
910 mp4->offset); | |
911 | |
912 if (n == NGX_ERROR) { | |
913 return NGX_ERROR; | |
914 } | |
915 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
916 if ((size_t) n != mp4->buffer_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
917 ngx_log_error(NGX_LOG_CRIT, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
918 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
|
919 n, mp4->buffer_size, mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
920 return NGX_ERROR; |
4085 | 921 } |
922 | |
923 mp4->buffer_pos = mp4->buffer_start; | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
924 mp4->buffer_end = mp4->buffer_start + mp4->buffer_size; |
4085 | 925 |
926 return NGX_OK; | |
927 } | |
928 | |
929 | |
930 static ngx_int_t | |
931 ngx_http_mp4_read_ftyp_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
932 { | |
933 u_char *ftyp_atom; | |
934 size_t atom_size; | |
935 ngx_buf_t *atom; | |
936 | |
937 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 ftyp atom"); | |
938 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
939 if (atom_data_size > 1024 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
940 || 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
|
941 { |
4085 | 942 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
943 "\"%s\" mp4 ftyp atom is too large:%uL", | |
944 mp4->file.name.data, atom_data_size); | |
945 return NGX_ERROR; | |
946 } | |
947 | |
948 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
949 | |
950 ftyp_atom = ngx_palloc(mp4->request->pool, atom_size); | |
951 if (ftyp_atom == NULL) { | |
952 return NGX_ERROR; | |
953 } | |
954 | |
955 ngx_mp4_set_32value(ftyp_atom, atom_size); | |
956 ngx_mp4_set_atom_name(ftyp_atom, 'f', 't', 'y', 'p'); | |
957 | |
958 /* | |
959 * only moov atom content is guaranteed to be in mp4->buffer | |
960 * during sending response, so ftyp atom content should be copied | |
961 */ | |
962 ngx_memcpy(ftyp_atom + sizeof(ngx_mp4_atom_header_t), | |
963 ngx_mp4_atom_data(mp4), (size_t) atom_data_size); | |
964 | |
965 atom = &mp4->ftyp_atom_buf; | |
966 atom->temporary = 1; | |
967 atom->pos = ftyp_atom; | |
968 atom->last = ftyp_atom + atom_size; | |
969 | |
970 mp4->ftyp_atom.buf = atom; | |
971 mp4->ftyp_size = atom_size; | |
972 mp4->content_length = atom_size; | |
973 | |
974 ngx_mp4_atom_next(mp4, atom_data_size); | |
975 | |
976 return NGX_OK; | |
977 } | |
978 | |
979 | |
980 /* | |
981 * Small excess buffer to process atoms after moov atom, mp4->buffer_start | |
982 * will be set to this buffer part after moov atom processing. | |
983 */ | |
984 #define NGX_HTTP_MP4_MOOV_BUFFER_EXCESS (4 * 1024) | |
985 | |
986 static ngx_int_t | |
987 ngx_http_mp4_read_moov_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
988 { | |
989 ngx_int_t rc; | |
990 ngx_uint_t no_mdat; | |
991 ngx_buf_t *atom; | |
992 ngx_http_mp4_conf_t *conf; | |
993 | |
994 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 moov atom"); | |
995 | |
996 no_mdat = (mp4->mdat_atom.buf == NULL); | |
997 | |
998 if (no_mdat && mp4->start == 0) { | |
999 /* | |
1000 * send original file if moov atom resides before | |
1001 * mdat atom and client requests integral file | |
1002 */ | |
1003 return NGX_DECLINED; | |
1004 } | |
1005 | |
1006 conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module); | |
1007 | |
1008 if (atom_data_size > mp4->buffer_size) { | |
1009 | |
4089
e27670e1ab70
mp4_max_moov_size directive has been renamed to mp4_max_buffer_size.
Igor Sysoev <igor@sysoev.ru>
parents:
4088
diff
changeset
|
1010 if (atom_data_size > conf->max_buffer_size) { |
4085 | 1011 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
1012 "\"%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
|
1013 "you may want to increase mp4_max_buffer_size", |
4085 | 1014 mp4->file.name.data, atom_data_size); |
1015 return NGX_ERROR; | |
1016 } | |
1017 | |
1018 ngx_pfree(mp4->request->pool, mp4->buffer); | |
1019 mp4->buffer = NULL; | |
1020 mp4->buffer_pos = NULL; | |
1021 mp4->buffer_end = NULL; | |
1022 | |
1023 mp4->buffer_size = (size_t) atom_data_size | |
1024 + NGX_HTTP_MP4_MOOV_BUFFER_EXCESS * no_mdat; | |
1025 } | |
1026 | |
1027 mp4->trak.elts = &mp4->traks; | |
1028 mp4->trak.size = sizeof(ngx_http_mp4_trak_t); | |
1029 mp4->trak.nalloc = 2; | |
1030 mp4->trak.pool = mp4->request->pool; | |
1031 | |
1032 atom = &mp4->moov_atom_buf; | |
1033 atom->temporary = 1; | |
1034 atom->pos = mp4->moov_atom_header; | |
1035 atom->last = mp4->moov_atom_header + 8; | |
1036 | |
1037 mp4->moov_atom.buf = &mp4->moov_atom_buf; | |
1038 | |
1039 rc = ngx_http_mp4_read_atom(mp4, ngx_http_mp4_moov_atoms, atom_data_size); | |
1040 | |
1041 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 moov atom done"); | |
1042 | |
1043 if (no_mdat) { | |
1044 mp4->buffer_start = mp4->buffer_pos; | |
1045 mp4->buffer_size = NGX_HTTP_MP4_MOOV_BUFFER_EXCESS; | |
1046 | |
1047 } else { | |
1048 /* skip atoms after moov atom */ | |
1049 mp4->offset = mp4->end; | |
1050 } | |
1051 | |
1052 return rc; | |
1053 } | |
1054 | |
1055 | |
1056 static ngx_int_t | |
1057 ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1058 { | |
1059 ngx_buf_t *data; | |
1060 | |
1061 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 mdat atom"); | |
1062 | |
1063 data = &mp4->mdat_data_buf; | |
1064 data->file = &mp4->file; | |
1065 data->in_file = 1; | |
1066 data->last_buf = 1; | |
1067 data->last_in_chain = 1; | |
1068 data->file_last = mp4->offset + atom_data_size; | |
1069 | |
1070 mp4->mdat_atom.buf = &mp4->mdat_atom_buf; | |
1071 mp4->mdat_atom.next = &mp4->mdat_data; | |
1072 mp4->mdat_data.buf = data; | |
1073 | |
1074 if (mp4->trak.nelts) { | |
1075 /* skip atoms after mdat atom */ | |
1076 mp4->offset = mp4->end; | |
1077 | |
1078 } else { | |
1079 ngx_mp4_atom_next(mp4, atom_data_size); | |
1080 } | |
1081 | |
1082 return NGX_OK; | |
1083 } | |
1084 | |
1085 | |
1086 static size_t | |
1087 ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset) | |
1088 { | |
1089 off_t atom_data_size; | |
1090 u_char *atom_header; | |
1091 uint32_t atom_header_size; | |
1092 uint64_t atom_size; | |
1093 ngx_buf_t *atom; | |
1094 | |
1095 atom_data_size = mp4->mdat_data.buf->file_last - start_offset; | |
1096 mp4->mdat_data.buf->file_pos = start_offset; | |
1097 | |
4088
8fe1da7b8386
bugfix of r4086: nginx could not be built without debug log.
Igor Sysoev <igor@sysoev.ru>
parents:
4087
diff
changeset
|
1098 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
4085 | 1099 "mdat new offset @%O:%O", start_offset, atom_data_size); |
1100 | |
1101 atom_header = mp4->mdat_atom_header; | |
1102 | |
4155
d9636bf3f159
Fix of building on platforms with 32-bit off_t. (closed #23)
Igor Sysoev <igor@sysoev.ru>
parents:
4112
diff
changeset
|
1103 if ((uint64_t) atom_data_size > 0xffffffff) { |
4085 | 1104 atom_size = 1; |
1105 atom_header_size = sizeof(ngx_mp4_atom_header64_t); | |
1106 ngx_mp4_set_64value(atom_header + sizeof(ngx_mp4_atom_header_t), | |
1107 sizeof(ngx_mp4_atom_header64_t) + atom_data_size); | |
1108 } else { | |
1109 atom_size = sizeof(ngx_mp4_atom_header_t) + atom_data_size; | |
1110 atom_header_size = sizeof(ngx_mp4_atom_header_t); | |
1111 } | |
1112 | |
4282
71cdac0b9ea6
Fix of "Content-Length" header of MP4 response if start argument was used.
Igor Sysoev <igor@sysoev.ru>
parents:
4189
diff
changeset
|
1113 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
|
1114 |
4085 | 1115 ngx_mp4_set_32value(atom_header, atom_size); |
1116 ngx_mp4_set_atom_name(atom_header, 'm', 'd', 'a', 't'); | |
1117 | |
1118 atom = &mp4->mdat_atom_buf; | |
1119 atom->temporary = 1; | |
1120 atom->pos = atom_header; | |
1121 atom->last = atom_header + atom_header_size; | |
1122 | |
1123 return atom_header_size; | |
1124 } | |
1125 | |
1126 | |
1127 typedef struct { | |
1128 u_char size[4]; | |
1129 u_char name[4]; | |
1130 u_char version[1]; | |
1131 u_char flags[3]; | |
1132 u_char creation_time[4]; | |
1133 u_char modification_time[4]; | |
1134 u_char timescale[4]; | |
1135 u_char duration[4]; | |
1136 u_char rate[4]; | |
1137 u_char volume[2]; | |
1138 u_char reserved[10]; | |
1139 u_char matrix[36]; | |
1140 u_char preview_time[4]; | |
1141 u_char preview_duration[4]; | |
1142 u_char poster_time[4]; | |
1143 u_char selection_time[4]; | |
1144 u_char selection_duration[4]; | |
1145 u_char current_time[4]; | |
1146 u_char next_track_id[4]; | |
1147 } ngx_mp4_mvhd_atom_t; | |
1148 | |
1149 typedef struct { | |
1150 u_char size[4]; | |
1151 u_char name[4]; | |
1152 u_char version[1]; | |
1153 u_char flags[3]; | |
1154 u_char creation_time[8]; | |
1155 u_char modification_time[8]; | |
1156 u_char timescale[4]; | |
1157 u_char duration[8]; | |
1158 u_char rate[4]; | |
1159 u_char volume[2]; | |
1160 u_char reserved[10]; | |
1161 u_char matrix[36]; | |
1162 u_char preview_time[4]; | |
1163 u_char preview_duration[4]; | |
1164 u_char poster_time[4]; | |
1165 u_char selection_time[4]; | |
1166 u_char selection_duration[4]; | |
1167 u_char current_time[4]; | |
1168 u_char next_track_id[4]; | |
1169 } ngx_mp4_mvhd64_atom_t; | |
1170 | |
1171 | |
1172 static ngx_int_t | |
1173 ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1174 { | |
1175 u_char *atom_header; | |
1176 size_t atom_size; | |
1177 uint32_t timescale; | |
1178 uint64_t duration; | |
1179 ngx_buf_t *atom; | |
1180 ngx_mp4_mvhd_atom_t *mvhd_atom; | |
1181 ngx_mp4_mvhd64_atom_t *mvhd64_atom; | |
1182 | |
1183 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 mvhd atom"); | |
1184 | |
1185 atom_header = ngx_mp4_atom_header(mp4); | |
1186 mvhd_atom = (ngx_mp4_mvhd_atom_t *) atom_header; | |
1187 mvhd64_atom = (ngx_mp4_mvhd64_atom_t *) atom_header; | |
1188 ngx_mp4_set_atom_name(atom_header, 'm', 'v', 'h', 'd'); | |
1189 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1190 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
|
1191 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1192 "\"%s\" mp4 mvhd atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1193 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1194 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1195 |
4085 | 1196 if (mvhd_atom->version[0] == 0) { |
1197 /* version 0: 32-bit duration */ | |
1198 timescale = ngx_mp4_get_32value(mvhd_atom->timescale); | |
1199 duration = ngx_mp4_get_32value(mvhd_atom->duration); | |
1200 | |
1201 } else { | |
1202 /* version 1: 64-bit duration */ | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1203 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1204 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
|
1205 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1206 "\"%s\" mp4 mvhd atom too small", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1207 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1208 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1209 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1210 |
4085 | 1211 timescale = ngx_mp4_get_32value(mvhd64_atom->timescale); |
1212 duration = ngx_mp4_get_64value(mvhd64_atom->duration); | |
1213 } | |
1214 | |
1215 mp4->timescale = timescale; | |
1216 | |
1217 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1218 "mvhd timescale:%uD, duration:%uL, time:%.3fs", | |
1219 timescale, duration, (double) duration / timescale); | |
1220 | |
1221 duration -= (uint64_t) mp4->start * timescale / 1000; | |
1222 | |
1223 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1224 "mvhd new duration:%uL, time:%.3fs", | |
1225 duration, (double) duration / timescale); | |
1226 | |
1227 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1228 ngx_mp4_set_32value(mvhd_atom->size, atom_size); | |
1229 | |
1230 if (mvhd_atom->version[0] == 0) { | |
1231 ngx_mp4_set_32value(mvhd_atom->duration, duration); | |
1232 | |
1233 } else { | |
1234 ngx_mp4_set_64value(mvhd64_atom->duration, duration); | |
1235 } | |
1236 | |
1237 atom = &mp4->mvhd_atom_buf; | |
1238 atom->temporary = 1; | |
1239 atom->pos = atom_header; | |
1240 atom->last = atom_header + atom_size; | |
1241 | |
1242 mp4->mvhd_atom.buf = atom; | |
1243 | |
1244 ngx_mp4_atom_next(mp4, atom_data_size); | |
1245 | |
1246 return NGX_OK; | |
1247 } | |
1248 | |
1249 | |
1250 static ngx_int_t | |
1251 ngx_http_mp4_read_trak_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1252 { | |
4099
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1253 u_char *atom_header, *atom_end; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1254 off_t atom_file_end; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1255 ngx_int_t rc; |
4085 | 1256 ngx_buf_t *atom; |
1257 ngx_http_mp4_trak_t *trak; | |
1258 | |
1259 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 trak atom"); | |
1260 | |
1261 trak = ngx_array_push(&mp4->trak); | |
1262 if (trak == NULL) { | |
1263 return NGX_ERROR; | |
1264 } | |
1265 | |
1266 ngx_memzero(trak, sizeof(ngx_http_mp4_trak_t)); | |
1267 | |
1268 atom_header = ngx_mp4_atom_header(mp4); | |
1269 ngx_mp4_set_atom_name(atom_header, 't', 'r', 'a', 'k'); | |
1270 | |
1271 atom = &trak->trak_atom_buf; | |
1272 atom->temporary = 1; | |
1273 atom->pos = atom_header; | |
1274 atom->last = atom_header + sizeof(ngx_mp4_atom_header_t); | |
1275 | |
1276 trak->out[NGX_HTTP_MP4_TRAK_ATOM].buf = atom; | |
1277 | |
4099
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1278 atom_end = mp4->buffer_pos + atom_data_size; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1279 atom_file_end = mp4->offset + atom_data_size; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1280 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1281 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
|
1282 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1283 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
|
1284 "mp4 trak atom: %i", rc); |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1285 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1286 if (rc == NGX_DECLINED) { |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1287 /* skip this trak */ |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1288 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
|
1289 mp4->trak.nelts--; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1290 mp4->buffer_pos = atom_end; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1291 mp4->offset = atom_file_end; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1292 return NGX_OK; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1293 } |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1294 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1295 return rc; |
4085 | 1296 } |
1297 | |
1298 | |
1299 static void | |
1300 ngx_http_mp4_update_trak_atom(ngx_http_mp4_file_t *mp4, | |
1301 ngx_http_mp4_trak_t *trak) | |
1302 { | |
1303 ngx_buf_t *atom; | |
1304 | |
1305 trak->size += sizeof(ngx_mp4_atom_header_t); | |
1306 atom = &trak->trak_atom_buf; | |
1307 ngx_mp4_set_32value(atom->pos, trak->size); | |
1308 } | |
1309 | |
1310 | |
1311 static ngx_int_t | |
1312 ngx_http_mp4_read_cmov_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1313 { | |
1314 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
1315 "\"%s\" mp4 compressed moov atom (cmov) is not supported", | |
1316 mp4->file.name.data); | |
1317 | |
1318 return NGX_ERROR; | |
1319 } | |
1320 | |
1321 | |
1322 typedef struct { | |
1323 u_char size[4]; | |
1324 u_char name[4]; | |
1325 u_char version[1]; | |
1326 u_char flags[3]; | |
1327 u_char creation_time[4]; | |
1328 u_char modification_time[4]; | |
1329 u_char track_id[4]; | |
1330 u_char reserved1[4]; | |
1331 u_char duration[4]; | |
1332 u_char reserved2[8]; | |
1333 u_char layer[2]; | |
1334 u_char group[2]; | |
1335 u_char volume[2]; | |
1336 u_char reverved3[2]; | |
1337 u_char matrix[36]; | |
1338 u_char width[4]; | |
1339 u_char heigth[4]; | |
1340 } ngx_mp4_tkhd_atom_t; | |
1341 | |
1342 typedef struct { | |
1343 u_char size[4]; | |
1344 u_char name[4]; | |
1345 u_char version[1]; | |
1346 u_char flags[3]; | |
1347 u_char creation_time[8]; | |
1348 u_char modification_time[8]; | |
1349 u_char track_id[4]; | |
1350 u_char reserved1[4]; | |
1351 u_char duration[8]; | |
1352 u_char reserved2[8]; | |
1353 u_char layer[2]; | |
1354 u_char group[2]; | |
1355 u_char volume[2]; | |
1356 u_char reverved3[2]; | |
1357 u_char matrix[36]; | |
1358 u_char width[4]; | |
1359 u_char heigth[4]; | |
1360 } ngx_mp4_tkhd64_atom_t; | |
1361 | |
1362 | |
1363 static ngx_int_t | |
1364 ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1365 { | |
1366 u_char *atom_header; | |
1367 size_t atom_size; | |
1368 uint64_t duration; | |
1369 ngx_buf_t *atom; | |
1370 ngx_http_mp4_trak_t *trak; | |
1371 ngx_mp4_tkhd_atom_t *tkhd_atom; | |
1372 ngx_mp4_tkhd64_atom_t *tkhd64_atom; | |
1373 | |
1374 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 tkhd atom"); | |
1375 | |
1376 atom_header = ngx_mp4_atom_header(mp4); | |
1377 tkhd_atom = (ngx_mp4_tkhd_atom_t *) atom_header; | |
1378 tkhd64_atom = (ngx_mp4_tkhd64_atom_t *) atom_header; | |
1379 ngx_mp4_set_atom_name(tkhd_atom, 't', 'k', 'h', 'd'); | |
1380 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1381 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
|
1382 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1383 "\"%s\" mp4 tkhd atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1384 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1385 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1386 |
4085 | 1387 if (tkhd_atom->version[0] == 0) { |
1388 /* version 0: 32-bit duration */ | |
1389 duration = ngx_mp4_get_32value(tkhd_atom->duration); | |
1390 | |
1391 } else { | |
1392 /* version 1: 64-bit duration */ | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1393 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1394 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
|
1395 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1396 "\"%s\" mp4 tkhd atom too small", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1397 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1398 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1399 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1400 |
4085 | 1401 duration = ngx_mp4_get_64value(tkhd64_atom->duration); |
1402 } | |
1403 | |
1404 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1405 "tkhd duration:%uL, time:%.3fs", | |
1406 duration, (double) duration / mp4->timescale); | |
1407 | |
1408 duration -= (uint64_t) mp4->start * mp4->timescale / 1000; | |
1409 | |
1410 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1411 "tkhd new duration:%uL, time:%.3fs", | |
1412 duration, (double) duration / mp4->timescale); | |
1413 | |
1414 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1415 | |
1416 trak = ngx_mp4_last_trak(mp4); | |
1417 trak->tkhd_size = atom_size; | |
1418 | |
1419 ngx_mp4_set_32value(tkhd_atom->size, atom_size); | |
1420 | |
1421 if (tkhd_atom->version[0] == 0) { | |
1422 ngx_mp4_set_32value(tkhd_atom->duration, duration); | |
1423 | |
1424 } else { | |
1425 ngx_mp4_set_64value(tkhd64_atom->duration, duration); | |
1426 } | |
1427 | |
1428 atom = &trak->tkhd_atom_buf; | |
1429 atom->temporary = 1; | |
1430 atom->pos = atom_header; | |
1431 atom->last = atom_header + atom_size; | |
1432 | |
1433 trak->out[NGX_HTTP_MP4_TKHD_ATOM].buf = atom; | |
1434 | |
1435 ngx_mp4_atom_next(mp4, atom_data_size); | |
1436 | |
1437 return NGX_OK; | |
1438 } | |
1439 | |
1440 | |
1441 static ngx_int_t | |
1442 ngx_http_mp4_read_mdia_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1443 { | |
1444 u_char *atom_header; | |
1445 ngx_buf_t *atom; | |
1446 ngx_http_mp4_trak_t *trak; | |
1447 | |
1448 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "process mdia atom"); | |
1449 | |
1450 atom_header = ngx_mp4_atom_header(mp4); | |
1451 ngx_mp4_set_atom_name(atom_header, 'm', 'd', 'i', 'a'); | |
1452 | |
1453 trak = ngx_mp4_last_trak(mp4); | |
1454 | |
1455 atom = &trak->mdia_atom_buf; | |
1456 atom->temporary = 1; | |
1457 atom->pos = atom_header; | |
1458 atom->last = atom_header + sizeof(ngx_mp4_atom_header_t); | |
1459 | |
1460 trak->out[NGX_HTTP_MP4_MDIA_ATOM].buf = atom; | |
1461 | |
1462 return ngx_http_mp4_read_atom(mp4, ngx_http_mp4_mdia_atoms, atom_data_size); | |
1463 } | |
1464 | |
1465 | |
1466 static void | |
1467 ngx_http_mp4_update_mdia_atom(ngx_http_mp4_file_t *mp4, | |
1468 ngx_http_mp4_trak_t *trak) | |
1469 { | |
1470 ngx_buf_t *atom; | |
1471 | |
1472 trak->size += sizeof(ngx_mp4_atom_header_t); | |
1473 atom = &trak->mdia_atom_buf; | |
1474 ngx_mp4_set_32value(atom->pos, trak->size); | |
1475 } | |
1476 | |
1477 | |
1478 typedef struct { | |
1479 u_char size[4]; | |
1480 u_char name[4]; | |
1481 u_char version[1]; | |
1482 u_char flags[3]; | |
1483 u_char creation_time[4]; | |
1484 u_char modification_time[4]; | |
1485 u_char timescale[4]; | |
1486 u_char duration[4]; | |
1487 u_char language[2]; | |
1488 u_char quality[2]; | |
1489 } ngx_mp4_mdhd_atom_t; | |
1490 | |
1491 typedef struct { | |
1492 u_char size[4]; | |
1493 u_char name[4]; | |
1494 u_char version[1]; | |
1495 u_char flags[3]; | |
1496 u_char creation_time[8]; | |
1497 u_char modification_time[8]; | |
1498 u_char timescale[4]; | |
1499 u_char duration[8]; | |
1500 u_char language[2]; | |
1501 u_char quality[2]; | |
1502 } ngx_mp4_mdhd64_atom_t; | |
1503 | |
1504 | |
1505 static ngx_int_t | |
1506 ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1507 { | |
1508 u_char *atom_header; | |
1509 size_t atom_size; | |
1510 uint32_t timescale; | |
1511 uint64_t duration; | |
1512 ngx_buf_t *atom; | |
1513 ngx_http_mp4_trak_t *trak; | |
1514 ngx_mp4_mdhd_atom_t *mdhd_atom; | |
1515 ngx_mp4_mdhd64_atom_t *mdhd64_atom; | |
1516 | |
1517 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 mdhd atom"); | |
1518 | |
1519 atom_header = ngx_mp4_atom_header(mp4); | |
1520 mdhd_atom = (ngx_mp4_mdhd_atom_t *) atom_header; | |
1521 mdhd64_atom = (ngx_mp4_mdhd64_atom_t *) atom_header; | |
1522 ngx_mp4_set_atom_name(mdhd_atom, 'm', 'd', 'h', 'd'); | |
1523 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1524 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
|
1525 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1526 "\"%s\" mp4 mdhd atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1527 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1528 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1529 |
4085 | 1530 if (mdhd_atom->version[0] == 0) { |
1531 /* version 0: everything is 32-bit */ | |
1532 timescale = ngx_mp4_get_32value(mdhd_atom->timescale); | |
1533 duration = ngx_mp4_get_32value(mdhd_atom->duration); | |
1534 | |
1535 } else { | |
1536 /* version 1: 64-bit duration and 32-bit timescale */ | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1537 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1538 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
|
1539 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1540 "\"%s\" mp4 mdhd atom too small", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1541 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1542 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1543 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1544 |
4085 | 1545 timescale = ngx_mp4_get_32value(mdhd64_atom->timescale); |
1546 duration = ngx_mp4_get_64value(mdhd64_atom->duration); | |
1547 } | |
1548 | |
1549 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1550 "mdhd timescale:%uD, duration:%uL, time:%.3fs", | |
1551 timescale, duration, (double) duration / timescale); | |
1552 | |
1553 duration -= (uint64_t) mp4->start * timescale / 1000; | |
1554 | |
1555 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1556 "mdhd new duration:%uL, time:%.3fs", | |
1557 duration, (double) duration / timescale); | |
1558 | |
1559 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1560 | |
1561 trak = ngx_mp4_last_trak(mp4); | |
1562 trak->mdhd_size = atom_size; | |
1563 trak->timescale = timescale; | |
1564 | |
1565 ngx_mp4_set_32value(mdhd_atom->size, atom_size); | |
1566 | |
1567 if (mdhd_atom->version[0] == 0) { | |
1568 ngx_mp4_set_32value(mdhd_atom->duration, duration); | |
1569 | |
1570 } else { | |
1571 ngx_mp4_set_64value(mdhd64_atom->duration, duration); | |
1572 } | |
1573 | |
1574 atom = &trak->mdhd_atom_buf; | |
1575 atom->temporary = 1; | |
1576 atom->pos = atom_header; | |
1577 atom->last = atom_header + atom_size; | |
1578 | |
1579 trak->out[NGX_HTTP_MP4_MDHD_ATOM].buf = atom; | |
1580 | |
1581 ngx_mp4_atom_next(mp4, atom_data_size); | |
1582 | |
1583 return NGX_OK; | |
1584 } | |
1585 | |
1586 | |
1587 static ngx_int_t | |
1588 ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1589 { | |
1590 u_char *atom_header; | |
1591 size_t atom_size; | |
1592 ngx_buf_t *atom; | |
1593 ngx_http_mp4_trak_t *trak; | |
1594 | |
1595 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 hdlr atom"); | |
1596 | |
1597 atom_header = ngx_mp4_atom_header(mp4); | |
1598 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1599 ngx_mp4_set_32value(atom_header, atom_size); | |
1600 ngx_mp4_set_atom_name(atom_header, 'h', 'd', 'l', 'r'); | |
1601 | |
1602 trak = ngx_mp4_last_trak(mp4); | |
1603 | |
1604 atom = &trak->hdlr_atom_buf; | |
1605 atom->temporary = 1; | |
1606 atom->pos = atom_header; | |
1607 atom->last = atom_header + atom_size; | |
1608 | |
1609 trak->hdlr_size = atom_size; | |
1610 trak->out[NGX_HTTP_MP4_HDLR_ATOM].buf = atom; | |
1611 | |
1612 ngx_mp4_atom_next(mp4, atom_data_size); | |
1613 | |
1614 return NGX_OK; | |
1615 } | |
1616 | |
1617 | |
1618 static ngx_int_t | |
1619 ngx_http_mp4_read_minf_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1620 { | |
1621 u_char *atom_header; | |
1622 ngx_buf_t *atom; | |
1623 ngx_http_mp4_trak_t *trak; | |
1624 | |
1625 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "process minf atom"); | |
1626 | |
1627 atom_header = ngx_mp4_atom_header(mp4); | |
1628 ngx_mp4_set_atom_name(atom_header, 'm', 'i', 'n', 'f'); | |
1629 | |
1630 trak = ngx_mp4_last_trak(mp4); | |
1631 | |
1632 atom = &trak->minf_atom_buf; | |
1633 atom->temporary = 1; | |
1634 atom->pos = atom_header; | |
1635 atom->last = atom_header + sizeof(ngx_mp4_atom_header_t); | |
1636 | |
1637 trak->out[NGX_HTTP_MP4_MINF_ATOM].buf = atom; | |
1638 | |
1639 return ngx_http_mp4_read_atom(mp4, ngx_http_mp4_minf_atoms, atom_data_size); | |
1640 } | |
1641 | |
1642 | |
1643 static void | |
1644 ngx_http_mp4_update_minf_atom(ngx_http_mp4_file_t *mp4, | |
1645 ngx_http_mp4_trak_t *trak) | |
1646 { | |
1647 ngx_buf_t *atom; | |
1648 | |
1649 trak->size += sizeof(ngx_mp4_atom_header_t) | |
1650 + trak->vmhd_size | |
1651 + trak->smhd_size | |
1652 + trak->dinf_size; | |
1653 atom = &trak->minf_atom_buf; | |
1654 ngx_mp4_set_32value(atom->pos, trak->size); | |
1655 } | |
1656 | |
1657 | |
1658 static ngx_int_t | |
1659 ngx_http_mp4_read_vmhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1660 { | |
1661 u_char *atom_header; | |
1662 size_t atom_size; | |
1663 ngx_buf_t *atom; | |
1664 ngx_http_mp4_trak_t *trak; | |
1665 | |
1666 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 vmhd atom"); | |
1667 | |
1668 atom_header = ngx_mp4_atom_header(mp4); | |
1669 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1670 ngx_mp4_set_32value(atom_header, atom_size); | |
1671 ngx_mp4_set_atom_name(atom_header, 'v', 'm', 'h', 'd'); | |
1672 | |
1673 trak = ngx_mp4_last_trak(mp4); | |
1674 | |
1675 atom = &trak->vmhd_atom_buf; | |
1676 atom->temporary = 1; | |
1677 atom->pos = atom_header; | |
1678 atom->last = atom_header + atom_size; | |
1679 | |
1680 trak->vmhd_size += atom_size; | |
1681 trak->out[NGX_HTTP_MP4_VMHD_ATOM].buf = atom; | |
1682 | |
1683 ngx_mp4_atom_next(mp4, atom_data_size); | |
1684 | |
1685 return NGX_OK; | |
1686 } | |
1687 | |
1688 | |
1689 static ngx_int_t | |
1690 ngx_http_mp4_read_smhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1691 { | |
1692 u_char *atom_header; | |
1693 size_t atom_size; | |
1694 ngx_buf_t *atom; | |
1695 ngx_http_mp4_trak_t *trak; | |
1696 | |
1697 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 smhd atom"); | |
1698 | |
1699 atom_header = ngx_mp4_atom_header(mp4); | |
1700 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1701 ngx_mp4_set_32value(atom_header, atom_size); | |
1702 ngx_mp4_set_atom_name(atom_header, 's', 'm', 'h', 'd'); | |
1703 | |
1704 trak = ngx_mp4_last_trak(mp4); | |
1705 | |
1706 atom = &trak->smhd_atom_buf; | |
1707 atom->temporary = 1; | |
1708 atom->pos = atom_header; | |
1709 atom->last = atom_header + atom_size; | |
1710 | |
1711 trak->vmhd_size += atom_size; | |
1712 trak->out[NGX_HTTP_MP4_SMHD_ATOM].buf = atom; | |
1713 | |
1714 ngx_mp4_atom_next(mp4, atom_data_size); | |
1715 | |
1716 return NGX_OK; | |
1717 } | |
1718 | |
1719 | |
1720 static ngx_int_t | |
1721 ngx_http_mp4_read_dinf_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1722 { | |
1723 u_char *atom_header; | |
1724 size_t atom_size; | |
1725 ngx_buf_t *atom; | |
1726 ngx_http_mp4_trak_t *trak; | |
1727 | |
1728 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 dinf atom"); | |
1729 | |
1730 atom_header = ngx_mp4_atom_header(mp4); | |
1731 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1732 ngx_mp4_set_32value(atom_header, atom_size); | |
1733 ngx_mp4_set_atom_name(atom_header, 'd', 'i', 'n', 'f'); | |
1734 | |
1735 trak = ngx_mp4_last_trak(mp4); | |
1736 | |
1737 atom = &trak->dinf_atom_buf; | |
1738 atom->temporary = 1; | |
1739 atom->pos = atom_header; | |
1740 atom->last = atom_header + atom_size; | |
1741 | |
1742 trak->dinf_size += atom_size; | |
1743 trak->out[NGX_HTTP_MP4_DINF_ATOM].buf = atom; | |
1744 | |
1745 ngx_mp4_atom_next(mp4, atom_data_size); | |
1746 | |
1747 return NGX_OK; | |
1748 } | |
1749 | |
1750 | |
1751 static ngx_int_t | |
1752 ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1753 { | |
1754 u_char *atom_header; | |
1755 ngx_buf_t *atom; | |
1756 ngx_http_mp4_trak_t *trak; | |
1757 | |
1758 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "process stbl atom"); | |
1759 | |
1760 atom_header = ngx_mp4_atom_header(mp4); | |
1761 ngx_mp4_set_atom_name(atom_header, 's', 't', 'b', 'l'); | |
1762 | |
1763 trak = ngx_mp4_last_trak(mp4); | |
1764 | |
1765 atom = &trak->stbl_atom_buf; | |
1766 atom->temporary = 1; | |
1767 atom->pos = atom_header; | |
1768 atom->last = atom_header + sizeof(ngx_mp4_atom_header_t); | |
1769 | |
1770 trak->out[NGX_HTTP_MP4_STBL_ATOM].buf = atom; | |
1771 | |
1772 return ngx_http_mp4_read_atom(mp4, ngx_http_mp4_stbl_atoms, atom_data_size); | |
1773 } | |
1774 | |
1775 | |
1776 static void | |
1777 ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, | |
1778 ngx_http_mp4_trak_t *trak) | |
1779 { | |
1780 ngx_buf_t *atom; | |
1781 | |
1782 trak->size += sizeof(ngx_mp4_atom_header_t); | |
1783 atom = &trak->stbl_atom_buf; | |
1784 ngx_mp4_set_32value(atom->pos, trak->size); | |
1785 } | |
1786 | |
1787 | |
1788 typedef struct { | |
1789 u_char size[4]; | |
1790 u_char name[4]; | |
1791 u_char version[1]; | |
1792 u_char flags[3]; | |
1793 u_char entries[4]; | |
4099
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1794 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1795 u_char media_size[4]; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1796 u_char media_name[4]; |
4085 | 1797 } ngx_mp4_stsd_atom_t; |
1798 | |
1799 | |
1800 static ngx_int_t | |
1801 ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1802 { | |
1803 u_char *atom_header, *atom_table; | |
1804 size_t atom_size; | |
1805 ngx_buf_t *atom; | |
1806 ngx_mp4_stsd_atom_t *stsd_atom; | |
1807 ngx_http_mp4_trak_t *trak; | |
1808 | |
1809 /* sample description atom */ | |
1810 | |
1811 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stsd atom"); | |
1812 | |
1813 atom_header = ngx_mp4_atom_header(mp4); | |
1814 stsd_atom = (ngx_mp4_stsd_atom_t *) atom_header; | |
1815 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1816 atom_table = atom_header + atom_size; | |
1817 ngx_mp4_set_32value(stsd_atom->size, atom_size); | |
1818 ngx_mp4_set_atom_name(stsd_atom, 's', 't', 's', 'd'); | |
1819 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1820 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
|
1821 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
|
1822 "\"%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
|
1823 return NGX_ERROR; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1824 } |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1825 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1826 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
|
1827 "stsd entries:%uD, media:%*s", |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1828 ngx_mp4_get_32value(stsd_atom->entries), |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1829 4, stsd_atom->media_name); |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1830 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1831 /* supported media format: "avc1" (H.264) and "mp4a" (MPEG-4/AAC) */ |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1832 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1833 if (ngx_strncmp(stsd_atom->media_name, "avc1", 4) != 0 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1834 && ngx_strncmp(stsd_atom->media_name, "mp4a", 4) != 0) |
4085 | 1835 { |
4099
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1836 return NGX_DECLINED; |
4085 | 1837 } |
1838 | |
1839 trak = ngx_mp4_last_trak(mp4); | |
1840 | |
1841 atom = &trak->stsd_atom_buf; | |
1842 atom->temporary = 1; | |
1843 atom->pos = atom_header; | |
1844 atom->last = atom_table; | |
1845 | |
1846 trak->out[NGX_HTTP_MP4_STSD_ATOM].buf = atom; | |
1847 trak->size += atom_size; | |
1848 | |
1849 ngx_mp4_atom_next(mp4, atom_data_size); | |
1850 | |
1851 return NGX_OK; | |
1852 } | |
1853 | |
1854 | |
1855 typedef struct { | |
1856 u_char size[4]; | |
1857 u_char name[4]; | |
1858 u_char version[1]; | |
1859 u_char flags[3]; | |
1860 u_char entries[4]; | |
1861 } ngx_mp4_stts_atom_t; | |
1862 | |
1863 typedef struct { | |
1864 u_char count[4]; | |
1865 u_char duration[4]; | |
1866 } ngx_mp4_stts_entry_t; | |
1867 | |
1868 | |
1869 static ngx_int_t | |
1870 ngx_http_mp4_read_stts_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1871 { | |
1872 u_char *atom_header, *atom_table, *atom_end; | |
1873 uint32_t entries; | |
1874 ngx_buf_t *atom, *data; | |
1875 ngx_mp4_stts_atom_t *stts_atom; | |
1876 ngx_http_mp4_trak_t *trak; | |
1877 | |
1878 /* time-to-sample atom */ | |
1879 | |
1880 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stts atom"); | |
1881 | |
1882 atom_header = ngx_mp4_atom_header(mp4); | |
1883 stts_atom = (ngx_mp4_stts_atom_t *) atom_header; | |
1884 ngx_mp4_set_atom_name(stts_atom, 's', 't', 't', 's'); | |
1885 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1886 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
|
1887 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1888 "\"%s\" mp4 stts atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1889 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1890 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1891 |
4085 | 1892 entries = ngx_mp4_get_32value(stts_atom->entries); |
1893 | |
1894 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 1895 "mp4 time-to-sample entries:%uD", entries); |
4085 | 1896 |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1897 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
|
1898 + entries * sizeof(ngx_mp4_stts_entry_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1899 { |
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 atom_table = atom_header + sizeof(ngx_mp4_stts_atom_t); |
1906 atom_end = atom_table + entries * sizeof(ngx_mp4_stts_entry_t); | |
1907 | |
1908 trak = ngx_mp4_last_trak(mp4); | |
1909 trak->time_to_sample_entries = entries; | |
1910 | |
1911 atom = &trak->stts_atom_buf; | |
1912 atom->temporary = 1; | |
1913 atom->pos = atom_header; | |
1914 atom->last = atom_table; | |
1915 | |
1916 data = &trak->stts_data_buf; | |
1917 data->temporary = 1; | |
1918 data->pos = atom_table; | |
1919 data->last = atom_end; | |
1920 | |
1921 trak->out[NGX_HTTP_MP4_STTS_ATOM].buf = atom; | |
1922 trak->out[NGX_HTTP_MP4_STTS_DATA].buf = data; | |
1923 | |
1924 ngx_mp4_atom_next(mp4, atom_data_size); | |
1925 | |
1926 return NGX_OK; | |
1927 } | |
1928 | |
1929 | |
1930 static ngx_int_t | |
1931 ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, | |
1932 ngx_http_mp4_trak_t *trak) | |
1933 { | |
1934 size_t atom_size; | |
1935 uint32_t entries, count, duration; | |
1936 uint64_t start_time; | |
1937 ngx_buf_t *atom, *data; | |
1938 ngx_uint_t start_sample; | |
1939 ngx_mp4_stts_atom_t *stts_atom; | |
1940 ngx_mp4_stts_entry_t *entry, *end; | |
1941 | |
1942 /* | |
1943 * mdia.minf.stbl.stts updating requires trak->timescale | |
1944 * from mdia.mdhd atom which may reside after mdia.minf | |
1945 */ | |
1946 | |
1947 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1948 "mp4 stts atom update"); | |
1949 | |
1950 data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf; | |
1951 | |
1952 if (data == NULL) { | |
1953 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
1954 "no mp4 stts atoms were found in \"%s\"", | |
1955 mp4->file.name.data); | |
1956 return NGX_ERROR; | |
1957 } | |
1958 | |
1959 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
|
1960 start_time = (uint64_t) mp4->start * trak->timescale / 1000; |
4085 | 1961 |
1962 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 1963 "time-to-sample start_time:%uL", start_time); |
4085 | 1964 |
1965 start_sample = 0; | |
1966 entry = (ngx_mp4_stts_entry_t *) data->pos; | |
1967 end = (ngx_mp4_stts_entry_t *) data->last; | |
1968 | |
1969 while (entry < end) { | |
1970 count = ngx_mp4_get_32value(entry->count); | |
1971 duration = ngx_mp4_get_32value(entry->duration); | |
1972 | |
1973 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1974 "count:%uD, duration:%uD", count, duration); | |
1975 | |
4306 | 1976 if (start_time < (uint64_t) count * duration) { |
4085 | 1977 start_sample += (ngx_uint_t) (start_time / duration); |
4578 | 1978 count -= (uint32_t) (start_time / duration); |
4085 | 1979 ngx_mp4_set_32value(entry->count, count); |
1980 goto found; | |
1981 } | |
1982 | |
1983 start_sample += count; | |
1984 start_time -= count * duration; | |
1985 entries--; | |
1986 entry++; | |
1987 } | |
1988 | |
1989 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
4094 | 1990 "start time is out mp4 stts samples in \"%s\"", |
4085 | 1991 mp4->file.name.data); |
1992 | |
1993 return NGX_ERROR; | |
1994 | |
1995 found: | |
1996 | |
1997 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1998 "start_sample:%ui, new count:%uD", start_sample, count); | |
1999 | |
2000 trak->start_sample = start_sample; | |
2001 | |
2002 data->pos = (u_char *) entry; | |
2003 atom_size = sizeof(ngx_mp4_stts_atom_t) + (data->last - data->pos); | |
2004 trak->size += atom_size; | |
2005 | |
2006 atom = trak->out[NGX_HTTP_MP4_STTS_ATOM].buf; | |
2007 stts_atom = (ngx_mp4_stts_atom_t *) atom->pos; | |
2008 ngx_mp4_set_32value(stts_atom->size, atom_size); | |
2009 ngx_mp4_set_32value(stts_atom->entries, entries); | |
2010 | |
2011 return NGX_OK; | |
2012 } | |
2013 | |
2014 | |
2015 typedef struct { | |
2016 u_char size[4]; | |
2017 u_char name[4]; | |
2018 u_char version[1]; | |
2019 u_char flags[3]; | |
2020 u_char entries[4]; | |
2021 } ngx_http_mp4_stss_atom_t; | |
2022 | |
2023 | |
2024 static ngx_int_t | |
2025 ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2026 { | |
2027 u_char *atom_header, *atom_table, *atom_end; | |
2028 uint32_t entries; | |
2029 ngx_buf_t *atom, *data; | |
2030 ngx_http_mp4_trak_t *trak; | |
2031 ngx_http_mp4_stss_atom_t *stss_atom; | |
2032 | |
2033 /* sync samples atom */ | |
2034 | |
2035 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stss atom"); | |
2036 | |
2037 atom_header = ngx_mp4_atom_header(mp4); | |
2038 stss_atom = (ngx_http_mp4_stss_atom_t *) atom_header; | |
2039 ngx_mp4_set_atom_name(stss_atom, 's', 't', 's', 's'); | |
2040 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2041 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
|
2042 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2043 "\"%s\" mp4 stss atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2044 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2045 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2046 |
4085 | 2047 entries = ngx_mp4_get_32value(stss_atom->entries); |
2048 | |
2049 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 2050 "sync sample entries:%uD", entries); |
4085 | 2051 |
2052 trak = ngx_mp4_last_trak(mp4); | |
2053 trak->sync_samples_entries = entries; | |
2054 | |
2055 atom_table = atom_header + sizeof(ngx_http_mp4_stss_atom_t); | |
2056 | |
2057 atom = &trak->stss_atom_buf; | |
2058 atom->temporary = 1; | |
2059 atom->pos = atom_header; | |
2060 atom->last = atom_table; | |
2061 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2062 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
|
2063 + entries * sizeof(uint32_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2064 { |
4085 | 2065 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
|
2066 "\"%s\" mp4 stss atom too small", mp4->file.name.data); |
4085 | 2067 return NGX_ERROR; |
2068 } | |
2069 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2070 atom_end = atom_table + entries * sizeof(uint32_t); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2071 |
4085 | 2072 data = &trak->stss_data_buf; |
2073 data->temporary = 1; | |
2074 data->pos = atom_table; | |
2075 data->last = atom_end; | |
2076 | |
2077 trak->out[NGX_HTTP_MP4_STSS_ATOM].buf = atom; | |
2078 trak->out[NGX_HTTP_MP4_STSS_DATA].buf = data; | |
2079 | |
2080 ngx_mp4_atom_next(mp4, atom_data_size); | |
2081 | |
2082 return NGX_OK; | |
2083 } | |
2084 | |
2085 | |
2086 static ngx_int_t | |
2087 ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, | |
2088 ngx_http_mp4_trak_t *trak) | |
2089 { | |
2090 size_t atom_size; | |
2091 uint32_t entries, sample, start_sample, *entry, *end; | |
2092 ngx_buf_t *atom, *data; | |
2093 ngx_http_mp4_stss_atom_t *stss_atom; | |
2094 | |
2095 /* | |
2096 * mdia.minf.stbl.stss updating requires trak->start_sample | |
2097 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2098 * atom which may reside after mdia.minf | |
2099 */ | |
2100 | |
2101 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2102 "mp4 stss atom update"); | |
2103 | |
2104 data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf; | |
2105 | |
2106 if (data == NULL) { | |
2107 return NGX_OK; | |
2108 } | |
2109 | |
2110 /* sync samples starts from 1 */ | |
2111 start_sample = trak->start_sample + 1; | |
2112 entries = trak->sync_samples_entries; | |
2113 | |
2114 entry = (uint32_t *) data->pos; | |
2115 end = (uint32_t *) data->last; | |
2116 | |
2117 while (entry < end) { | |
2118 sample = ngx_mp4_get_32value(entry); | |
2119 | |
2120 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2121 "start:%uD, sync:%uD", start_sample, sample); | |
2122 | |
2123 if (sample >= start_sample) { | |
2124 goto found; | |
2125 } | |
2126 | |
2127 entries--; | |
2128 entry++; | |
2129 } | |
2130 | |
2131 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2132 "start sample is out of mp4 stss atom in \"%s\"", | |
2133 mp4->file.name.data); | |
2134 | |
2135 return NGX_ERROR; | |
2136 | |
2137 found: | |
2138 | |
2139 data->pos = (u_char *) entry; | |
2140 | |
2141 start_sample = trak->start_sample; | |
2142 | |
2143 while (entry < end) { | |
2144 sample = ngx_mp4_get_32value(entry); | |
2145 sample -= start_sample; | |
2146 ngx_mp4_set_32value(entry, sample); | |
2147 entry++; | |
2148 } | |
2149 | |
2150 atom_size = sizeof(ngx_http_mp4_stss_atom_t) + (data->last - data->pos); | |
2151 trak->size += atom_size; | |
2152 | |
2153 atom = trak->out[NGX_HTTP_MP4_STSS_ATOM].buf; | |
2154 stss_atom = (ngx_http_mp4_stss_atom_t *) atom->pos; | |
2155 | |
2156 ngx_mp4_set_32value(stss_atom->size, atom_size); | |
2157 ngx_mp4_set_32value(stss_atom->entries, entries); | |
2158 | |
2159 return NGX_OK; | |
2160 } | |
2161 | |
2162 | |
2163 typedef struct { | |
2164 u_char size[4]; | |
2165 u_char name[4]; | |
2166 u_char version[1]; | |
2167 u_char flags[3]; | |
2168 u_char entries[4]; | |
2169 } ngx_mp4_ctts_atom_t; | |
2170 | |
2171 typedef struct { | |
2172 u_char count[4]; | |
2173 u_char offset[4]; | |
2174 } ngx_mp4_ctts_entry_t; | |
2175 | |
2176 | |
2177 static ngx_int_t | |
2178 ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2179 { | |
2180 u_char *atom_header, *atom_table, *atom_end; | |
2181 uint32_t entries; | |
2182 ngx_buf_t *atom, *data; | |
2183 ngx_mp4_ctts_atom_t *ctts_atom; | |
2184 ngx_http_mp4_trak_t *trak; | |
2185 | |
2186 /* composition offsets atom */ | |
2187 | |
2188 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 ctts atom"); | |
2189 | |
2190 atom_header = ngx_mp4_atom_header(mp4); | |
2191 ctts_atom = (ngx_mp4_ctts_atom_t *) atom_header; | |
2192 ngx_mp4_set_atom_name(ctts_atom, 'c', 't', 't', 's'); | |
2193 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2194 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
|
2195 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2196 "\"%s\" mp4 ctts atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2197 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2198 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2199 |
4085 | 2200 entries = ngx_mp4_get_32value(ctts_atom->entries); |
2201 | |
2202 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 2203 "composition offset entries:%uD", entries); |
4085 | 2204 |
2205 trak = ngx_mp4_last_trak(mp4); | |
2206 trak->composition_offset_entries = entries; | |
2207 | |
2208 atom_table = atom_header + sizeof(ngx_mp4_ctts_atom_t); | |
2209 | |
2210 atom = &trak->ctts_atom_buf; | |
2211 atom->temporary = 1; | |
2212 atom->pos = atom_header; | |
2213 atom->last = atom_table; | |
2214 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2215 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
|
2216 + entries * sizeof(ngx_mp4_ctts_entry_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2217 { |
4085 | 2218 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
|
2219 "\"%s\" mp4 ctts atom too small", mp4->file.name.data); |
4085 | 2220 return NGX_ERROR; |
2221 } | |
2222 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2223 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
|
2224 |
4085 | 2225 data = &trak->ctts_data_buf; |
2226 data->temporary = 1; | |
2227 data->pos = atom_table; | |
2228 data->last = atom_end; | |
2229 | |
2230 trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = atom; | |
2231 trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = data; | |
2232 | |
2233 ngx_mp4_atom_next(mp4, atom_data_size); | |
2234 | |
2235 return NGX_OK; | |
2236 } | |
2237 | |
2238 | |
2239 static void | |
2240 ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4, | |
2241 ngx_http_mp4_trak_t *trak) | |
2242 { | |
2243 size_t atom_size; | |
2244 uint32_t entries, count, start_sample; | |
2245 ngx_buf_t *atom, *data; | |
2246 ngx_mp4_ctts_atom_t *ctts_atom; | |
2247 ngx_mp4_ctts_entry_t *entry, *end; | |
2248 | |
2249 /* | |
2250 * mdia.minf.stbl.ctts updating requires trak->start_sample | |
2251 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2252 * atom which may reside after mdia.minf | |
2253 */ | |
2254 | |
2255 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2256 "mp4 ctts atom update"); | |
2257 | |
2258 data = trak->out[NGX_HTTP_MP4_CTTS_DATA].buf; | |
2259 | |
2260 if (data == NULL) { | |
2261 return; | |
2262 } | |
2263 | |
2264 /* sync samples starts from 1 */ | |
2265 start_sample = trak->start_sample + 1; | |
2266 entries = trak->composition_offset_entries; | |
2267 entry = (ngx_mp4_ctts_entry_t *) data->pos; | |
2268 end = (ngx_mp4_ctts_entry_t *) data->last; | |
2269 | |
2270 while (entry < end) { | |
2271 count = ngx_mp4_get_32value(entry->count); | |
2272 | |
4088
8fe1da7b8386
bugfix of r4086: nginx could not be built without debug log.
Igor Sysoev <igor@sysoev.ru>
parents:
4087
diff
changeset
|
2273 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
4085 | 2274 "start:%uD, count:%uD, offset:%uD", |
2275 start_sample, count, ngx_mp4_get_32value(entry->offset)); | |
2276 | |
2277 if (start_sample <= count) { | |
2278 count -= (start_sample - 1); | |
2279 ngx_mp4_set_32value(entry->count, count); | |
2280 goto found; | |
2281 } | |
2282 | |
2283 start_sample -= count; | |
2284 entries--; | |
2285 entry++; | |
2286 } | |
2287 | |
2288 trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL; | |
2289 trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL; | |
2290 | |
2291 return; | |
2292 | |
2293 found: | |
2294 | |
2295 data->pos = (u_char *) entry; | |
2296 atom_size = sizeof(ngx_mp4_ctts_atom_t) + (data->last - data->pos); | |
2297 trak->size += atom_size; | |
2298 | |
2299 atom = trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf; | |
2300 ctts_atom = (ngx_mp4_ctts_atom_t *) atom->pos; | |
2301 | |
2302 ngx_mp4_set_32value(ctts_atom->size, atom_size); | |
2303 ngx_mp4_set_32value(ctts_atom->entries, entries); | |
2304 | |
2305 return; | |
2306 } | |
2307 | |
2308 | |
2309 typedef struct { | |
2310 u_char size[4]; | |
2311 u_char name[4]; | |
2312 u_char version[1]; | |
2313 u_char flags[3]; | |
2314 u_char entries[4]; | |
2315 } ngx_mp4_stsc_atom_t; | |
2316 | |
2317 | |
2318 static ngx_int_t | |
2319 ngx_http_mp4_read_stsc_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2320 { | |
2321 u_char *atom_header, *atom_table, *atom_end; | |
2322 uint32_t entries; | |
2323 ngx_buf_t *atom, *data; | |
2324 ngx_mp4_stsc_atom_t *stsc_atom; | |
2325 ngx_http_mp4_trak_t *trak; | |
2326 | |
2327 /* sample-to-chunk atom */ | |
2328 | |
2329 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stsc atom"); | |
2330 | |
2331 atom_header = ngx_mp4_atom_header(mp4); | |
2332 stsc_atom = (ngx_mp4_stsc_atom_t *) atom_header; | |
2333 ngx_mp4_set_atom_name(stsc_atom, 's', 't', 's', 'c'); | |
2334 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2335 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
|
2336 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2337 "\"%s\" mp4 stsc atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2338 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2339 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2340 |
4085 | 2341 entries = ngx_mp4_get_32value(stsc_atom->entries); |
2342 | |
2343 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 2344 "sample-to-chunk entries:%uD", entries); |
4085 | 2345 |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2346 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
|
2347 + entries * sizeof(ngx_mp4_stsc_entry_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2348 { |
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 atom_table = atom_header + sizeof(ngx_mp4_stsc_atom_t); |
2355 atom_end = atom_table + entries * sizeof(ngx_mp4_stsc_entry_t); | |
2356 | |
2357 trak = ngx_mp4_last_trak(mp4); | |
2358 trak->sample_to_chunk_entries = entries; | |
2359 | |
2360 atom = &trak->stsc_atom_buf; | |
2361 atom->temporary = 1; | |
2362 atom->pos = atom_header; | |
2363 atom->last = atom_table; | |
2364 | |
2365 data = &trak->stsc_data_buf; | |
2366 data->temporary = 1; | |
2367 data->pos = atom_table; | |
2368 data->last = atom_end; | |
2369 | |
2370 trak->out[NGX_HTTP_MP4_STSC_ATOM].buf = atom; | |
2371 trak->out[NGX_HTTP_MP4_STSC_DATA].buf = data; | |
2372 | |
2373 ngx_mp4_atom_next(mp4, atom_data_size); | |
2374 | |
2375 return NGX_OK; | |
2376 } | |
2377 | |
2378 | |
2379 static ngx_int_t | |
2380 ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4, | |
2381 ngx_http_mp4_trak_t *trak) | |
2382 { | |
2383 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
|
2384 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
|
2385 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
|
2386 ngx_buf_t *atom, *data, *buf; |
4085 | 2387 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
|
2388 ngx_mp4_stsc_entry_t *entry, *first, *end; |
4085 | 2389 |
2390 /* | |
2391 * mdia.minf.stbl.stsc updating requires trak->start_sample | |
2392 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2393 * atom which may reside after mdia.minf | |
2394 */ | |
2395 | |
2396 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2397 "mp4 stsc atom update"); | |
2398 | |
2399 data = trak->out[NGX_HTTP_MP4_STSC_DATA].buf; | |
2400 | |
2401 if (data == NULL) { | |
2402 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2403 "no mp4 stsc atoms were found in \"%s\"", | |
2404 mp4->file.name.data); | |
2405 return NGX_ERROR; | |
2406 } | |
2407 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2408 if (trak->sample_to_chunk_entries == 0) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2409 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2410 "zero number of entries in stsc atom in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2411 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2412 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2413 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2414 |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2415 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
|
2416 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
|
2417 |
4085 | 2418 entry = (ngx_mp4_stsc_entry_t *) data->pos; |
2419 end = (ngx_mp4_stsc_entry_t *) data->last; | |
2420 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2421 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
|
2422 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
|
2423 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
|
2424 entry++; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2425 |
4085 | 2426 while (entry < end) { |
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 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
|
2429 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2430 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
|
2431 "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
|
2432 "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
|
2433 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
|
2434 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2435 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
|
2436 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2437 if (start_sample <= n) { |
4085 | 2438 goto found; |
2439 } | |
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 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
|
2442 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2443 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
|
2444 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
|
2445 id = ngx_mp4_get_32value(entry->id); |
4085 | 2446 entries--; |
2447 entry++; | |
2448 } | |
2449 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2450 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
|
2451 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2452 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
|
2453 "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
|
2454 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
|
2455 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2456 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
|
2457 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2458 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
|
2459 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
|
2460 "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
|
2461 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
|
2462 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
|
2463 } |
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 found: |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2466 |
4085 | 2467 entries++; |
2468 entry--; | |
2469 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2470 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
|
2471 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
|
2472 "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
|
2473 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
|
2474 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
|
2475 } |
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 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
|
2478 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2479 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
|
2480 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
|
2481 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2482 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
|
2483 "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
|
2484 trak->start_chunk, trak->chunk_samples); |
4085 | 2485 |
2486 data->pos = (u_char *) entry; | |
2487 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
|
2488 |
4382
b4d54fa76853
Fixed mp4 if first entry in stsc was skipped (ticket #72).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4306
diff
changeset
|
2489 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
|
2490 |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2491 if (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
|
2492 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2493 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
|
2494 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
|
2495 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
|
2496 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
|
2497 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2498 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
|
2499 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
|
2500 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
|
2501 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
|
2502 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2503 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
|
2504 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2505 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
|
2506 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2507 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
|
2508 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2509 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2510 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
|
2511 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
|
2512 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
|
2513 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
|
2514 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2515 |
4085 | 2516 trak->size += atom_size; |
2517 | |
2518 atom = trak->out[NGX_HTTP_MP4_STSC_ATOM].buf; | |
2519 stsc_atom = (ngx_mp4_stsc_atom_t *) atom->pos; | |
2520 | |
2521 ngx_mp4_set_32value(stsc_atom->size, atom_size); | |
2522 ngx_mp4_set_32value(stsc_atom->entries, entries); | |
2523 | |
2524 return NGX_OK; | |
2525 } | |
2526 | |
2527 | |
2528 typedef struct { | |
2529 u_char size[4]; | |
2530 u_char name[4]; | |
2531 u_char version[1]; | |
2532 u_char flags[3]; | |
2533 u_char uniform_size[4]; | |
2534 u_char entries[4]; | |
2535 } ngx_mp4_stsz_atom_t; | |
2536 | |
2537 | |
2538 static ngx_int_t | |
2539 ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2540 { | |
2541 u_char *atom_header, *atom_table, *atom_end; | |
2542 size_t atom_size; | |
2543 uint32_t entries, size; | |
2544 ngx_buf_t *atom, *data; | |
2545 ngx_mp4_stsz_atom_t *stsz_atom; | |
2546 ngx_http_mp4_trak_t *trak; | |
2547 | |
2548 /* sample sizes atom */ | |
2549 | |
2550 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stsz atom"); | |
2551 | |
2552 atom_header = ngx_mp4_atom_header(mp4); | |
2553 stsz_atom = (ngx_mp4_stsz_atom_t *) atom_header; | |
2554 ngx_mp4_set_atom_name(stsz_atom, 's', 't', 's', 'z'); | |
2555 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2556 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
|
2557 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2558 "\"%s\" mp4 stsz atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2559 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2560 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2561 |
4085 | 2562 size = ngx_mp4_get_32value(stsz_atom->uniform_size); |
2563 entries = ngx_mp4_get_32value(stsz_atom->entries); | |
2564 | |
2565 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2566 "sample uniform size:%uD, entries:%uD", size, entries); | |
2567 | |
2568 trak = ngx_mp4_last_trak(mp4); | |
2569 trak->sample_sizes_entries = entries; | |
2570 | |
2571 atom_table = atom_header + sizeof(ngx_mp4_stsz_atom_t); | |
2572 | |
2573 atom = &trak->stsz_atom_buf; | |
2574 atom->temporary = 1; | |
2575 atom->pos = atom_header; | |
2576 atom->last = atom_table; | |
2577 | |
2578 trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf = atom; | |
2579 | |
2580 if (size == 0) { | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2581 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
|
2582 + entries * sizeof(uint32_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2583 { |
4085 | 2584 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
|
2585 "\"%s\" mp4 stsz atom too small", |
4085 | 2586 mp4->file.name.data); |
2587 return NGX_ERROR; | |
2588 } | |
2589 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2590 atom_end = atom_table + entries * sizeof(uint32_t); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2591 |
4085 | 2592 data = &trak->stsz_data_buf; |
2593 data->temporary = 1; | |
2594 data->pos = atom_table; | |
2595 data->last = atom_end; | |
2596 | |
2597 trak->out[NGX_HTTP_MP4_STSZ_DATA].buf = data; | |
2598 | |
2599 } else { | |
2600 /* 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
|
2601 /* TODO : chunk samples */ |
4085 | 2602 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; |
2603 ngx_mp4_set_32value(atom_header, atom_size); | |
2604 trak->size += atom_size; | |
2605 } | |
2606 | |
2607 ngx_mp4_atom_next(mp4, atom_data_size); | |
2608 | |
2609 return NGX_OK; | |
2610 } | |
2611 | |
2612 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2613 static ngx_int_t |
4085 | 2614 ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, |
2615 ngx_http_mp4_trak_t *trak) | |
2616 { | |
2617 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
|
2618 uint32_t *pos, *end; |
4085 | 2619 ngx_buf_t *atom, *data; |
2620 ngx_mp4_stsz_atom_t *stsz_atom; | |
2621 | |
2622 /* | |
2623 * mdia.minf.stbl.stsz updating requires trak->start_sample | |
2624 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2625 * atom which may reside after mdia.minf | |
2626 */ | |
2627 | |
2628 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2629 "mp4 stsz atom update"); | |
2630 | |
2631 data = trak->out[NGX_HTTP_MP4_STSZ_DATA].buf; | |
2632 | |
2633 if (data) { | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2634 if (trak->start_sample > trak->sample_sizes_entries) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2635 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2636 "start time is out mp4 stsz samples in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2637 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2638 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2639 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2640 |
4085 | 2641 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
|
2642 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
|
2643 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2644 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
|
2645 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
|
2646 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2647 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2648 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
4112 | 2649 "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
|
2650 |
4085 | 2651 atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos); |
2652 trak->size += atom_size; | |
2653 | |
2654 atom = trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf; | |
2655 stsz_atom = (ngx_mp4_stsz_atom_t *) atom->pos; | |
2656 | |
2657 ngx_mp4_set_32value(stsz_atom->size, atom_size); | |
2658 ngx_mp4_set_32value(stsz_atom->entries, | |
2659 trak->sample_sizes_entries - trak->start_sample); | |
2660 } | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2661 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2662 return NGX_OK; |
4085 | 2663 } |
2664 | |
2665 | |
2666 typedef struct { | |
2667 u_char size[4]; | |
2668 u_char name[4]; | |
2669 u_char version[1]; | |
2670 u_char flags[3]; | |
2671 u_char entries[4]; | |
2672 } ngx_mp4_stco_atom_t; | |
2673 | |
2674 | |
2675 static ngx_int_t | |
2676 ngx_http_mp4_read_stco_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2677 { | |
2678 u_char *atom_header, *atom_table, *atom_end; | |
2679 uint32_t entries; | |
2680 ngx_buf_t *atom, *data; | |
2681 ngx_mp4_stco_atom_t *stco_atom; | |
2682 ngx_http_mp4_trak_t *trak; | |
2683 | |
2684 /* chunk offsets atom */ | |
2685 | |
2686 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stco atom"); | |
2687 | |
2688 atom_header = ngx_mp4_atom_header(mp4); | |
2689 stco_atom = (ngx_mp4_stco_atom_t *) atom_header; | |
2690 ngx_mp4_set_atom_name(stco_atom, 's', 't', 'c', 'o'); | |
2691 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2692 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
|
2693 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2694 "\"%s\" mp4 stco atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2695 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2696 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2697 |
4085 | 2698 entries = ngx_mp4_get_32value(stco_atom->entries); |
2699 | |
2700 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); | |
2701 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2702 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
|
2703 + entries * sizeof(uint32_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2704 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2705 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2706 "\"%s\" mp4 stco atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2707 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2708 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2709 |
4085 | 2710 atom_table = atom_header + sizeof(ngx_mp4_stco_atom_t); |
2711 atom_end = atom_table + entries * sizeof(uint32_t); | |
2712 | |
2713 trak = ngx_mp4_last_trak(mp4); | |
2714 trak->chunks = entries; | |
2715 | |
4107 | 2716 atom = &trak->stco_atom_buf; |
4085 | 2717 atom->temporary = 1; |
2718 atom->pos = atom_header; | |
2719 atom->last = atom_table; | |
2720 | |
4107 | 2721 data = &trak->stco_data_buf; |
4085 | 2722 data->temporary = 1; |
2723 data->pos = atom_table; | |
2724 data->last = atom_end; | |
2725 | |
2726 trak->out[NGX_HTTP_MP4_STCO_ATOM].buf = atom; | |
2727 trak->out[NGX_HTTP_MP4_STCO_DATA].buf = data; | |
2728 | |
2729 ngx_mp4_atom_next(mp4, atom_data_size); | |
2730 | |
2731 return NGX_OK; | |
2732 } | |
2733 | |
2734 | |
2735 static ngx_int_t | |
2736 ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4, | |
2737 ngx_http_mp4_trak_t *trak) | |
2738 { | |
2739 size_t atom_size; | |
2740 ngx_buf_t *atom, *data; | |
2741 ngx_mp4_stco_atom_t *stco_atom; | |
2742 | |
2743 /* | |
2744 * mdia.minf.stbl.stco updating requires trak->start_chunk | |
2745 * from mdia.minf.stbl.stsc which depends on value from mdia.mdhd | |
2746 * atom which may reside after mdia.minf | |
2747 */ | |
2748 | |
2749 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2750 "mp4 stco atom update"); | |
2751 | |
2752 data = trak->out[NGX_HTTP_MP4_STCO_DATA].buf; | |
2753 | |
2754 if (data == NULL) { | |
2755 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2756 "no mp4 stco atoms were found in \"%s\"", | |
2757 mp4->file.name.data); | |
2758 return NGX_ERROR; | |
2759 } | |
2760 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2761 if (trak->start_chunk > trak->chunks) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2762 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2763 "start time is out mp4 stco chunks in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2764 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2765 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2766 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2767 |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2768 data->pos += trak->start_chunk * sizeof(uint32_t); |
4085 | 2769 atom_size = sizeof(ngx_mp4_stco_atom_t) + (data->last - data->pos); |
2770 trak->size += atom_size; | |
2771 | |
2772 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
|
2773 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
|
2774 ngx_mp4_set_32value(data->pos, trak->start_offset); |
4085 | 2775 |
2776 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2777 "start chunk offset:%uD", trak->start_offset); | |
2778 | |
2779 atom = trak->out[NGX_HTTP_MP4_STCO_ATOM].buf; | |
2780 stco_atom = (ngx_mp4_stco_atom_t *) atom->pos; | |
2781 | |
2782 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
|
2783 ngx_mp4_set_32value(stco_atom->entries, trak->chunks - trak->start_chunk); |
4085 | 2784 |
2785 return NGX_OK; | |
2786 } | |
2787 | |
2788 | |
2789 static void | |
2790 ngx_http_mp4_adjust_stco_atom(ngx_http_mp4_file_t *mp4, | |
2791 ngx_http_mp4_trak_t *trak, int32_t adjustment) | |
2792 { | |
2793 uint32_t offset, *entry, *end; | |
2794 ngx_buf_t *data; | |
2795 | |
2796 /* | |
2797 * moov.trak.mdia.minf.stbl.stco adjustment requires | |
2798 * minimal start offset of all traks and new moov atom size | |
2799 */ | |
2800 | |
2801 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2802 "mp4 stco atom adjustment"); | |
2803 | |
2804 data = trak->out[NGX_HTTP_MP4_STCO_DATA].buf; | |
2805 entry = (uint32_t *) data->pos; | |
2806 end = (uint32_t *) data->last; | |
2807 | |
2808 while (entry < end) { | |
2809 offset = ngx_mp4_get_32value(entry); | |
2810 offset += adjustment; | |
2811 ngx_mp4_set_32value(entry, offset); | |
2812 entry++; | |
2813 } | |
2814 } | |
2815 | |
2816 | |
4112 | 2817 typedef struct { |
2818 u_char size[4]; | |
2819 u_char name[4]; | |
2820 u_char version[1]; | |
2821 u_char flags[3]; | |
2822 u_char entries[4]; | |
2823 } ngx_mp4_co64_atom_t; | |
2824 | |
2825 | |
2826 static ngx_int_t | |
2827 ngx_http_mp4_read_co64_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2828 { | |
2829 u_char *atom_header, *atom_table, *atom_end; | |
2830 uint32_t entries; | |
2831 ngx_buf_t *atom, *data; | |
2832 ngx_mp4_co64_atom_t *co64_atom; | |
2833 ngx_http_mp4_trak_t *trak; | |
2834 | |
2835 /* chunk offsets atom */ | |
2836 | |
2837 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 co64 atom"); | |
2838 | |
2839 atom_header = ngx_mp4_atom_header(mp4); | |
2840 co64_atom = (ngx_mp4_co64_atom_t *) atom_header; | |
2841 ngx_mp4_set_atom_name(co64_atom, 'c', 'o', '6', '4'); | |
2842 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2843 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
|
2844 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2845 "\"%s\" mp4 co64 atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2846 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2847 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2848 |
4112 | 2849 entries = ngx_mp4_get_32value(co64_atom->entries); |
2850 | |
2851 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); | |
2852 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2853 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
|
2854 + entries * sizeof(uint64_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2855 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2856 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2857 "\"%s\" mp4 co64 atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2858 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2859 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2860 |
4112 | 2861 atom_table = atom_header + sizeof(ngx_mp4_co64_atom_t); |
2862 atom_end = atom_table + entries * sizeof(uint64_t); | |
2863 | |
2864 trak = ngx_mp4_last_trak(mp4); | |
2865 trak->chunks = entries; | |
2866 | |
2867 atom = &trak->co64_atom_buf; | |
2868 atom->temporary = 1; | |
2869 atom->pos = atom_header; | |
2870 atom->last = atom_table; | |
2871 | |
2872 data = &trak->co64_data_buf; | |
2873 data->temporary = 1; | |
2874 data->pos = atom_table; | |
2875 data->last = atom_end; | |
2876 | |
2877 trak->out[NGX_HTTP_MP4_CO64_ATOM].buf = atom; | |
2878 trak->out[NGX_HTTP_MP4_CO64_DATA].buf = data; | |
2879 | |
2880 ngx_mp4_atom_next(mp4, atom_data_size); | |
2881 | |
2882 return NGX_OK; | |
2883 } | |
2884 | |
2885 | |
2886 static ngx_int_t | |
2887 ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4, | |
2888 ngx_http_mp4_trak_t *trak) | |
2889 { | |
2890 size_t atom_size; | |
2891 ngx_buf_t *atom, *data; | |
2892 ngx_mp4_co64_atom_t *co64_atom; | |
2893 | |
2894 /* | |
2895 * mdia.minf.stbl.co64 updating requires trak->start_chunk | |
2896 * from mdia.minf.stbl.stsc which depends on value from mdia.mdhd | |
2897 * atom which may reside after mdia.minf | |
2898 */ | |
2899 | |
2900 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2901 "mp4 co64 atom update"); | |
2902 | |
2903 data = trak->out[NGX_HTTP_MP4_CO64_DATA].buf; | |
2904 | |
2905 if (data == NULL) { | |
2906 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2907 "no mp4 co64 atoms were found in \"%s\"", | |
2908 mp4->file.name.data); | |
2909 return NGX_ERROR; | |
2910 } | |
2911 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2912 if (trak->start_chunk > trak->chunks) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2913 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2914 "start time is out mp4 co64 chunks in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2915 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2916 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2917 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2918 |
4112 | 2919 data->pos += trak->start_chunk * sizeof(uint64_t); |
2920 atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos); | |
2921 trak->size += atom_size; | |
2922 | |
2923 trak->start_offset = ngx_mp4_get_64value(data->pos); | |
2924 trak->start_offset += trak->chunk_samples_size; | |
2925 ngx_mp4_set_64value(data->pos, trak->start_offset); | |
2926 | |
2927 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2928 "start chunk offset:%uL", trak->start_offset); | |
2929 | |
2930 atom = trak->out[NGX_HTTP_MP4_CO64_ATOM].buf; | |
2931 co64_atom = (ngx_mp4_co64_atom_t *) atom->pos; | |
2932 | |
2933 ngx_mp4_set_32value(co64_atom->size, atom_size); | |
2934 ngx_mp4_set_32value(co64_atom->entries, trak->chunks - trak->start_chunk); | |
2935 | |
2936 return NGX_OK; | |
2937 } | |
2938 | |
2939 | |
2940 static void | |
2941 ngx_http_mp4_adjust_co64_atom(ngx_http_mp4_file_t *mp4, | |
2942 ngx_http_mp4_trak_t *trak, off_t adjustment) | |
2943 { | |
2944 uint64_t offset, *entry, *end; | |
2945 ngx_buf_t *data; | |
2946 | |
2947 /* | |
2948 * moov.trak.mdia.minf.stbl.co64 adjustment requires | |
2949 * minimal start offset of all traks and new moov atom size | |
2950 */ | |
2951 | |
2952 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2953 "mp4 co64 atom adjustment"); | |
2954 | |
2955 data = trak->out[NGX_HTTP_MP4_CO64_DATA].buf; | |
2956 entry = (uint64_t *) data->pos; | |
2957 end = (uint64_t *) data->last; | |
2958 | |
2959 while (entry < end) { | |
2960 offset = ngx_mp4_get_64value(entry); | |
2961 offset += adjustment; | |
2962 ngx_mp4_set_64value(entry, offset); | |
2963 entry++; | |
2964 } | |
2965 } | |
2966 | |
2967 | |
4085 | 2968 static char * |
2969 ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
2970 { | |
2971 ngx_http_core_loc_conf_t *clcf; | |
2972 | |
2973 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); | |
2974 clcf->handler = ngx_http_mp4_handler; | |
2975 | |
2976 return NGX_CONF_OK; | |
2977 } | |
2978 | |
2979 | |
2980 static void * | |
2981 ngx_http_mp4_create_conf(ngx_conf_t *cf) | |
2982 { | |
2983 ngx_http_mp4_conf_t *conf; | |
2984 | |
2985 conf = ngx_palloc(cf->pool, sizeof(ngx_http_mp4_conf_t)); | |
2986 if (conf == NULL) { | |
2987 return NULL; | |
2988 } | |
2989 | |
2990 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
|
2991 conf->max_buffer_size = NGX_CONF_UNSET_SIZE; |
4085 | 2992 |
2993 return conf; | |
2994 } | |
2995 | |
2996 | |
2997 static char * | |
2998 ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
2999 { | |
3000 ngx_http_mp4_conf_t *prev = parent; | |
3001 ngx_http_mp4_conf_t *conf = child; | |
3002 | |
3003 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
|
3004 ngx_conf_merge_size_value(conf->max_buffer_size, prev->max_buffer_size, |
4085 | 3005 10 * 1024 * 1024); |
3006 | |
3007 return NGX_CONF_OK; | |
3008 } |