Mercurial > hg > nginx
annotate src/http/modules/ngx_http_mp4_module.c @ 5542:847c308917af
Mp4: fix seeks after the last key frame.
Mp4 module does not allow seeks after the last key frame. Since
stss atom only contains key frames it's usually shorter than
other track atoms. That leads to stss seek error when seek
position is close to the end of file. The fix outputs empty
stss frame instead of generating error.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Wed, 29 Jan 2014 13:30:36 +0400 |
parents | 9d056f10fb99 |
children | 5730c0193842 |
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 | |
5542
847c308917af
Mp4: fix seeks after the last key frame.
Roman Arutyunyan <arut@nginx.com>
parents:
5496
diff
changeset
|
2156 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
847c308917af
Mp4: fix seeks after the last key frame.
Roman Arutyunyan <arut@nginx.com>
parents:
5496
diff
changeset
|
2157 "start sample is out of mp4 stss atom"); |
4085 | 2158 |
2159 found: | |
2160 | |
2161 data->pos = (u_char *) entry; | |
2162 | |
2163 start_sample = trak->start_sample; | |
2164 | |
2165 while (entry < end) { | |
2166 sample = ngx_mp4_get_32value(entry); | |
2167 sample -= start_sample; | |
2168 ngx_mp4_set_32value(entry, sample); | |
2169 entry++; | |
2170 } | |
2171 | |
2172 atom_size = sizeof(ngx_http_mp4_stss_atom_t) + (data->last - data->pos); | |
2173 trak->size += atom_size; | |
2174 | |
2175 atom = trak->out[NGX_HTTP_MP4_STSS_ATOM].buf; | |
2176 stss_atom = (ngx_http_mp4_stss_atom_t *) atom->pos; | |
2177 | |
2178 ngx_mp4_set_32value(stss_atom->size, atom_size); | |
2179 ngx_mp4_set_32value(stss_atom->entries, entries); | |
2180 | |
2181 return NGX_OK; | |
2182 } | |
2183 | |
2184 | |
2185 typedef struct { | |
2186 u_char size[4]; | |
2187 u_char name[4]; | |
2188 u_char version[1]; | |
2189 u_char flags[3]; | |
2190 u_char entries[4]; | |
2191 } ngx_mp4_ctts_atom_t; | |
2192 | |
2193 typedef struct { | |
2194 u_char count[4]; | |
2195 u_char offset[4]; | |
2196 } ngx_mp4_ctts_entry_t; | |
2197 | |
2198 | |
2199 static ngx_int_t | |
2200 ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2201 { | |
2202 u_char *atom_header, *atom_table, *atom_end; | |
2203 uint32_t entries; | |
2204 ngx_buf_t *atom, *data; | |
2205 ngx_mp4_ctts_atom_t *ctts_atom; | |
2206 ngx_http_mp4_trak_t *trak; | |
2207 | |
2208 /* composition offsets atom */ | |
2209 | |
2210 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 ctts atom"); | |
2211 | |
2212 atom_header = ngx_mp4_atom_header(mp4); | |
2213 ctts_atom = (ngx_mp4_ctts_atom_t *) atom_header; | |
2214 ngx_mp4_set_atom_name(ctts_atom, 'c', 't', 't', 's'); | |
2215 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2216 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
|
2217 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2218 "\"%s\" mp4 ctts atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2219 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2220 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2221 |
4085 | 2222 entries = ngx_mp4_get_32value(ctts_atom->entries); |
2223 | |
2224 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 2225 "composition offset entries:%uD", entries); |
4085 | 2226 |
2227 trak = ngx_mp4_last_trak(mp4); | |
2228 trak->composition_offset_entries = entries; | |
2229 | |
2230 atom_table = atom_header + sizeof(ngx_mp4_ctts_atom_t); | |
2231 | |
2232 atom = &trak->ctts_atom_buf; | |
2233 atom->temporary = 1; | |
2234 atom->pos = atom_header; | |
2235 atom->last = atom_table; | |
2236 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2237 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
|
2238 + entries * sizeof(ngx_mp4_ctts_entry_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2239 { |
4085 | 2240 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
|
2241 "\"%s\" mp4 ctts atom too small", mp4->file.name.data); |
4085 | 2242 return NGX_ERROR; |
2243 } | |
2244 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2245 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
|
2246 |
4085 | 2247 data = &trak->ctts_data_buf; |
2248 data->temporary = 1; | |
2249 data->pos = atom_table; | |
2250 data->last = atom_end; | |
2251 | |
2252 trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = atom; | |
2253 trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = data; | |
2254 | |
2255 ngx_mp4_atom_next(mp4, atom_data_size); | |
2256 | |
2257 return NGX_OK; | |
2258 } | |
2259 | |
2260 | |
2261 static void | |
2262 ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4, | |
2263 ngx_http_mp4_trak_t *trak) | |
2264 { | |
2265 size_t atom_size; | |
2266 uint32_t entries, count, start_sample; | |
2267 ngx_buf_t *atom, *data; | |
2268 ngx_mp4_ctts_atom_t *ctts_atom; | |
2269 ngx_mp4_ctts_entry_t *entry, *end; | |
2270 | |
2271 /* | |
2272 * mdia.minf.stbl.ctts updating requires trak->start_sample | |
2273 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2274 * atom which may reside after mdia.minf | |
2275 */ | |
2276 | |
2277 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2278 "mp4 ctts atom update"); | |
2279 | |
2280 data = trak->out[NGX_HTTP_MP4_CTTS_DATA].buf; | |
2281 | |
2282 if (data == NULL) { | |
2283 return; | |
2284 } | |
2285 | |
2286 /* sync samples starts from 1 */ | |
2287 start_sample = trak->start_sample + 1; | |
2288 entries = trak->composition_offset_entries; | |
2289 entry = (ngx_mp4_ctts_entry_t *) data->pos; | |
2290 end = (ngx_mp4_ctts_entry_t *) data->last; | |
2291 | |
2292 while (entry < end) { | |
2293 count = ngx_mp4_get_32value(entry->count); | |
2294 | |
4088
8fe1da7b8386
bugfix of r4086: nginx could not be built without debug log.
Igor Sysoev <igor@sysoev.ru>
parents:
4087
diff
changeset
|
2295 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
4085 | 2296 "start:%uD, count:%uD, offset:%uD", |
2297 start_sample, count, ngx_mp4_get_32value(entry->offset)); | |
2298 | |
2299 if (start_sample <= count) { | |
2300 count -= (start_sample - 1); | |
2301 ngx_mp4_set_32value(entry->count, count); | |
2302 goto found; | |
2303 } | |
2304 | |
2305 start_sample -= count; | |
2306 entries--; | |
2307 entry++; | |
2308 } | |
2309 | |
2310 trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL; | |
2311 trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL; | |
2312 | |
2313 return; | |
2314 | |
2315 found: | |
2316 | |
2317 data->pos = (u_char *) entry; | |
2318 atom_size = sizeof(ngx_mp4_ctts_atom_t) + (data->last - data->pos); | |
2319 trak->size += atom_size; | |
2320 | |
2321 atom = trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf; | |
2322 ctts_atom = (ngx_mp4_ctts_atom_t *) atom->pos; | |
2323 | |
2324 ngx_mp4_set_32value(ctts_atom->size, atom_size); | |
2325 ngx_mp4_set_32value(ctts_atom->entries, entries); | |
2326 | |
2327 return; | |
2328 } | |
2329 | |
2330 | |
2331 typedef struct { | |
2332 u_char size[4]; | |
2333 u_char name[4]; | |
2334 u_char version[1]; | |
2335 u_char flags[3]; | |
2336 u_char entries[4]; | |
2337 } ngx_mp4_stsc_atom_t; | |
2338 | |
2339 | |
2340 static ngx_int_t | |
2341 ngx_http_mp4_read_stsc_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2342 { | |
2343 u_char *atom_header, *atom_table, *atom_end; | |
2344 uint32_t entries; | |
2345 ngx_buf_t *atom, *data; | |
2346 ngx_mp4_stsc_atom_t *stsc_atom; | |
2347 ngx_http_mp4_trak_t *trak; | |
2348 | |
2349 /* sample-to-chunk atom */ | |
2350 | |
2351 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stsc atom"); | |
2352 | |
2353 atom_header = ngx_mp4_atom_header(mp4); | |
2354 stsc_atom = (ngx_mp4_stsc_atom_t *) atom_header; | |
2355 ngx_mp4_set_atom_name(stsc_atom, 's', 't', 's', 'c'); | |
2356 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2357 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
|
2358 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2359 "\"%s\" mp4 stsc atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2360 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2361 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2362 |
4085 | 2363 entries = ngx_mp4_get_32value(stsc_atom->entries); |
2364 | |
2365 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 2366 "sample-to-chunk entries:%uD", entries); |
4085 | 2367 |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2368 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
|
2369 + entries * sizeof(ngx_mp4_stsc_entry_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2370 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2371 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2372 "\"%s\" mp4 stsc atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2373 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2374 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2375 |
4085 | 2376 atom_table = atom_header + sizeof(ngx_mp4_stsc_atom_t); |
2377 atom_end = atom_table + entries * sizeof(ngx_mp4_stsc_entry_t); | |
2378 | |
2379 trak = ngx_mp4_last_trak(mp4); | |
2380 trak->sample_to_chunk_entries = entries; | |
2381 | |
2382 atom = &trak->stsc_atom_buf; | |
2383 atom->temporary = 1; | |
2384 atom->pos = atom_header; | |
2385 atom->last = atom_table; | |
2386 | |
2387 data = &trak->stsc_data_buf; | |
2388 data->temporary = 1; | |
2389 data->pos = atom_table; | |
2390 data->last = atom_end; | |
2391 | |
2392 trak->out[NGX_HTTP_MP4_STSC_ATOM].buf = atom; | |
2393 trak->out[NGX_HTTP_MP4_STSC_DATA].buf = data; | |
2394 | |
2395 ngx_mp4_atom_next(mp4, atom_data_size); | |
2396 | |
2397 return NGX_OK; | |
2398 } | |
2399 | |
2400 | |
2401 static ngx_int_t | |
2402 ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4, | |
2403 ngx_http_mp4_trak_t *trak) | |
2404 { | |
2405 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
|
2406 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
|
2407 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
|
2408 ngx_buf_t *atom, *data, *buf; |
4085 | 2409 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
|
2410 ngx_mp4_stsc_entry_t *entry, *first, *end; |
4085 | 2411 |
2412 /* | |
2413 * mdia.minf.stbl.stsc updating requires trak->start_sample | |
2414 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2415 * atom which may reside after mdia.minf | |
2416 */ | |
2417 | |
2418 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2419 "mp4 stsc atom update"); | |
2420 | |
2421 data = trak->out[NGX_HTTP_MP4_STSC_DATA].buf; | |
2422 | |
2423 if (data == NULL) { | |
2424 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2425 "no mp4 stsc atoms were found in \"%s\"", | |
2426 mp4->file.name.data); | |
2427 return NGX_ERROR; | |
2428 } | |
2429 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2430 if (trak->sample_to_chunk_entries == 0) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2431 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2432 "zero number of entries in stsc atom in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2433 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2434 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2435 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2436 |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2437 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
|
2438 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
|
2439 |
4085 | 2440 entry = (ngx_mp4_stsc_entry_t *) data->pos; |
2441 end = (ngx_mp4_stsc_entry_t *) data->last; | |
2442 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2443 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
|
2444 samples = ngx_mp4_get_32value(entry->samples); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2445 id = ngx_mp4_get_32value(entry->id); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2446 entry++; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2447 |
4085 | 2448 while (entry < end) { |
2449 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2450 next_chunk = 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
|
2451 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2452 ngx_log_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
|
2453 "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
|
2454 "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
|
2455 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
|
2456 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2457 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
|
2458 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2459 if (start_sample <= n) { |
4085 | 2460 goto found; |
2461 } | |
2462 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2463 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
|
2464 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2465 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
|
2466 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
|
2467 id = ngx_mp4_get_32value(entry->id); |
4085 | 2468 entries--; |
2469 entry++; | |
2470 } | |
2471 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2472 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
|
2473 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2474 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
|
2475 "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
|
2476 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
|
2477 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2478 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
|
2479 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2480 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
|
2481 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
|
2482 "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
|
2483 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
|
2484 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
|
2485 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2486 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2487 found: |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2488 |
4085 | 2489 entries++; |
2490 entry--; | |
2491 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2492 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
|
2493 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
|
2494 "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
|
2495 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
|
2496 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
|
2497 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2498 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2499 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
|
2500 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2501 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
|
2502 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
|
2503 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2504 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
|
2505 "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
|
2506 trak->start_chunk, trak->chunk_samples); |
4085 | 2507 |
2508 data->pos = (u_char *) entry; | |
2509 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
|
2510 |
4382
b4d54fa76853
Fixed mp4 if first entry in stsc was skipped (ticket #72).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4306
diff
changeset
|
2511 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
|
2512 |
4687
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2513 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
|
2514 |
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2515 /* 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
|
2516 |
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2517 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
|
2518 |
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2519 } 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
|
2520 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2521 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
|
2522 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
|
2523 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
|
2524 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
|
2525 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2526 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
|
2527 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
|
2528 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
|
2529 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
|
2530 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2531 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
|
2532 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2533 ngx_mp4_set_32value(entry->chunk, 2); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2534 |
4687
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2535 entries++; |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2536 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
|
2537 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2538 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2539 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
|
2540 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
|
2541 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
|
2542 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
|
2543 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2544 |
4085 | 2545 trak->size += atom_size; |
2546 | |
2547 atom = trak->out[NGX_HTTP_MP4_STSC_ATOM].buf; | |
2548 stsc_atom = (ngx_mp4_stsc_atom_t *) atom->pos; | |
2549 | |
2550 ngx_mp4_set_32value(stsc_atom->size, atom_size); | |
2551 ngx_mp4_set_32value(stsc_atom->entries, entries); | |
2552 | |
2553 return NGX_OK; | |
2554 } | |
2555 | |
2556 | |
2557 typedef struct { | |
2558 u_char size[4]; | |
2559 u_char name[4]; | |
2560 u_char version[1]; | |
2561 u_char flags[3]; | |
2562 u_char uniform_size[4]; | |
2563 u_char entries[4]; | |
2564 } ngx_mp4_stsz_atom_t; | |
2565 | |
2566 | |
2567 static ngx_int_t | |
2568 ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2569 { | |
2570 u_char *atom_header, *atom_table, *atom_end; | |
2571 size_t atom_size; | |
2572 uint32_t entries, size; | |
2573 ngx_buf_t *atom, *data; | |
2574 ngx_mp4_stsz_atom_t *stsz_atom; | |
2575 ngx_http_mp4_trak_t *trak; | |
2576 | |
2577 /* sample sizes atom */ | |
2578 | |
2579 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stsz atom"); | |
2580 | |
2581 atom_header = ngx_mp4_atom_header(mp4); | |
2582 stsz_atom = (ngx_mp4_stsz_atom_t *) atom_header; | |
2583 ngx_mp4_set_atom_name(stsz_atom, 's', 't', 's', 'z'); | |
2584 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2585 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
|
2586 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2587 "\"%s\" mp4 stsz atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2588 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2589 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2590 |
4085 | 2591 size = ngx_mp4_get_32value(stsz_atom->uniform_size); |
2592 entries = ngx_mp4_get_32value(stsz_atom->entries); | |
2593 | |
2594 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2595 "sample uniform size:%uD, entries:%uD", size, entries); | |
2596 | |
2597 trak = ngx_mp4_last_trak(mp4); | |
2598 trak->sample_sizes_entries = entries; | |
2599 | |
2600 atom_table = atom_header + sizeof(ngx_mp4_stsz_atom_t); | |
2601 | |
2602 atom = &trak->stsz_atom_buf; | |
2603 atom->temporary = 1; | |
2604 atom->pos = atom_header; | |
2605 atom->last = atom_table; | |
2606 | |
2607 trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf = atom; | |
2608 | |
2609 if (size == 0) { | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2610 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
|
2611 + entries * sizeof(uint32_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2612 { |
4085 | 2613 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
|
2614 "\"%s\" mp4 stsz atom too small", |
4085 | 2615 mp4->file.name.data); |
2616 return NGX_ERROR; | |
2617 } | |
2618 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2619 atom_end = atom_table + entries * sizeof(uint32_t); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2620 |
4085 | 2621 data = &trak->stsz_data_buf; |
2622 data->temporary = 1; | |
2623 data->pos = atom_table; | |
2624 data->last = atom_end; | |
2625 | |
2626 trak->out[NGX_HTTP_MP4_STSZ_DATA].buf = data; | |
2627 | |
2628 } else { | |
2629 /* 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
|
2630 /* TODO : chunk samples */ |
4085 | 2631 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; |
2632 ngx_mp4_set_32value(atom_header, atom_size); | |
2633 trak->size += atom_size; | |
2634 } | |
2635 | |
2636 ngx_mp4_atom_next(mp4, atom_data_size); | |
2637 | |
2638 return NGX_OK; | |
2639 } | |
2640 | |
2641 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2642 static ngx_int_t |
4085 | 2643 ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, |
2644 ngx_http_mp4_trak_t *trak) | |
2645 { | |
2646 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
|
2647 uint32_t *pos, *end; |
4085 | 2648 ngx_buf_t *atom, *data; |
2649 ngx_mp4_stsz_atom_t *stsz_atom; | |
2650 | |
2651 /* | |
2652 * mdia.minf.stbl.stsz updating requires trak->start_sample | |
2653 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2654 * atom which may reside after mdia.minf | |
2655 */ | |
2656 | |
2657 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2658 "mp4 stsz atom update"); | |
2659 | |
2660 data = trak->out[NGX_HTTP_MP4_STSZ_DATA].buf; | |
2661 | |
2662 if (data) { | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2663 if (trak->start_sample > trak->sample_sizes_entries) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2664 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2665 "start time is out mp4 stsz samples in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2666 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2667 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2668 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2669 |
4085 | 2670 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
|
2671 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
|
2672 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2673 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
|
2674 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
|
2675 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2676 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2677 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
4112 | 2678 "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
|
2679 |
4085 | 2680 atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos); |
2681 trak->size += atom_size; | |
2682 | |
2683 atom = trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf; | |
2684 stsz_atom = (ngx_mp4_stsz_atom_t *) atom->pos; | |
2685 | |
2686 ngx_mp4_set_32value(stsz_atom->size, atom_size); | |
2687 ngx_mp4_set_32value(stsz_atom->entries, | |
2688 trak->sample_sizes_entries - trak->start_sample); | |
2689 } | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2690 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2691 return NGX_OK; |
4085 | 2692 } |
2693 | |
2694 | |
2695 typedef struct { | |
2696 u_char size[4]; | |
2697 u_char name[4]; | |
2698 u_char version[1]; | |
2699 u_char flags[3]; | |
2700 u_char entries[4]; | |
2701 } ngx_mp4_stco_atom_t; | |
2702 | |
2703 | |
2704 static ngx_int_t | |
2705 ngx_http_mp4_read_stco_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2706 { | |
2707 u_char *atom_header, *atom_table, *atom_end; | |
2708 uint32_t entries; | |
2709 ngx_buf_t *atom, *data; | |
2710 ngx_mp4_stco_atom_t *stco_atom; | |
2711 ngx_http_mp4_trak_t *trak; | |
2712 | |
2713 /* chunk offsets atom */ | |
2714 | |
2715 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stco atom"); | |
2716 | |
2717 atom_header = ngx_mp4_atom_header(mp4); | |
2718 stco_atom = (ngx_mp4_stco_atom_t *) atom_header; | |
2719 ngx_mp4_set_atom_name(stco_atom, 's', 't', 'c', 'o'); | |
2720 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2721 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
|
2722 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2723 "\"%s\" mp4 stco atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2724 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2725 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2726 |
4085 | 2727 entries = ngx_mp4_get_32value(stco_atom->entries); |
2728 | |
2729 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); | |
2730 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2731 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
|
2732 + entries * sizeof(uint32_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2733 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2734 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2735 "\"%s\" mp4 stco atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2736 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2737 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2738 |
4085 | 2739 atom_table = atom_header + sizeof(ngx_mp4_stco_atom_t); |
2740 atom_end = atom_table + entries * sizeof(uint32_t); | |
2741 | |
2742 trak = ngx_mp4_last_trak(mp4); | |
2743 trak->chunks = entries; | |
2744 | |
4107 | 2745 atom = &trak->stco_atom_buf; |
4085 | 2746 atom->temporary = 1; |
2747 atom->pos = atom_header; | |
2748 atom->last = atom_table; | |
2749 | |
4107 | 2750 data = &trak->stco_data_buf; |
4085 | 2751 data->temporary = 1; |
2752 data->pos = atom_table; | |
2753 data->last = atom_end; | |
2754 | |
2755 trak->out[NGX_HTTP_MP4_STCO_ATOM].buf = atom; | |
2756 trak->out[NGX_HTTP_MP4_STCO_DATA].buf = data; | |
2757 | |
2758 ngx_mp4_atom_next(mp4, atom_data_size); | |
2759 | |
2760 return NGX_OK; | |
2761 } | |
2762 | |
2763 | |
2764 static ngx_int_t | |
2765 ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4, | |
2766 ngx_http_mp4_trak_t *trak) | |
2767 { | |
2768 size_t atom_size; | |
2769 ngx_buf_t *atom, *data; | |
2770 ngx_mp4_stco_atom_t *stco_atom; | |
2771 | |
2772 /* | |
2773 * mdia.minf.stbl.stco updating requires trak->start_chunk | |
2774 * from mdia.minf.stbl.stsc which depends on value from mdia.mdhd | |
2775 * atom which may reside after mdia.minf | |
2776 */ | |
2777 | |
2778 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2779 "mp4 stco atom update"); | |
2780 | |
2781 data = trak->out[NGX_HTTP_MP4_STCO_DATA].buf; | |
2782 | |
2783 if (data == NULL) { | |
2784 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2785 "no mp4 stco atoms were found in \"%s\"", | |
2786 mp4->file.name.data); | |
2787 return NGX_ERROR; | |
2788 } | |
2789 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2790 if (trak->start_chunk > trak->chunks) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2791 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2792 "start time is out mp4 stco chunks in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2793 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2794 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2795 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2796 |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2797 data->pos += trak->start_chunk * sizeof(uint32_t); |
4085 | 2798 atom_size = sizeof(ngx_mp4_stco_atom_t) + (data->last - data->pos); |
2799 trak->size += atom_size; | |
2800 | |
2801 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
|
2802 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
|
2803 ngx_mp4_set_32value(data->pos, trak->start_offset); |
4085 | 2804 |
2805 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2806 "start chunk offset:%uD", trak->start_offset); | |
2807 | |
2808 atom = trak->out[NGX_HTTP_MP4_STCO_ATOM].buf; | |
2809 stco_atom = (ngx_mp4_stco_atom_t *) atom->pos; | |
2810 | |
2811 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
|
2812 ngx_mp4_set_32value(stco_atom->entries, trak->chunks - trak->start_chunk); |
4085 | 2813 |
2814 return NGX_OK; | |
2815 } | |
2816 | |
2817 | |
2818 static void | |
2819 ngx_http_mp4_adjust_stco_atom(ngx_http_mp4_file_t *mp4, | |
2820 ngx_http_mp4_trak_t *trak, int32_t adjustment) | |
2821 { | |
2822 uint32_t offset, *entry, *end; | |
2823 ngx_buf_t *data; | |
2824 | |
2825 /* | |
2826 * moov.trak.mdia.minf.stbl.stco adjustment requires | |
2827 * minimal start offset of all traks and new moov atom size | |
2828 */ | |
2829 | |
2830 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2831 "mp4 stco atom adjustment"); | |
2832 | |
2833 data = trak->out[NGX_HTTP_MP4_STCO_DATA].buf; | |
2834 entry = (uint32_t *) data->pos; | |
2835 end = (uint32_t *) data->last; | |
2836 | |
2837 while (entry < end) { | |
2838 offset = ngx_mp4_get_32value(entry); | |
2839 offset += adjustment; | |
2840 ngx_mp4_set_32value(entry, offset); | |
2841 entry++; | |
2842 } | |
2843 } | |
2844 | |
2845 | |
4112 | 2846 typedef struct { |
2847 u_char size[4]; | |
2848 u_char name[4]; | |
2849 u_char version[1]; | |
2850 u_char flags[3]; | |
2851 u_char entries[4]; | |
2852 } ngx_mp4_co64_atom_t; | |
2853 | |
2854 | |
2855 static ngx_int_t | |
2856 ngx_http_mp4_read_co64_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2857 { | |
2858 u_char *atom_header, *atom_table, *atom_end; | |
2859 uint32_t entries; | |
2860 ngx_buf_t *atom, *data; | |
2861 ngx_mp4_co64_atom_t *co64_atom; | |
2862 ngx_http_mp4_trak_t *trak; | |
2863 | |
2864 /* chunk offsets atom */ | |
2865 | |
2866 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 co64 atom"); | |
2867 | |
2868 atom_header = ngx_mp4_atom_header(mp4); | |
2869 co64_atom = (ngx_mp4_co64_atom_t *) atom_header; | |
2870 ngx_mp4_set_atom_name(co64_atom, 'c', 'o', '6', '4'); | |
2871 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2872 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
|
2873 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2874 "\"%s\" mp4 co64 atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2875 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2876 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2877 |
4112 | 2878 entries = ngx_mp4_get_32value(co64_atom->entries); |
2879 | |
2880 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); | |
2881 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2882 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
|
2883 + entries * sizeof(uint64_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2884 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2885 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2886 "\"%s\" mp4 co64 atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2887 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2888 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2889 |
4112 | 2890 atom_table = atom_header + sizeof(ngx_mp4_co64_atom_t); |
2891 atom_end = atom_table + entries * sizeof(uint64_t); | |
2892 | |
2893 trak = ngx_mp4_last_trak(mp4); | |
2894 trak->chunks = entries; | |
2895 | |
2896 atom = &trak->co64_atom_buf; | |
2897 atom->temporary = 1; | |
2898 atom->pos = atom_header; | |
2899 atom->last = atom_table; | |
2900 | |
2901 data = &trak->co64_data_buf; | |
2902 data->temporary = 1; | |
2903 data->pos = atom_table; | |
2904 data->last = atom_end; | |
2905 | |
2906 trak->out[NGX_HTTP_MP4_CO64_ATOM].buf = atom; | |
2907 trak->out[NGX_HTTP_MP4_CO64_DATA].buf = data; | |
2908 | |
2909 ngx_mp4_atom_next(mp4, atom_data_size); | |
2910 | |
2911 return NGX_OK; | |
2912 } | |
2913 | |
2914 | |
2915 static ngx_int_t | |
2916 ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4, | |
2917 ngx_http_mp4_trak_t *trak) | |
2918 { | |
2919 size_t atom_size; | |
2920 ngx_buf_t *atom, *data; | |
2921 ngx_mp4_co64_atom_t *co64_atom; | |
2922 | |
2923 /* | |
2924 * mdia.minf.stbl.co64 updating requires trak->start_chunk | |
2925 * from mdia.minf.stbl.stsc which depends on value from mdia.mdhd | |
2926 * atom which may reside after mdia.minf | |
2927 */ | |
2928 | |
2929 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2930 "mp4 co64 atom update"); | |
2931 | |
2932 data = trak->out[NGX_HTTP_MP4_CO64_DATA].buf; | |
2933 | |
2934 if (data == NULL) { | |
2935 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2936 "no mp4 co64 atoms were found in \"%s\"", | |
2937 mp4->file.name.data); | |
2938 return NGX_ERROR; | |
2939 } | |
2940 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2941 if (trak->start_chunk > trak->chunks) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2942 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2943 "start time is out mp4 co64 chunks in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2944 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2945 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2946 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2947 |
4112 | 2948 data->pos += trak->start_chunk * sizeof(uint64_t); |
2949 atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos); | |
2950 trak->size += atom_size; | |
2951 | |
2952 trak->start_offset = ngx_mp4_get_64value(data->pos); | |
2953 trak->start_offset += trak->chunk_samples_size; | |
2954 ngx_mp4_set_64value(data->pos, trak->start_offset); | |
2955 | |
2956 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2957 "start chunk offset:%uL", trak->start_offset); | |
2958 | |
2959 atom = trak->out[NGX_HTTP_MP4_CO64_ATOM].buf; | |
2960 co64_atom = (ngx_mp4_co64_atom_t *) atom->pos; | |
2961 | |
2962 ngx_mp4_set_32value(co64_atom->size, atom_size); | |
2963 ngx_mp4_set_32value(co64_atom->entries, trak->chunks - trak->start_chunk); | |
2964 | |
2965 return NGX_OK; | |
2966 } | |
2967 | |
2968 | |
2969 static void | |
2970 ngx_http_mp4_adjust_co64_atom(ngx_http_mp4_file_t *mp4, | |
2971 ngx_http_mp4_trak_t *trak, off_t adjustment) | |
2972 { | |
2973 uint64_t offset, *entry, *end; | |
2974 ngx_buf_t *data; | |
2975 | |
2976 /* | |
2977 * moov.trak.mdia.minf.stbl.co64 adjustment requires | |
2978 * minimal start offset of all traks and new moov atom size | |
2979 */ | |
2980 | |
2981 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2982 "mp4 co64 atom adjustment"); | |
2983 | |
2984 data = trak->out[NGX_HTTP_MP4_CO64_DATA].buf; | |
2985 entry = (uint64_t *) data->pos; | |
2986 end = (uint64_t *) data->last; | |
2987 | |
2988 while (entry < end) { | |
2989 offset = ngx_mp4_get_64value(entry); | |
2990 offset += adjustment; | |
2991 ngx_mp4_set_64value(entry, offset); | |
2992 entry++; | |
2993 } | |
2994 } | |
2995 | |
2996 | |
4085 | 2997 static char * |
2998 ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
2999 { | |
3000 ngx_http_core_loc_conf_t *clcf; | |
3001 | |
3002 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); | |
3003 clcf->handler = ngx_http_mp4_handler; | |
3004 | |
3005 return NGX_CONF_OK; | |
3006 } | |
3007 | |
3008 | |
3009 static void * | |
3010 ngx_http_mp4_create_conf(ngx_conf_t *cf) | |
3011 { | |
3012 ngx_http_mp4_conf_t *conf; | |
3013 | |
3014 conf = ngx_palloc(cf->pool, sizeof(ngx_http_mp4_conf_t)); | |
3015 if (conf == NULL) { | |
3016 return NULL; | |
3017 } | |
3018 | |
3019 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
|
3020 conf->max_buffer_size = NGX_CONF_UNSET_SIZE; |
4085 | 3021 |
3022 return conf; | |
3023 } | |
3024 | |
3025 | |
3026 static char * | |
3027 ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
3028 { | |
3029 ngx_http_mp4_conf_t *prev = parent; | |
3030 ngx_http_mp4_conf_t *conf = child; | |
3031 | |
3032 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
|
3033 ngx_conf_merge_size_value(conf->max_buffer_size, prev->max_buffer_size, |
4085 | 3034 10 * 1024 * 1024); |
3035 | |
3036 return NGX_CONF_OK; | |
3037 } |