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