Mercurial > hg > nginx
annotate src/http/modules/ngx_http_mp4_module.c @ 5543:5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Mp4 module does not check movie and track durations when reading
file. Instead it generates errors when track metadata is shorter
than seek position. Now such tracks are skipped and movie duration
check is performed at file read stage.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Wed, 29 Jan 2014 13:33:45 +0400 |
parents | 847c308917af |
children | 2f586f1684fa |
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; | |
5543
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1211 uint64_t duration, start_time; |
4085 | 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 | |
5543
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1254 start_time = (uint64_t) mp4->start * timescale / 1000; |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1255 |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1256 if (duration < start_time) { |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1257 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1258 "\"%s\" mp4 start time exceeds file duration", |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1259 mp4->file.name.data); |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1260 return NGX_ERROR; |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1261 } |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1262 |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1263 duration -= start_time; |
4085 | 1264 |
1265 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1266 "mvhd new duration:%uL, time:%.3fs", | |
1267 duration, (double) duration / timescale); | |
1268 | |
1269 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1270 ngx_mp4_set_32value(mvhd_atom->size, atom_size); | |
1271 | |
1272 if (mvhd_atom->version[0] == 0) { | |
1273 ngx_mp4_set_32value(mvhd_atom->duration, duration); | |
1274 | |
1275 } else { | |
1276 ngx_mp4_set_64value(mvhd64_atom->duration, duration); | |
1277 } | |
1278 | |
1279 atom = &mp4->mvhd_atom_buf; | |
1280 atom->temporary = 1; | |
1281 atom->pos = atom_header; | |
1282 atom->last = atom_header + atom_size; | |
1283 | |
1284 mp4->mvhd_atom.buf = atom; | |
1285 | |
1286 ngx_mp4_atom_next(mp4, atom_data_size); | |
1287 | |
1288 return NGX_OK; | |
1289 } | |
1290 | |
1291 | |
1292 static ngx_int_t | |
1293 ngx_http_mp4_read_trak_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1294 { | |
4099
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1295 u_char *atom_header, *atom_end; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1296 off_t atom_file_end; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1297 ngx_int_t rc; |
4085 | 1298 ngx_buf_t *atom; |
1299 ngx_http_mp4_trak_t *trak; | |
1300 | |
1301 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 trak atom"); | |
1302 | |
1303 trak = ngx_array_push(&mp4->trak); | |
1304 if (trak == NULL) { | |
1305 return NGX_ERROR; | |
1306 } | |
1307 | |
1308 ngx_memzero(trak, sizeof(ngx_http_mp4_trak_t)); | |
1309 | |
1310 atom_header = ngx_mp4_atom_header(mp4); | |
1311 ngx_mp4_set_atom_name(atom_header, 't', 'r', 'a', 'k'); | |
1312 | |
1313 atom = &trak->trak_atom_buf; | |
1314 atom->temporary = 1; | |
1315 atom->pos = atom_header; | |
1316 atom->last = atom_header + sizeof(ngx_mp4_atom_header_t); | |
1317 | |
1318 trak->out[NGX_HTTP_MP4_TRAK_ATOM].buf = atom; | |
1319 | |
5359
2fda9065d0f4
Win32: Borland C compatibility fixes.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5358
diff
changeset
|
1320 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
|
1321 atom_file_end = mp4->offset + atom_data_size; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1322 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1323 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
|
1324 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1325 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
|
1326 "mp4 trak atom: %i", rc); |
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 if (rc == NGX_DECLINED) { |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1329 /* skip this trak */ |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1330 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
|
1331 mp4->trak.nelts--; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1332 mp4->buffer_pos = atom_end; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1333 mp4->offset = atom_file_end; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1334 return NGX_OK; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1335 } |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1336 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1337 return rc; |
4085 | 1338 } |
1339 | |
1340 | |
1341 static void | |
1342 ngx_http_mp4_update_trak_atom(ngx_http_mp4_file_t *mp4, | |
1343 ngx_http_mp4_trak_t *trak) | |
1344 { | |
1345 ngx_buf_t *atom; | |
1346 | |
1347 trak->size += sizeof(ngx_mp4_atom_header_t); | |
1348 atom = &trak->trak_atom_buf; | |
1349 ngx_mp4_set_32value(atom->pos, trak->size); | |
1350 } | |
1351 | |
1352 | |
1353 static ngx_int_t | |
1354 ngx_http_mp4_read_cmov_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1355 { | |
1356 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
1357 "\"%s\" mp4 compressed moov atom (cmov) is not supported", | |
1358 mp4->file.name.data); | |
1359 | |
1360 return NGX_ERROR; | |
1361 } | |
1362 | |
1363 | |
1364 typedef struct { | |
1365 u_char size[4]; | |
1366 u_char name[4]; | |
1367 u_char version[1]; | |
1368 u_char flags[3]; | |
1369 u_char creation_time[4]; | |
1370 u_char modification_time[4]; | |
1371 u_char track_id[4]; | |
1372 u_char reserved1[4]; | |
1373 u_char duration[4]; | |
1374 u_char reserved2[8]; | |
1375 u_char layer[2]; | |
1376 u_char group[2]; | |
1377 u_char volume[2]; | |
1378 u_char reverved3[2]; | |
1379 u_char matrix[36]; | |
1380 u_char width[4]; | |
1381 u_char heigth[4]; | |
1382 } ngx_mp4_tkhd_atom_t; | |
1383 | |
1384 typedef struct { | |
1385 u_char size[4]; | |
1386 u_char name[4]; | |
1387 u_char version[1]; | |
1388 u_char flags[3]; | |
1389 u_char creation_time[8]; | |
1390 u_char modification_time[8]; | |
1391 u_char track_id[4]; | |
1392 u_char reserved1[4]; | |
1393 u_char duration[8]; | |
1394 u_char reserved2[8]; | |
1395 u_char layer[2]; | |
1396 u_char group[2]; | |
1397 u_char volume[2]; | |
1398 u_char reverved3[2]; | |
1399 u_char matrix[36]; | |
1400 u_char width[4]; | |
1401 u_char heigth[4]; | |
1402 } ngx_mp4_tkhd64_atom_t; | |
1403 | |
1404 | |
1405 static ngx_int_t | |
1406 ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1407 { | |
1408 u_char *atom_header; | |
1409 size_t atom_size; | |
5543
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1410 uint64_t duration, start_time; |
4085 | 1411 ngx_buf_t *atom; |
1412 ngx_http_mp4_trak_t *trak; | |
1413 ngx_mp4_tkhd_atom_t *tkhd_atom; | |
1414 ngx_mp4_tkhd64_atom_t *tkhd64_atom; | |
1415 | |
1416 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 tkhd atom"); | |
1417 | |
1418 atom_header = ngx_mp4_atom_header(mp4); | |
1419 tkhd_atom = (ngx_mp4_tkhd_atom_t *) atom_header; | |
1420 tkhd64_atom = (ngx_mp4_tkhd64_atom_t *) atom_header; | |
1421 ngx_mp4_set_atom_name(tkhd_atom, 't', 'k', 'h', 'd'); | |
1422 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1423 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
|
1424 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1425 "\"%s\" mp4 tkhd atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1426 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1427 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1428 |
4085 | 1429 if (tkhd_atom->version[0] == 0) { |
1430 /* version 0: 32-bit duration */ | |
1431 duration = ngx_mp4_get_32value(tkhd_atom->duration); | |
1432 | |
1433 } else { | |
1434 /* version 1: 64-bit duration */ | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1435 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1436 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
|
1437 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1438 "\"%s\" mp4 tkhd atom too small", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1439 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1440 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1441 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1442 |
4085 | 1443 duration = ngx_mp4_get_64value(tkhd64_atom->duration); |
1444 } | |
1445 | |
1446 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1447 "tkhd duration:%uL, time:%.3fs", | |
1448 duration, (double) duration / mp4->timescale); | |
1449 | |
5543
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1450 start_time = (uint64_t) mp4->start * mp4->timescale / 1000; |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1451 |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1452 if (duration < start_time) { |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1453 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1454 "tkhd duration is less than start time"); |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1455 return NGX_DECLINED; |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1456 } |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1457 |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1458 duration -= start_time; |
4085 | 1459 |
1460 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1461 "tkhd new duration:%uL, time:%.3fs", | |
1462 duration, (double) duration / mp4->timescale); | |
1463 | |
1464 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1465 | |
1466 trak = ngx_mp4_last_trak(mp4); | |
1467 trak->tkhd_size = atom_size; | |
1468 | |
1469 ngx_mp4_set_32value(tkhd_atom->size, atom_size); | |
1470 | |
1471 if (tkhd_atom->version[0] == 0) { | |
1472 ngx_mp4_set_32value(tkhd_atom->duration, duration); | |
1473 | |
1474 } else { | |
1475 ngx_mp4_set_64value(tkhd64_atom->duration, duration); | |
1476 } | |
1477 | |
1478 atom = &trak->tkhd_atom_buf; | |
1479 atom->temporary = 1; | |
1480 atom->pos = atom_header; | |
1481 atom->last = atom_header + atom_size; | |
1482 | |
1483 trak->out[NGX_HTTP_MP4_TKHD_ATOM].buf = atom; | |
1484 | |
1485 ngx_mp4_atom_next(mp4, atom_data_size); | |
1486 | |
1487 return NGX_OK; | |
1488 } | |
1489 | |
1490 | |
1491 static ngx_int_t | |
1492 ngx_http_mp4_read_mdia_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1493 { | |
1494 u_char *atom_header; | |
1495 ngx_buf_t *atom; | |
1496 ngx_http_mp4_trak_t *trak; | |
1497 | |
1498 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "process mdia atom"); | |
1499 | |
1500 atom_header = ngx_mp4_atom_header(mp4); | |
1501 ngx_mp4_set_atom_name(atom_header, 'm', 'd', 'i', 'a'); | |
1502 | |
1503 trak = ngx_mp4_last_trak(mp4); | |
1504 | |
1505 atom = &trak->mdia_atom_buf; | |
1506 atom->temporary = 1; | |
1507 atom->pos = atom_header; | |
1508 atom->last = atom_header + sizeof(ngx_mp4_atom_header_t); | |
1509 | |
1510 trak->out[NGX_HTTP_MP4_MDIA_ATOM].buf = atom; | |
1511 | |
1512 return ngx_http_mp4_read_atom(mp4, ngx_http_mp4_mdia_atoms, atom_data_size); | |
1513 } | |
1514 | |
1515 | |
1516 static void | |
1517 ngx_http_mp4_update_mdia_atom(ngx_http_mp4_file_t *mp4, | |
1518 ngx_http_mp4_trak_t *trak) | |
1519 { | |
1520 ngx_buf_t *atom; | |
1521 | |
1522 trak->size += sizeof(ngx_mp4_atom_header_t); | |
1523 atom = &trak->mdia_atom_buf; | |
1524 ngx_mp4_set_32value(atom->pos, trak->size); | |
1525 } | |
1526 | |
1527 | |
1528 typedef struct { | |
1529 u_char size[4]; | |
1530 u_char name[4]; | |
1531 u_char version[1]; | |
1532 u_char flags[3]; | |
1533 u_char creation_time[4]; | |
1534 u_char modification_time[4]; | |
1535 u_char timescale[4]; | |
1536 u_char duration[4]; | |
1537 u_char language[2]; | |
1538 u_char quality[2]; | |
1539 } ngx_mp4_mdhd_atom_t; | |
1540 | |
1541 typedef struct { | |
1542 u_char size[4]; | |
1543 u_char name[4]; | |
1544 u_char version[1]; | |
1545 u_char flags[3]; | |
1546 u_char creation_time[8]; | |
1547 u_char modification_time[8]; | |
1548 u_char timescale[4]; | |
1549 u_char duration[8]; | |
1550 u_char language[2]; | |
1551 u_char quality[2]; | |
1552 } ngx_mp4_mdhd64_atom_t; | |
1553 | |
1554 | |
1555 static ngx_int_t | |
1556 ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1557 { | |
1558 u_char *atom_header; | |
1559 size_t atom_size; | |
1560 uint32_t timescale; | |
5543
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1561 uint64_t duration, start_time; |
4085 | 1562 ngx_buf_t *atom; |
1563 ngx_http_mp4_trak_t *trak; | |
1564 ngx_mp4_mdhd_atom_t *mdhd_atom; | |
1565 ngx_mp4_mdhd64_atom_t *mdhd64_atom; | |
1566 | |
1567 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 mdhd atom"); | |
1568 | |
1569 atom_header = ngx_mp4_atom_header(mp4); | |
1570 mdhd_atom = (ngx_mp4_mdhd_atom_t *) atom_header; | |
1571 mdhd64_atom = (ngx_mp4_mdhd64_atom_t *) atom_header; | |
1572 ngx_mp4_set_atom_name(mdhd_atom, 'm', 'd', 'h', 'd'); | |
1573 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1574 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
|
1575 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1576 "\"%s\" mp4 mdhd atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1577 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1578 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1579 |
4085 | 1580 if (mdhd_atom->version[0] == 0) { |
1581 /* version 0: everything is 32-bit */ | |
1582 timescale = ngx_mp4_get_32value(mdhd_atom->timescale); | |
1583 duration = ngx_mp4_get_32value(mdhd_atom->duration); | |
1584 | |
1585 } else { | |
1586 /* version 1: 64-bit duration and 32-bit timescale */ | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1587 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1588 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
|
1589 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1590 "\"%s\" mp4 mdhd atom too small", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1591 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1592 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1593 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1594 |
4085 | 1595 timescale = ngx_mp4_get_32value(mdhd64_atom->timescale); |
1596 duration = ngx_mp4_get_64value(mdhd64_atom->duration); | |
1597 } | |
1598 | |
1599 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1600 "mdhd timescale:%uD, duration:%uL, time:%.3fs", | |
1601 timescale, duration, (double) duration / timescale); | |
1602 | |
5543
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1603 start_time = (uint64_t) mp4->start * timescale / 1000; |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1604 |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1605 if (duration < start_time) { |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1606 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1607 "mdhd duration is less than start time"); |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1608 return NGX_DECLINED; |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1609 } |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1610 |
5730c0193842
Mp4: skip tracks shorter than seek position (ticket #414).
Roman Arutyunyan <arut@nginx.com>
parents:
5542
diff
changeset
|
1611 duration -= start_time; |
4085 | 1612 |
1613 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1614 "mdhd new duration:%uL, time:%.3fs", | |
1615 duration, (double) duration / timescale); | |
1616 | |
1617 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1618 | |
1619 trak = ngx_mp4_last_trak(mp4); | |
1620 trak->mdhd_size = atom_size; | |
1621 trak->timescale = timescale; | |
1622 | |
1623 ngx_mp4_set_32value(mdhd_atom->size, atom_size); | |
1624 | |
1625 if (mdhd_atom->version[0] == 0) { | |
1626 ngx_mp4_set_32value(mdhd_atom->duration, duration); | |
1627 | |
1628 } else { | |
1629 ngx_mp4_set_64value(mdhd64_atom->duration, duration); | |
1630 } | |
1631 | |
1632 atom = &trak->mdhd_atom_buf; | |
1633 atom->temporary = 1; | |
1634 atom->pos = atom_header; | |
1635 atom->last = atom_header + atom_size; | |
1636 | |
1637 trak->out[NGX_HTTP_MP4_MDHD_ATOM].buf = atom; | |
1638 | |
1639 ngx_mp4_atom_next(mp4, atom_data_size); | |
1640 | |
1641 return NGX_OK; | |
1642 } | |
1643 | |
1644 | |
1645 static ngx_int_t | |
1646 ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1647 { | |
1648 u_char *atom_header; | |
1649 size_t atom_size; | |
1650 ngx_buf_t *atom; | |
1651 ngx_http_mp4_trak_t *trak; | |
1652 | |
1653 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 hdlr atom"); | |
1654 | |
1655 atom_header = ngx_mp4_atom_header(mp4); | |
1656 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1657 ngx_mp4_set_32value(atom_header, atom_size); | |
1658 ngx_mp4_set_atom_name(atom_header, 'h', 'd', 'l', 'r'); | |
1659 | |
1660 trak = ngx_mp4_last_trak(mp4); | |
1661 | |
1662 atom = &trak->hdlr_atom_buf; | |
1663 atom->temporary = 1; | |
1664 atom->pos = atom_header; | |
1665 atom->last = atom_header + atom_size; | |
1666 | |
1667 trak->hdlr_size = atom_size; | |
1668 trak->out[NGX_HTTP_MP4_HDLR_ATOM].buf = atom; | |
1669 | |
1670 ngx_mp4_atom_next(mp4, atom_data_size); | |
1671 | |
1672 return NGX_OK; | |
1673 } | |
1674 | |
1675 | |
1676 static ngx_int_t | |
1677 ngx_http_mp4_read_minf_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1678 { | |
1679 u_char *atom_header; | |
1680 ngx_buf_t *atom; | |
1681 ngx_http_mp4_trak_t *trak; | |
1682 | |
1683 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "process minf atom"); | |
1684 | |
1685 atom_header = ngx_mp4_atom_header(mp4); | |
1686 ngx_mp4_set_atom_name(atom_header, 'm', 'i', 'n', 'f'); | |
1687 | |
1688 trak = ngx_mp4_last_trak(mp4); | |
1689 | |
1690 atom = &trak->minf_atom_buf; | |
1691 atom->temporary = 1; | |
1692 atom->pos = atom_header; | |
1693 atom->last = atom_header + sizeof(ngx_mp4_atom_header_t); | |
1694 | |
1695 trak->out[NGX_HTTP_MP4_MINF_ATOM].buf = atom; | |
1696 | |
1697 return ngx_http_mp4_read_atom(mp4, ngx_http_mp4_minf_atoms, atom_data_size); | |
1698 } | |
1699 | |
1700 | |
1701 static void | |
1702 ngx_http_mp4_update_minf_atom(ngx_http_mp4_file_t *mp4, | |
1703 ngx_http_mp4_trak_t *trak) | |
1704 { | |
1705 ngx_buf_t *atom; | |
1706 | |
1707 trak->size += sizeof(ngx_mp4_atom_header_t) | |
1708 + trak->vmhd_size | |
1709 + trak->smhd_size | |
1710 + trak->dinf_size; | |
1711 atom = &trak->minf_atom_buf; | |
1712 ngx_mp4_set_32value(atom->pos, trak->size); | |
1713 } | |
1714 | |
1715 | |
1716 static ngx_int_t | |
1717 ngx_http_mp4_read_vmhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1718 { | |
1719 u_char *atom_header; | |
1720 size_t atom_size; | |
1721 ngx_buf_t *atom; | |
1722 ngx_http_mp4_trak_t *trak; | |
1723 | |
1724 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 vmhd atom"); | |
1725 | |
1726 atom_header = ngx_mp4_atom_header(mp4); | |
1727 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1728 ngx_mp4_set_32value(atom_header, atom_size); | |
1729 ngx_mp4_set_atom_name(atom_header, 'v', 'm', 'h', 'd'); | |
1730 | |
1731 trak = ngx_mp4_last_trak(mp4); | |
1732 | |
1733 atom = &trak->vmhd_atom_buf; | |
1734 atom->temporary = 1; | |
1735 atom->pos = atom_header; | |
1736 atom->last = atom_header + atom_size; | |
1737 | |
1738 trak->vmhd_size += atom_size; | |
1739 trak->out[NGX_HTTP_MP4_VMHD_ATOM].buf = atom; | |
1740 | |
1741 ngx_mp4_atom_next(mp4, atom_data_size); | |
1742 | |
1743 return NGX_OK; | |
1744 } | |
1745 | |
1746 | |
1747 static ngx_int_t | |
1748 ngx_http_mp4_read_smhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1749 { | |
1750 u_char *atom_header; | |
1751 size_t atom_size; | |
1752 ngx_buf_t *atom; | |
1753 ngx_http_mp4_trak_t *trak; | |
1754 | |
1755 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 smhd atom"); | |
1756 | |
1757 atom_header = ngx_mp4_atom_header(mp4); | |
1758 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1759 ngx_mp4_set_32value(atom_header, atom_size); | |
1760 ngx_mp4_set_atom_name(atom_header, 's', 'm', 'h', 'd'); | |
1761 | |
1762 trak = ngx_mp4_last_trak(mp4); | |
1763 | |
1764 atom = &trak->smhd_atom_buf; | |
1765 atom->temporary = 1; | |
1766 atom->pos = atom_header; | |
1767 atom->last = atom_header + atom_size; | |
1768 | |
1769 trak->vmhd_size += atom_size; | |
1770 trak->out[NGX_HTTP_MP4_SMHD_ATOM].buf = atom; | |
1771 | |
1772 ngx_mp4_atom_next(mp4, atom_data_size); | |
1773 | |
1774 return NGX_OK; | |
1775 } | |
1776 | |
1777 | |
1778 static ngx_int_t | |
1779 ngx_http_mp4_read_dinf_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1780 { | |
1781 u_char *atom_header; | |
1782 size_t atom_size; | |
1783 ngx_buf_t *atom; | |
1784 ngx_http_mp4_trak_t *trak; | |
1785 | |
1786 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 dinf atom"); | |
1787 | |
1788 atom_header = ngx_mp4_atom_header(mp4); | |
1789 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1790 ngx_mp4_set_32value(atom_header, atom_size); | |
1791 ngx_mp4_set_atom_name(atom_header, 'd', 'i', 'n', 'f'); | |
1792 | |
1793 trak = ngx_mp4_last_trak(mp4); | |
1794 | |
1795 atom = &trak->dinf_atom_buf; | |
1796 atom->temporary = 1; | |
1797 atom->pos = atom_header; | |
1798 atom->last = atom_header + atom_size; | |
1799 | |
1800 trak->dinf_size += atom_size; | |
1801 trak->out[NGX_HTTP_MP4_DINF_ATOM].buf = atom; | |
1802 | |
1803 ngx_mp4_atom_next(mp4, atom_data_size); | |
1804 | |
1805 return NGX_OK; | |
1806 } | |
1807 | |
1808 | |
1809 static ngx_int_t | |
1810 ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1811 { | |
1812 u_char *atom_header; | |
1813 ngx_buf_t *atom; | |
1814 ngx_http_mp4_trak_t *trak; | |
1815 | |
1816 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "process stbl atom"); | |
1817 | |
1818 atom_header = ngx_mp4_atom_header(mp4); | |
1819 ngx_mp4_set_atom_name(atom_header, 's', 't', 'b', 'l'); | |
1820 | |
1821 trak = ngx_mp4_last_trak(mp4); | |
1822 | |
1823 atom = &trak->stbl_atom_buf; | |
1824 atom->temporary = 1; | |
1825 atom->pos = atom_header; | |
1826 atom->last = atom_header + sizeof(ngx_mp4_atom_header_t); | |
1827 | |
1828 trak->out[NGX_HTTP_MP4_STBL_ATOM].buf = atom; | |
1829 | |
1830 return ngx_http_mp4_read_atom(mp4, ngx_http_mp4_stbl_atoms, atom_data_size); | |
1831 } | |
1832 | |
1833 | |
1834 static void | |
1835 ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, | |
1836 ngx_http_mp4_trak_t *trak) | |
1837 { | |
1838 ngx_buf_t *atom; | |
1839 | |
1840 trak->size += sizeof(ngx_mp4_atom_header_t); | |
1841 atom = &trak->stbl_atom_buf; | |
1842 ngx_mp4_set_32value(atom->pos, trak->size); | |
1843 } | |
1844 | |
1845 | |
1846 typedef struct { | |
1847 u_char size[4]; | |
1848 u_char name[4]; | |
1849 u_char version[1]; | |
1850 u_char flags[3]; | |
1851 u_char entries[4]; | |
4099
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1852 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1853 u_char media_size[4]; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1854 u_char media_name[4]; |
4085 | 1855 } ngx_mp4_stsd_atom_t; |
1856 | |
1857 | |
1858 static ngx_int_t | |
1859 ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1860 { | |
1861 u_char *atom_header, *atom_table; | |
1862 size_t atom_size; | |
1863 ngx_buf_t *atom; | |
1864 ngx_mp4_stsd_atom_t *stsd_atom; | |
1865 ngx_http_mp4_trak_t *trak; | |
1866 | |
1867 /* sample description atom */ | |
1868 | |
1869 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stsd atom"); | |
1870 | |
1871 atom_header = ngx_mp4_atom_header(mp4); | |
1872 stsd_atom = (ngx_mp4_stsd_atom_t *) atom_header; | |
1873 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1874 atom_table = atom_header + atom_size; | |
1875 ngx_mp4_set_32value(stsd_atom->size, atom_size); | |
1876 ngx_mp4_set_atom_name(stsd_atom, 's', 't', 's', 'd'); | |
1877 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1878 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
|
1879 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
|
1880 "\"%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
|
1881 return NGX_ERROR; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1882 } |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1883 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1884 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
|
1885 "stsd entries:%uD, media:%*s", |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1886 ngx_mp4_get_32value(stsd_atom->entries), |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1887 4, stsd_atom->media_name); |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1888 |
4085 | 1889 trak = ngx_mp4_last_trak(mp4); |
1890 | |
1891 atom = &trak->stsd_atom_buf; | |
1892 atom->temporary = 1; | |
1893 atom->pos = atom_header; | |
1894 atom->last = atom_table; | |
1895 | |
1896 trak->out[NGX_HTTP_MP4_STSD_ATOM].buf = atom; | |
1897 trak->size += atom_size; | |
1898 | |
1899 ngx_mp4_atom_next(mp4, atom_data_size); | |
1900 | |
1901 return NGX_OK; | |
1902 } | |
1903 | |
1904 | |
1905 typedef struct { | |
1906 u_char size[4]; | |
1907 u_char name[4]; | |
1908 u_char version[1]; | |
1909 u_char flags[3]; | |
1910 u_char entries[4]; | |
1911 } ngx_mp4_stts_atom_t; | |
1912 | |
1913 typedef struct { | |
1914 u_char count[4]; | |
1915 u_char duration[4]; | |
1916 } ngx_mp4_stts_entry_t; | |
1917 | |
1918 | |
1919 static ngx_int_t | |
1920 ngx_http_mp4_read_stts_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1921 { | |
1922 u_char *atom_header, *atom_table, *atom_end; | |
1923 uint32_t entries; | |
1924 ngx_buf_t *atom, *data; | |
1925 ngx_mp4_stts_atom_t *stts_atom; | |
1926 ngx_http_mp4_trak_t *trak; | |
1927 | |
1928 /* time-to-sample atom */ | |
1929 | |
1930 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stts atom"); | |
1931 | |
1932 atom_header = ngx_mp4_atom_header(mp4); | |
1933 stts_atom = (ngx_mp4_stts_atom_t *) atom_header; | |
1934 ngx_mp4_set_atom_name(stts_atom, 's', 't', 't', 's'); | |
1935 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1936 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
|
1937 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1938 "\"%s\" mp4 stts atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1939 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1940 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1941 |
4085 | 1942 entries = ngx_mp4_get_32value(stts_atom->entries); |
1943 | |
1944 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 1945 "mp4 time-to-sample entries:%uD", entries); |
4085 | 1946 |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1947 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
|
1948 + entries * sizeof(ngx_mp4_stts_entry_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1949 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1950 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1951 "\"%s\" mp4 stts atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1952 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1953 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1954 |
4085 | 1955 atom_table = atom_header + sizeof(ngx_mp4_stts_atom_t); |
1956 atom_end = atom_table + entries * sizeof(ngx_mp4_stts_entry_t); | |
1957 | |
1958 trak = ngx_mp4_last_trak(mp4); | |
1959 trak->time_to_sample_entries = entries; | |
1960 | |
1961 atom = &trak->stts_atom_buf; | |
1962 atom->temporary = 1; | |
1963 atom->pos = atom_header; | |
1964 atom->last = atom_table; | |
1965 | |
1966 data = &trak->stts_data_buf; | |
1967 data->temporary = 1; | |
1968 data->pos = atom_table; | |
1969 data->last = atom_end; | |
1970 | |
1971 trak->out[NGX_HTTP_MP4_STTS_ATOM].buf = atom; | |
1972 trak->out[NGX_HTTP_MP4_STTS_DATA].buf = data; | |
1973 | |
1974 ngx_mp4_atom_next(mp4, atom_data_size); | |
1975 | |
1976 return NGX_OK; | |
1977 } | |
1978 | |
1979 | |
1980 static ngx_int_t | |
1981 ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, | |
1982 ngx_http_mp4_trak_t *trak) | |
1983 { | |
1984 size_t atom_size; | |
1985 uint32_t entries, count, duration; | |
1986 uint64_t start_time; | |
1987 ngx_buf_t *atom, *data; | |
1988 ngx_uint_t start_sample; | |
1989 ngx_mp4_stts_atom_t *stts_atom; | |
1990 ngx_mp4_stts_entry_t *entry, *end; | |
1991 | |
1992 /* | |
1993 * mdia.minf.stbl.stts updating requires trak->timescale | |
1994 * from mdia.mdhd atom which may reside after mdia.minf | |
1995 */ | |
1996 | |
1997 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1998 "mp4 stts atom update"); | |
1999 | |
2000 data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf; | |
2001 | |
2002 if (data == NULL) { | |
2003 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2004 "no mp4 stts atoms were found in \"%s\"", | |
2005 mp4->file.name.data); | |
2006 return NGX_ERROR; | |
2007 } | |
2008 | |
2009 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
|
2010 start_time = (uint64_t) mp4->start * trak->timescale / 1000; |
4085 | 2011 |
2012 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 2013 "time-to-sample start_time:%uL", start_time); |
4085 | 2014 |
2015 start_sample = 0; | |
2016 entry = (ngx_mp4_stts_entry_t *) data->pos; | |
2017 end = (ngx_mp4_stts_entry_t *) data->last; | |
2018 | |
2019 while (entry < end) { | |
2020 count = ngx_mp4_get_32value(entry->count); | |
2021 duration = ngx_mp4_get_32value(entry->duration); | |
2022 | |
2023 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2024 "count:%uD, duration:%uD", count, duration); | |
2025 | |
4306 | 2026 if (start_time < (uint64_t) count * duration) { |
4085 | 2027 start_sample += (ngx_uint_t) (start_time / duration); |
4578 | 2028 count -= (uint32_t) (start_time / duration); |
4085 | 2029 ngx_mp4_set_32value(entry->count, count); |
2030 goto found; | |
2031 } | |
2032 | |
2033 start_sample += count; | |
2034 start_time -= count * duration; | |
2035 entries--; | |
2036 entry++; | |
2037 } | |
2038 | |
2039 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
4094 | 2040 "start time is out mp4 stts samples in \"%s\"", |
4085 | 2041 mp4->file.name.data); |
2042 | |
2043 return NGX_ERROR; | |
2044 | |
2045 found: | |
2046 | |
2047 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2048 "start_sample:%ui, new count:%uD", start_sample, count); | |
2049 | |
2050 trak->start_sample = start_sample; | |
2051 | |
2052 data->pos = (u_char *) entry; | |
2053 atom_size = sizeof(ngx_mp4_stts_atom_t) + (data->last - data->pos); | |
2054 trak->size += atom_size; | |
2055 | |
2056 atom = trak->out[NGX_HTTP_MP4_STTS_ATOM].buf; | |
2057 stts_atom = (ngx_mp4_stts_atom_t *) atom->pos; | |
2058 ngx_mp4_set_32value(stts_atom->size, atom_size); | |
2059 ngx_mp4_set_32value(stts_atom->entries, entries); | |
2060 | |
2061 return NGX_OK; | |
2062 } | |
2063 | |
2064 | |
2065 typedef struct { | |
2066 u_char size[4]; | |
2067 u_char name[4]; | |
2068 u_char version[1]; | |
2069 u_char flags[3]; | |
2070 u_char entries[4]; | |
2071 } ngx_http_mp4_stss_atom_t; | |
2072 | |
2073 | |
2074 static ngx_int_t | |
2075 ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2076 { | |
2077 u_char *atom_header, *atom_table, *atom_end; | |
2078 uint32_t entries; | |
2079 ngx_buf_t *atom, *data; | |
2080 ngx_http_mp4_trak_t *trak; | |
2081 ngx_http_mp4_stss_atom_t *stss_atom; | |
2082 | |
2083 /* sync samples atom */ | |
2084 | |
2085 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stss atom"); | |
2086 | |
2087 atom_header = ngx_mp4_atom_header(mp4); | |
2088 stss_atom = (ngx_http_mp4_stss_atom_t *) atom_header; | |
2089 ngx_mp4_set_atom_name(stss_atom, 's', 't', 's', 's'); | |
2090 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2091 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
|
2092 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2093 "\"%s\" mp4 stss atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2094 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2095 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2096 |
4085 | 2097 entries = ngx_mp4_get_32value(stss_atom->entries); |
2098 | |
2099 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 2100 "sync sample entries:%uD", entries); |
4085 | 2101 |
2102 trak = ngx_mp4_last_trak(mp4); | |
2103 trak->sync_samples_entries = entries; | |
2104 | |
2105 atom_table = atom_header + sizeof(ngx_http_mp4_stss_atom_t); | |
2106 | |
2107 atom = &trak->stss_atom_buf; | |
2108 atom->temporary = 1; | |
2109 atom->pos = atom_header; | |
2110 atom->last = atom_table; | |
2111 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2112 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
|
2113 + entries * sizeof(uint32_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2114 { |
4085 | 2115 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
|
2116 "\"%s\" mp4 stss atom too small", mp4->file.name.data); |
4085 | 2117 return NGX_ERROR; |
2118 } | |
2119 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2120 atom_end = atom_table + entries * sizeof(uint32_t); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2121 |
4085 | 2122 data = &trak->stss_data_buf; |
2123 data->temporary = 1; | |
2124 data->pos = atom_table; | |
2125 data->last = atom_end; | |
2126 | |
2127 trak->out[NGX_HTTP_MP4_STSS_ATOM].buf = atom; | |
2128 trak->out[NGX_HTTP_MP4_STSS_DATA].buf = data; | |
2129 | |
2130 ngx_mp4_atom_next(mp4, atom_data_size); | |
2131 | |
2132 return NGX_OK; | |
2133 } | |
2134 | |
2135 | |
2136 static ngx_int_t | |
2137 ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, | |
2138 ngx_http_mp4_trak_t *trak) | |
2139 { | |
2140 size_t atom_size; | |
2141 uint32_t entries, sample, start_sample, *entry, *end; | |
2142 ngx_buf_t *atom, *data; | |
2143 ngx_http_mp4_stss_atom_t *stss_atom; | |
2144 | |
2145 /* | |
2146 * mdia.minf.stbl.stss updating requires trak->start_sample | |
2147 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2148 * atom which may reside after mdia.minf | |
2149 */ | |
2150 | |
2151 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2152 "mp4 stss atom update"); | |
2153 | |
2154 data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf; | |
2155 | |
2156 if (data == NULL) { | |
2157 return NGX_OK; | |
2158 } | |
2159 | |
2160 /* sync samples starts from 1 */ | |
2161 start_sample = trak->start_sample + 1; | |
2162 entries = trak->sync_samples_entries; | |
2163 | |
2164 entry = (uint32_t *) data->pos; | |
2165 end = (uint32_t *) data->last; | |
2166 | |
2167 while (entry < end) { | |
2168 sample = ngx_mp4_get_32value(entry); | |
2169 | |
2170 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2171 "start:%uD, sync:%uD", start_sample, sample); | |
2172 | |
2173 if (sample >= start_sample) { | |
2174 goto found; | |
2175 } | |
2176 | |
2177 entries--; | |
2178 entry++; | |
2179 } | |
2180 | |
5542
847c308917af
Mp4: fix seeks after the last key frame.
Roman Arutyunyan <arut@nginx.com>
parents:
5496
diff
changeset
|
2181 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
|
2182 "start sample is out of mp4 stss atom"); |
4085 | 2183 |
2184 found: | |
2185 | |
2186 data->pos = (u_char *) entry; | |
2187 | |
2188 start_sample = trak->start_sample; | |
2189 | |
2190 while (entry < end) { | |
2191 sample = ngx_mp4_get_32value(entry); | |
2192 sample -= start_sample; | |
2193 ngx_mp4_set_32value(entry, sample); | |
2194 entry++; | |
2195 } | |
2196 | |
2197 atom_size = sizeof(ngx_http_mp4_stss_atom_t) + (data->last - data->pos); | |
2198 trak->size += atom_size; | |
2199 | |
2200 atom = trak->out[NGX_HTTP_MP4_STSS_ATOM].buf; | |
2201 stss_atom = (ngx_http_mp4_stss_atom_t *) atom->pos; | |
2202 | |
2203 ngx_mp4_set_32value(stss_atom->size, atom_size); | |
2204 ngx_mp4_set_32value(stss_atom->entries, entries); | |
2205 | |
2206 return NGX_OK; | |
2207 } | |
2208 | |
2209 | |
2210 typedef struct { | |
2211 u_char size[4]; | |
2212 u_char name[4]; | |
2213 u_char version[1]; | |
2214 u_char flags[3]; | |
2215 u_char entries[4]; | |
2216 } ngx_mp4_ctts_atom_t; | |
2217 | |
2218 typedef struct { | |
2219 u_char count[4]; | |
2220 u_char offset[4]; | |
2221 } ngx_mp4_ctts_entry_t; | |
2222 | |
2223 | |
2224 static ngx_int_t | |
2225 ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2226 { | |
2227 u_char *atom_header, *atom_table, *atom_end; | |
2228 uint32_t entries; | |
2229 ngx_buf_t *atom, *data; | |
2230 ngx_mp4_ctts_atom_t *ctts_atom; | |
2231 ngx_http_mp4_trak_t *trak; | |
2232 | |
2233 /* composition offsets atom */ | |
2234 | |
2235 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 ctts atom"); | |
2236 | |
2237 atom_header = ngx_mp4_atom_header(mp4); | |
2238 ctts_atom = (ngx_mp4_ctts_atom_t *) atom_header; | |
2239 ngx_mp4_set_atom_name(ctts_atom, 'c', 't', 't', 's'); | |
2240 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2241 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
|
2242 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2243 "\"%s\" mp4 ctts atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2244 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2245 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2246 |
4085 | 2247 entries = ngx_mp4_get_32value(ctts_atom->entries); |
2248 | |
2249 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 2250 "composition offset entries:%uD", entries); |
4085 | 2251 |
2252 trak = ngx_mp4_last_trak(mp4); | |
2253 trak->composition_offset_entries = entries; | |
2254 | |
2255 atom_table = atom_header + sizeof(ngx_mp4_ctts_atom_t); | |
2256 | |
2257 atom = &trak->ctts_atom_buf; | |
2258 atom->temporary = 1; | |
2259 atom->pos = atom_header; | |
2260 atom->last = atom_table; | |
2261 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2262 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
|
2263 + entries * sizeof(ngx_mp4_ctts_entry_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2264 { |
4085 | 2265 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
|
2266 "\"%s\" mp4 ctts atom too small", mp4->file.name.data); |
4085 | 2267 return NGX_ERROR; |
2268 } | |
2269 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2270 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
|
2271 |
4085 | 2272 data = &trak->ctts_data_buf; |
2273 data->temporary = 1; | |
2274 data->pos = atom_table; | |
2275 data->last = atom_end; | |
2276 | |
2277 trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = atom; | |
2278 trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = data; | |
2279 | |
2280 ngx_mp4_atom_next(mp4, atom_data_size); | |
2281 | |
2282 return NGX_OK; | |
2283 } | |
2284 | |
2285 | |
2286 static void | |
2287 ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4, | |
2288 ngx_http_mp4_trak_t *trak) | |
2289 { | |
2290 size_t atom_size; | |
2291 uint32_t entries, count, start_sample; | |
2292 ngx_buf_t *atom, *data; | |
2293 ngx_mp4_ctts_atom_t *ctts_atom; | |
2294 ngx_mp4_ctts_entry_t *entry, *end; | |
2295 | |
2296 /* | |
2297 * mdia.minf.stbl.ctts updating requires trak->start_sample | |
2298 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2299 * atom which may reside after mdia.minf | |
2300 */ | |
2301 | |
2302 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2303 "mp4 ctts atom update"); | |
2304 | |
2305 data = trak->out[NGX_HTTP_MP4_CTTS_DATA].buf; | |
2306 | |
2307 if (data == NULL) { | |
2308 return; | |
2309 } | |
2310 | |
2311 /* sync samples starts from 1 */ | |
2312 start_sample = trak->start_sample + 1; | |
2313 entries = trak->composition_offset_entries; | |
2314 entry = (ngx_mp4_ctts_entry_t *) data->pos; | |
2315 end = (ngx_mp4_ctts_entry_t *) data->last; | |
2316 | |
2317 while (entry < end) { | |
2318 count = ngx_mp4_get_32value(entry->count); | |
2319 | |
4088
8fe1da7b8386
bugfix of r4086: nginx could not be built without debug log.
Igor Sysoev <igor@sysoev.ru>
parents:
4087
diff
changeset
|
2320 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
4085 | 2321 "start:%uD, count:%uD, offset:%uD", |
2322 start_sample, count, ngx_mp4_get_32value(entry->offset)); | |
2323 | |
2324 if (start_sample <= count) { | |
2325 count -= (start_sample - 1); | |
2326 ngx_mp4_set_32value(entry->count, count); | |
2327 goto found; | |
2328 } | |
2329 | |
2330 start_sample -= count; | |
2331 entries--; | |
2332 entry++; | |
2333 } | |
2334 | |
2335 trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL; | |
2336 trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL; | |
2337 | |
2338 return; | |
2339 | |
2340 found: | |
2341 | |
2342 data->pos = (u_char *) entry; | |
2343 atom_size = sizeof(ngx_mp4_ctts_atom_t) + (data->last - data->pos); | |
2344 trak->size += atom_size; | |
2345 | |
2346 atom = trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf; | |
2347 ctts_atom = (ngx_mp4_ctts_atom_t *) atom->pos; | |
2348 | |
2349 ngx_mp4_set_32value(ctts_atom->size, atom_size); | |
2350 ngx_mp4_set_32value(ctts_atom->entries, entries); | |
2351 | |
2352 return; | |
2353 } | |
2354 | |
2355 | |
2356 typedef struct { | |
2357 u_char size[4]; | |
2358 u_char name[4]; | |
2359 u_char version[1]; | |
2360 u_char flags[3]; | |
2361 u_char entries[4]; | |
2362 } ngx_mp4_stsc_atom_t; | |
2363 | |
2364 | |
2365 static ngx_int_t | |
2366 ngx_http_mp4_read_stsc_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2367 { | |
2368 u_char *atom_header, *atom_table, *atom_end; | |
2369 uint32_t entries; | |
2370 ngx_buf_t *atom, *data; | |
2371 ngx_mp4_stsc_atom_t *stsc_atom; | |
2372 ngx_http_mp4_trak_t *trak; | |
2373 | |
2374 /* sample-to-chunk atom */ | |
2375 | |
2376 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stsc atom"); | |
2377 | |
2378 atom_header = ngx_mp4_atom_header(mp4); | |
2379 stsc_atom = (ngx_mp4_stsc_atom_t *) atom_header; | |
2380 ngx_mp4_set_atom_name(stsc_atom, 's', 't', 's', 'c'); | |
2381 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2382 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
|
2383 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2384 "\"%s\" mp4 stsc atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2385 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2386 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2387 |
4085 | 2388 entries = ngx_mp4_get_32value(stsc_atom->entries); |
2389 | |
2390 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 2391 "sample-to-chunk entries:%uD", entries); |
4085 | 2392 |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2393 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
|
2394 + entries * sizeof(ngx_mp4_stsc_entry_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2395 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2396 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2397 "\"%s\" mp4 stsc atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2398 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2399 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2400 |
4085 | 2401 atom_table = atom_header + sizeof(ngx_mp4_stsc_atom_t); |
2402 atom_end = atom_table + entries * sizeof(ngx_mp4_stsc_entry_t); | |
2403 | |
2404 trak = ngx_mp4_last_trak(mp4); | |
2405 trak->sample_to_chunk_entries = entries; | |
2406 | |
2407 atom = &trak->stsc_atom_buf; | |
2408 atom->temporary = 1; | |
2409 atom->pos = atom_header; | |
2410 atom->last = atom_table; | |
2411 | |
2412 data = &trak->stsc_data_buf; | |
2413 data->temporary = 1; | |
2414 data->pos = atom_table; | |
2415 data->last = atom_end; | |
2416 | |
2417 trak->out[NGX_HTTP_MP4_STSC_ATOM].buf = atom; | |
2418 trak->out[NGX_HTTP_MP4_STSC_DATA].buf = data; | |
2419 | |
2420 ngx_mp4_atom_next(mp4, atom_data_size); | |
2421 | |
2422 return NGX_OK; | |
2423 } | |
2424 | |
2425 | |
2426 static ngx_int_t | |
2427 ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4, | |
2428 ngx_http_mp4_trak_t *trak) | |
2429 { | |
2430 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
|
2431 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
|
2432 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
|
2433 ngx_buf_t *atom, *data, *buf; |
4085 | 2434 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
|
2435 ngx_mp4_stsc_entry_t *entry, *first, *end; |
4085 | 2436 |
2437 /* | |
2438 * mdia.minf.stbl.stsc updating requires trak->start_sample | |
2439 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2440 * atom which may reside after mdia.minf | |
2441 */ | |
2442 | |
2443 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2444 "mp4 stsc atom update"); | |
2445 | |
2446 data = trak->out[NGX_HTTP_MP4_STSC_DATA].buf; | |
2447 | |
2448 if (data == NULL) { | |
2449 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2450 "no mp4 stsc atoms were found in \"%s\"", | |
2451 mp4->file.name.data); | |
2452 return NGX_ERROR; | |
2453 } | |
2454 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2455 if (trak->sample_to_chunk_entries == 0) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2456 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2457 "zero number of entries in stsc atom in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2458 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2459 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2460 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2461 |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2462 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
|
2463 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
|
2464 |
4085 | 2465 entry = (ngx_mp4_stsc_entry_t *) data->pos; |
2466 end = (ngx_mp4_stsc_entry_t *) data->last; | |
2467 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2468 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
|
2469 samples = ngx_mp4_get_32value(entry->samples); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2470 id = ngx_mp4_get_32value(entry->id); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2471 entry++; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2472 |
4085 | 2473 while (entry < end) { |
2474 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2475 next_chunk = 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
|
2476 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2477 ngx_log_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
|
2478 "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
|
2479 "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
|
2480 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
|
2481 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2482 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
|
2483 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2484 if (start_sample <= n) { |
4085 | 2485 goto found; |
2486 } | |
2487 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2488 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
|
2489 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2490 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
|
2491 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
|
2492 id = ngx_mp4_get_32value(entry->id); |
4085 | 2493 entries--; |
2494 entry++; | |
2495 } | |
2496 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2497 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
|
2498 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2499 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
|
2500 "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
|
2501 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
|
2502 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2503 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
|
2504 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2505 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
|
2506 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
|
2507 "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
|
2508 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
|
2509 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
|
2510 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2511 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2512 found: |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2513 |
4085 | 2514 entries++; |
2515 entry--; | |
2516 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2517 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
|
2518 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
|
2519 "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
|
2520 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
|
2521 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
|
2522 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2523 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2524 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
|
2525 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2526 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
|
2527 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
|
2528 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2529 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
|
2530 "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
|
2531 trak->start_chunk, trak->chunk_samples); |
4085 | 2532 |
2533 data->pos = (u_char *) entry; | |
2534 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
|
2535 |
4382
b4d54fa76853
Fixed mp4 if first entry in stsc was skipped (ticket #72).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4306
diff
changeset
|
2536 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
|
2537 |
4687
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2538 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
|
2539 |
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2540 /* 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
|
2541 |
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2542 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
|
2543 |
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2544 } 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
|
2545 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2546 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
|
2547 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
|
2548 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
|
2549 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
|
2550 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2551 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
|
2552 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
|
2553 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
|
2554 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
|
2555 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2556 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
|
2557 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2558 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
|
2559 |
4687
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2560 entries++; |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2561 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
|
2562 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2563 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2564 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
|
2565 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
|
2566 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
|
2567 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
|
2568 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2569 |
4085 | 2570 trak->size += atom_size; |
2571 | |
2572 atom = trak->out[NGX_HTTP_MP4_STSC_ATOM].buf; | |
2573 stsc_atom = (ngx_mp4_stsc_atom_t *) atom->pos; | |
2574 | |
2575 ngx_mp4_set_32value(stsc_atom->size, atom_size); | |
2576 ngx_mp4_set_32value(stsc_atom->entries, entries); | |
2577 | |
2578 return NGX_OK; | |
2579 } | |
2580 | |
2581 | |
2582 typedef struct { | |
2583 u_char size[4]; | |
2584 u_char name[4]; | |
2585 u_char version[1]; | |
2586 u_char flags[3]; | |
2587 u_char uniform_size[4]; | |
2588 u_char entries[4]; | |
2589 } ngx_mp4_stsz_atom_t; | |
2590 | |
2591 | |
2592 static ngx_int_t | |
2593 ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2594 { | |
2595 u_char *atom_header, *atom_table, *atom_end; | |
2596 size_t atom_size; | |
2597 uint32_t entries, size; | |
2598 ngx_buf_t *atom, *data; | |
2599 ngx_mp4_stsz_atom_t *stsz_atom; | |
2600 ngx_http_mp4_trak_t *trak; | |
2601 | |
2602 /* sample sizes atom */ | |
2603 | |
2604 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stsz atom"); | |
2605 | |
2606 atom_header = ngx_mp4_atom_header(mp4); | |
2607 stsz_atom = (ngx_mp4_stsz_atom_t *) atom_header; | |
2608 ngx_mp4_set_atom_name(stsz_atom, 's', 't', 's', 'z'); | |
2609 | |
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) > atom_data_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2611 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2612 "\"%s\" mp4 stsz atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2613 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2614 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2615 |
4085 | 2616 size = ngx_mp4_get_32value(stsz_atom->uniform_size); |
2617 entries = ngx_mp4_get_32value(stsz_atom->entries); | |
2618 | |
2619 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2620 "sample uniform size:%uD, entries:%uD", size, entries); | |
2621 | |
2622 trak = ngx_mp4_last_trak(mp4); | |
2623 trak->sample_sizes_entries = entries; | |
2624 | |
2625 atom_table = atom_header + sizeof(ngx_mp4_stsz_atom_t); | |
2626 | |
2627 atom = &trak->stsz_atom_buf; | |
2628 atom->temporary = 1; | |
2629 atom->pos = atom_header; | |
2630 atom->last = atom_table; | |
2631 | |
2632 trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf = atom; | |
2633 | |
2634 if (size == 0) { | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2635 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
|
2636 + entries * sizeof(uint32_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2637 { |
4085 | 2638 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
|
2639 "\"%s\" mp4 stsz atom too small", |
4085 | 2640 mp4->file.name.data); |
2641 return NGX_ERROR; | |
2642 } | |
2643 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2644 atom_end = atom_table + entries * sizeof(uint32_t); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2645 |
4085 | 2646 data = &trak->stsz_data_buf; |
2647 data->temporary = 1; | |
2648 data->pos = atom_table; | |
2649 data->last = atom_end; | |
2650 | |
2651 trak->out[NGX_HTTP_MP4_STSZ_DATA].buf = data; | |
2652 | |
2653 } else { | |
2654 /* 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
|
2655 /* TODO : chunk samples */ |
4085 | 2656 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; |
2657 ngx_mp4_set_32value(atom_header, atom_size); | |
2658 trak->size += atom_size; | |
2659 } | |
2660 | |
2661 ngx_mp4_atom_next(mp4, atom_data_size); | |
2662 | |
2663 return NGX_OK; | |
2664 } | |
2665 | |
2666 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2667 static ngx_int_t |
4085 | 2668 ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, |
2669 ngx_http_mp4_trak_t *trak) | |
2670 { | |
2671 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
|
2672 uint32_t *pos, *end; |
4085 | 2673 ngx_buf_t *atom, *data; |
2674 ngx_mp4_stsz_atom_t *stsz_atom; | |
2675 | |
2676 /* | |
2677 * mdia.minf.stbl.stsz updating requires trak->start_sample | |
2678 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2679 * atom which may reside after mdia.minf | |
2680 */ | |
2681 | |
2682 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2683 "mp4 stsz atom update"); | |
2684 | |
2685 data = trak->out[NGX_HTTP_MP4_STSZ_DATA].buf; | |
2686 | |
2687 if (data) { | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2688 if (trak->start_sample > trak->sample_sizes_entries) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2689 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2690 "start time is out mp4 stsz samples in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2691 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2692 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2693 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2694 |
4085 | 2695 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
|
2696 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
|
2697 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2698 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
|
2699 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
|
2700 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2701 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2702 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
4112 | 2703 "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
|
2704 |
4085 | 2705 atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos); |
2706 trak->size += atom_size; | |
2707 | |
2708 atom = trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf; | |
2709 stsz_atom = (ngx_mp4_stsz_atom_t *) atom->pos; | |
2710 | |
2711 ngx_mp4_set_32value(stsz_atom->size, atom_size); | |
2712 ngx_mp4_set_32value(stsz_atom->entries, | |
2713 trak->sample_sizes_entries - trak->start_sample); | |
2714 } | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2715 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2716 return NGX_OK; |
4085 | 2717 } |
2718 | |
2719 | |
2720 typedef struct { | |
2721 u_char size[4]; | |
2722 u_char name[4]; | |
2723 u_char version[1]; | |
2724 u_char flags[3]; | |
2725 u_char entries[4]; | |
2726 } ngx_mp4_stco_atom_t; | |
2727 | |
2728 | |
2729 static ngx_int_t | |
2730 ngx_http_mp4_read_stco_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2731 { | |
2732 u_char *atom_header, *atom_table, *atom_end; | |
2733 uint32_t entries; | |
2734 ngx_buf_t *atom, *data; | |
2735 ngx_mp4_stco_atom_t *stco_atom; | |
2736 ngx_http_mp4_trak_t *trak; | |
2737 | |
2738 /* chunk offsets atom */ | |
2739 | |
2740 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stco atom"); | |
2741 | |
2742 atom_header = ngx_mp4_atom_header(mp4); | |
2743 stco_atom = (ngx_mp4_stco_atom_t *) atom_header; | |
2744 ngx_mp4_set_atom_name(stco_atom, 's', 't', 'c', 'o'); | |
2745 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2746 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
|
2747 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2748 "\"%s\" mp4 stco atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2749 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2750 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2751 |
4085 | 2752 entries = ngx_mp4_get_32value(stco_atom->entries); |
2753 | |
2754 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); | |
2755 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2756 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
|
2757 + entries * sizeof(uint32_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2758 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2759 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2760 "\"%s\" mp4 stco atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2761 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2762 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2763 |
4085 | 2764 atom_table = atom_header + sizeof(ngx_mp4_stco_atom_t); |
2765 atom_end = atom_table + entries * sizeof(uint32_t); | |
2766 | |
2767 trak = ngx_mp4_last_trak(mp4); | |
2768 trak->chunks = entries; | |
2769 | |
4107 | 2770 atom = &trak->stco_atom_buf; |
4085 | 2771 atom->temporary = 1; |
2772 atom->pos = atom_header; | |
2773 atom->last = atom_table; | |
2774 | |
4107 | 2775 data = &trak->stco_data_buf; |
4085 | 2776 data->temporary = 1; |
2777 data->pos = atom_table; | |
2778 data->last = atom_end; | |
2779 | |
2780 trak->out[NGX_HTTP_MP4_STCO_ATOM].buf = atom; | |
2781 trak->out[NGX_HTTP_MP4_STCO_DATA].buf = data; | |
2782 | |
2783 ngx_mp4_atom_next(mp4, atom_data_size); | |
2784 | |
2785 return NGX_OK; | |
2786 } | |
2787 | |
2788 | |
2789 static ngx_int_t | |
2790 ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4, | |
2791 ngx_http_mp4_trak_t *trak) | |
2792 { | |
2793 size_t atom_size; | |
2794 ngx_buf_t *atom, *data; | |
2795 ngx_mp4_stco_atom_t *stco_atom; | |
2796 | |
2797 /* | |
2798 * mdia.minf.stbl.stco updating requires trak->start_chunk | |
2799 * from mdia.minf.stbl.stsc which depends on value from mdia.mdhd | |
2800 * atom which may reside after mdia.minf | |
2801 */ | |
2802 | |
2803 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2804 "mp4 stco atom update"); | |
2805 | |
2806 data = trak->out[NGX_HTTP_MP4_STCO_DATA].buf; | |
2807 | |
2808 if (data == NULL) { | |
2809 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2810 "no mp4 stco atoms were found in \"%s\"", | |
2811 mp4->file.name.data); | |
2812 return NGX_ERROR; | |
2813 } | |
2814 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2815 if (trak->start_chunk > trak->chunks) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2816 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2817 "start time is out mp4 stco chunks in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2818 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2819 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2820 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2821 |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2822 data->pos += trak->start_chunk * sizeof(uint32_t); |
4085 | 2823 atom_size = sizeof(ngx_mp4_stco_atom_t) + (data->last - data->pos); |
2824 trak->size += atom_size; | |
2825 | |
2826 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
|
2827 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
|
2828 ngx_mp4_set_32value(data->pos, trak->start_offset); |
4085 | 2829 |
2830 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2831 "start chunk offset:%uD", trak->start_offset); | |
2832 | |
2833 atom = trak->out[NGX_HTTP_MP4_STCO_ATOM].buf; | |
2834 stco_atom = (ngx_mp4_stco_atom_t *) atom->pos; | |
2835 | |
2836 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
|
2837 ngx_mp4_set_32value(stco_atom->entries, trak->chunks - trak->start_chunk); |
4085 | 2838 |
2839 return NGX_OK; | |
2840 } | |
2841 | |
2842 | |
2843 static void | |
2844 ngx_http_mp4_adjust_stco_atom(ngx_http_mp4_file_t *mp4, | |
2845 ngx_http_mp4_trak_t *trak, int32_t adjustment) | |
2846 { | |
2847 uint32_t offset, *entry, *end; | |
2848 ngx_buf_t *data; | |
2849 | |
2850 /* | |
2851 * moov.trak.mdia.minf.stbl.stco adjustment requires | |
2852 * minimal start offset of all traks and new moov atom size | |
2853 */ | |
2854 | |
2855 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2856 "mp4 stco atom adjustment"); | |
2857 | |
2858 data = trak->out[NGX_HTTP_MP4_STCO_DATA].buf; | |
2859 entry = (uint32_t *) data->pos; | |
2860 end = (uint32_t *) data->last; | |
2861 | |
2862 while (entry < end) { | |
2863 offset = ngx_mp4_get_32value(entry); | |
2864 offset += adjustment; | |
2865 ngx_mp4_set_32value(entry, offset); | |
2866 entry++; | |
2867 } | |
2868 } | |
2869 | |
2870 | |
4112 | 2871 typedef struct { |
2872 u_char size[4]; | |
2873 u_char name[4]; | |
2874 u_char version[1]; | |
2875 u_char flags[3]; | |
2876 u_char entries[4]; | |
2877 } ngx_mp4_co64_atom_t; | |
2878 | |
2879 | |
2880 static ngx_int_t | |
2881 ngx_http_mp4_read_co64_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2882 { | |
2883 u_char *atom_header, *atom_table, *atom_end; | |
2884 uint32_t entries; | |
2885 ngx_buf_t *atom, *data; | |
2886 ngx_mp4_co64_atom_t *co64_atom; | |
2887 ngx_http_mp4_trak_t *trak; | |
2888 | |
2889 /* chunk offsets atom */ | |
2890 | |
2891 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 co64 atom"); | |
2892 | |
2893 atom_header = ngx_mp4_atom_header(mp4); | |
2894 co64_atom = (ngx_mp4_co64_atom_t *) atom_header; | |
2895 ngx_mp4_set_atom_name(co64_atom, 'c', 'o', '6', '4'); | |
2896 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2897 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
|
2898 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2899 "\"%s\" mp4 co64 atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2900 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2901 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2902 |
4112 | 2903 entries = ngx_mp4_get_32value(co64_atom->entries); |
2904 | |
2905 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); | |
2906 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2907 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
|
2908 + entries * sizeof(uint64_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2909 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2910 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2911 "\"%s\" mp4 co64 atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2912 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2913 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2914 |
4112 | 2915 atom_table = atom_header + sizeof(ngx_mp4_co64_atom_t); |
2916 atom_end = atom_table + entries * sizeof(uint64_t); | |
2917 | |
2918 trak = ngx_mp4_last_trak(mp4); | |
2919 trak->chunks = entries; | |
2920 | |
2921 atom = &trak->co64_atom_buf; | |
2922 atom->temporary = 1; | |
2923 atom->pos = atom_header; | |
2924 atom->last = atom_table; | |
2925 | |
2926 data = &trak->co64_data_buf; | |
2927 data->temporary = 1; | |
2928 data->pos = atom_table; | |
2929 data->last = atom_end; | |
2930 | |
2931 trak->out[NGX_HTTP_MP4_CO64_ATOM].buf = atom; | |
2932 trak->out[NGX_HTTP_MP4_CO64_DATA].buf = data; | |
2933 | |
2934 ngx_mp4_atom_next(mp4, atom_data_size); | |
2935 | |
2936 return NGX_OK; | |
2937 } | |
2938 | |
2939 | |
2940 static ngx_int_t | |
2941 ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4, | |
2942 ngx_http_mp4_trak_t *trak) | |
2943 { | |
2944 size_t atom_size; | |
2945 ngx_buf_t *atom, *data; | |
2946 ngx_mp4_co64_atom_t *co64_atom; | |
2947 | |
2948 /* | |
2949 * mdia.minf.stbl.co64 updating requires trak->start_chunk | |
2950 * from mdia.minf.stbl.stsc which depends on value from mdia.mdhd | |
2951 * atom which may reside after mdia.minf | |
2952 */ | |
2953 | |
2954 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2955 "mp4 co64 atom update"); | |
2956 | |
2957 data = trak->out[NGX_HTTP_MP4_CO64_DATA].buf; | |
2958 | |
2959 if (data == NULL) { | |
2960 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2961 "no mp4 co64 atoms were found in \"%s\"", | |
2962 mp4->file.name.data); | |
2963 return NGX_ERROR; | |
2964 } | |
2965 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2966 if (trak->start_chunk > trak->chunks) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2967 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2968 "start time is out mp4 co64 chunks in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2969 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2970 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2971 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2972 |
4112 | 2973 data->pos += trak->start_chunk * sizeof(uint64_t); |
2974 atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos); | |
2975 trak->size += atom_size; | |
2976 | |
2977 trak->start_offset = ngx_mp4_get_64value(data->pos); | |
2978 trak->start_offset += trak->chunk_samples_size; | |
2979 ngx_mp4_set_64value(data->pos, trak->start_offset); | |
2980 | |
2981 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2982 "start chunk offset:%uL", trak->start_offset); | |
2983 | |
2984 atom = trak->out[NGX_HTTP_MP4_CO64_ATOM].buf; | |
2985 co64_atom = (ngx_mp4_co64_atom_t *) atom->pos; | |
2986 | |
2987 ngx_mp4_set_32value(co64_atom->size, atom_size); | |
2988 ngx_mp4_set_32value(co64_atom->entries, trak->chunks - trak->start_chunk); | |
2989 | |
2990 return NGX_OK; | |
2991 } | |
2992 | |
2993 | |
2994 static void | |
2995 ngx_http_mp4_adjust_co64_atom(ngx_http_mp4_file_t *mp4, | |
2996 ngx_http_mp4_trak_t *trak, off_t adjustment) | |
2997 { | |
2998 uint64_t offset, *entry, *end; | |
2999 ngx_buf_t *data; | |
3000 | |
3001 /* | |
3002 * moov.trak.mdia.minf.stbl.co64 adjustment requires | |
3003 * minimal start offset of all traks and new moov atom size | |
3004 */ | |
3005 | |
3006 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
3007 "mp4 co64 atom adjustment"); | |
3008 | |
3009 data = trak->out[NGX_HTTP_MP4_CO64_DATA].buf; | |
3010 entry = (uint64_t *) data->pos; | |
3011 end = (uint64_t *) data->last; | |
3012 | |
3013 while (entry < end) { | |
3014 offset = ngx_mp4_get_64value(entry); | |
3015 offset += adjustment; | |
3016 ngx_mp4_set_64value(entry, offset); | |
3017 entry++; | |
3018 } | |
3019 } | |
3020 | |
3021 | |
4085 | 3022 static char * |
3023 ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
3024 { | |
3025 ngx_http_core_loc_conf_t *clcf; | |
3026 | |
3027 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); | |
3028 clcf->handler = ngx_http_mp4_handler; | |
3029 | |
3030 return NGX_CONF_OK; | |
3031 } | |
3032 | |
3033 | |
3034 static void * | |
3035 ngx_http_mp4_create_conf(ngx_conf_t *cf) | |
3036 { | |
3037 ngx_http_mp4_conf_t *conf; | |
3038 | |
3039 conf = ngx_palloc(cf->pool, sizeof(ngx_http_mp4_conf_t)); | |
3040 if (conf == NULL) { | |
3041 return NULL; | |
3042 } | |
3043 | |
3044 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
|
3045 conf->max_buffer_size = NGX_CONF_UNSET_SIZE; |
4085 | 3046 |
3047 return conf; | |
3048 } | |
3049 | |
3050 | |
3051 static char * | |
3052 ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
3053 { | |
3054 ngx_http_mp4_conf_t *prev = parent; | |
3055 ngx_http_mp4_conf_t *conf = child; | |
3056 | |
3057 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
|
3058 ngx_conf_merge_size_value(conf->max_buffer_size, prev->max_buffer_size, |
4085 | 3059 10 * 1024 * 1024); |
3060 | |
3061 return NGX_CONF_OK; | |
3062 } |