/src/vlc/modules/demux/mp4/essetup.c
Line | Count | Source (jump to first uncovered line) |
1 | | /***************************************************************************** |
2 | | * essetup.h: es setup from stsd and extensions parsing |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2001-2004, 2010, 2014 VLC authors and VideoLAN |
5 | | * |
6 | | * Authors: Laurent Aimar <fenrir@via.ecp.fr> |
7 | | * |
8 | | * This program is free software; you can redistribute it and/or modify it |
9 | | * under the terms of the GNU Lesser General Public License as published by |
10 | | * the Free Software Foundation; either version 2.1 of the License, or |
11 | | * (at your option) any later version. |
12 | | * |
13 | | * This program is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public License |
19 | | * along with this program; if not, write to the Free Software Foundation, |
20 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
21 | | *****************************************************************************/ |
22 | | |
23 | | #ifdef HAVE_CONFIG_H |
24 | | # include "config.h" |
25 | | #endif |
26 | | |
27 | | #include <stdbit.h> |
28 | | |
29 | | #include "mp4.h" |
30 | | #include "avci.h" |
31 | | #include "../xiph.h" |
32 | | #include "../../packetizer/iso_color_tables.h" |
33 | | #include "../../packetizer/mpeg4systems.h" |
34 | | #include "qt_palette.h" |
35 | | |
36 | | #include <vlc_demux.h> |
37 | | #include <vlc_aout.h> |
38 | | #include <assert.h> |
39 | | |
40 | | |
41 | | static void CopyExtradata( const uint8_t *p_extra, size_t i_extra, |
42 | | es_format_t *fmt ) |
43 | 1.24k | { |
44 | 1.24k | if( i_extra > 0 && !fmt->i_extra ) |
45 | 1.20k | { |
46 | 1.20k | fmt->p_extra = malloc( i_extra ); |
47 | 1.20k | if( i_extra ) |
48 | 1.20k | { |
49 | 1.20k | fmt->i_extra = i_extra; |
50 | 1.20k | memcpy( fmt->p_extra, p_extra, i_extra ); |
51 | 1.20k | } |
52 | 1.20k | } |
53 | 1.24k | } |
54 | | |
55 | | static uint32_t GetSampleType( demux_t *p_demux, const MP4_Box_t *p_sample ) |
56 | 3.23k | { |
57 | 3.23k | const MP4_Box_t *p_frma; |
58 | 3.23k | if( ( p_frma = MP4_BoxGet( p_sample, "sinf/frma" ) ) && BOXDATA(p_frma) ) |
59 | 21 | { |
60 | 21 | msg_Warn( p_demux, "Original Format Box: %4.4s", (char *)&BOXDATA(p_frma)->i_type ); |
61 | 21 | return BOXDATA(p_frma)->i_type; |
62 | 21 | } |
63 | 3.20k | return p_sample->i_type; |
64 | 3.23k | } |
65 | | |
66 | | static void SetupGlobalExtensions( const MP4_Box_t *p_sample, |
67 | | es_format_t *p_fmt ) |
68 | 3.22k | { |
69 | 3.22k | if( !p_fmt->i_bitrate ) |
70 | 2.15k | { |
71 | 2.15k | const MP4_Box_t *p_btrt = MP4_BoxGet( p_sample, "btrt" ); |
72 | 2.15k | if( p_btrt && BOXDATA(p_btrt) ) |
73 | 27 | { |
74 | 27 | p_fmt->i_bitrate = BOXDATA(p_btrt)->i_avg_bitrate; |
75 | 27 | } |
76 | 2.15k | } |
77 | | |
78 | 3.22k | const MP4_Box_t *p_glbl = MP4_BoxGet( p_sample, "glbl" ); |
79 | 3.22k | if( p_glbl && p_glbl->data.p_binary && p_glbl->data.p_binary->p_blob ) |
80 | 9 | { |
81 | 9 | CopyExtradata( p_glbl->data.p_binary->p_blob, |
82 | 9 | p_glbl->data.p_binary->i_blob, p_fmt ); |
83 | 9 | } |
84 | 3.22k | } |
85 | | |
86 | | static void SetupESDS( demux_t *p_demux, const mp4_track_t *p_track, |
87 | | const MP4_descriptor_decoder_config_t *p_decconfig, |
88 | | es_format_t *p_fmt ) |
89 | 344 | { |
90 | | /* First update information based on i_objectTypeIndication */ |
91 | 344 | switch( p_decconfig->i_objectProfileIndication ) |
92 | 344 | { |
93 | | /* Private ID */ |
94 | 1 | case( 0xe0 ): /* NeroDigital: dvd subs */ |
95 | 1 | if( p_fmt->i_cat == SPU_ES ) |
96 | 0 | { |
97 | 0 | p_fmt->i_codec = VLC_CODEC_SPU; |
98 | 0 | if( p_track->i_width > 0 ) |
99 | 0 | p_fmt->subs.spu.i_original_frame_width = p_track->i_width; |
100 | 0 | if( p_track->i_height > 0 ) |
101 | 0 | p_fmt->subs.spu.i_original_frame_height = p_track->i_height; |
102 | 0 | } |
103 | 1 | break; |
104 | 1 | case( 0xe1 ): /* QCelp for 3gp */ |
105 | 1 | if( p_fmt->i_cat == AUDIO_ES ) |
106 | 1 | { |
107 | 1 | p_fmt->i_codec = VLC_CODEC_QCELP; |
108 | 1 | } |
109 | 1 | break; |
110 | | |
111 | | /* Fallback */ |
112 | 342 | default: |
113 | 342 | if( MPEG4_get_codec_by_ObjectType( p_decconfig->i_objectProfileIndication, |
114 | 342 | p_decconfig->p_decoder_specific_info, |
115 | 342 | p_decconfig->i_decoder_specific_info_len, |
116 | 342 | &p_fmt->i_codec, |
117 | 342 | &p_fmt->i_profile ) ) |
118 | 337 | break; |
119 | | /* Unknown entry, but don't touch i_fourcc */ |
120 | 5 | msg_Warn( p_demux, |
121 | 5 | "unknown objectProfileIndication(0x%x) (Track[ID 0x%x])", |
122 | 5 | p_decconfig->i_objectProfileIndication, |
123 | 5 | p_track->i_track_ID ); |
124 | 5 | return; |
125 | 344 | } |
126 | | |
127 | 339 | p_fmt->i_original_fourcc = 0; /* so we don't have MP4A as original fourcc */ |
128 | 339 | p_fmt->i_bitrate = p_decconfig->i_avg_bitrate; |
129 | | |
130 | 339 | CopyExtradata( p_decconfig->p_decoder_specific_info, |
131 | 339 | p_decconfig->i_decoder_specific_info_len, |
132 | 339 | p_fmt ); |
133 | | |
134 | 339 | if( p_fmt->i_codec == VLC_CODEC_SPU && |
135 | 339 | p_fmt->i_extra >= sizeof(p_fmt->subs.spu.palette) ) |
136 | 0 | { |
137 | 0 | for (size_t i = 0; i < ARRAY_SIZE(p_fmt->subs.spu.palette); i++) |
138 | 0 | { |
139 | 0 | p_fmt->subs.spu.palette[i] = GetDWBE((char*)p_fmt->p_extra + i * 4); |
140 | 0 | } |
141 | 0 | p_fmt->subs.spu.b_palette = true; |
142 | 0 | } |
143 | 339 | } |
144 | | |
145 | | static int SetupRTPReceptionHintTrack( demux_t *p_demux, const mp4_track_t *p_track, |
146 | | const MP4_Box_t *p_sample, es_format_t *p_fmt, |
147 | | track_config_t *params ) |
148 | 2 | { |
149 | 2 | const uint32_t i_sample_type = GetSampleType( p_demux, p_sample ); |
150 | 2 | p_fmt->i_original_fourcc = i_sample_type; |
151 | | |
152 | 2 | const MP4_Box_t *p_sdp = MP4_BoxGet( p_track->p_track, "udta/hnti/sdp " ); |
153 | 2 | if( !p_sdp ) |
154 | 2 | { |
155 | 2 | msg_Err(p_demux, "Required 'sdp '-box not found"); |
156 | 2 | return 0; |
157 | 2 | } |
158 | 0 | char *strtok_state; |
159 | 0 | char * pch = strtok_r(BOXDATA(p_sdp)->psz_text, " =\n", &strtok_state); /* media entry */ |
160 | 0 | if( pch && pch[0] != 'm' ) |
161 | 0 | { |
162 | 0 | msg_Err(p_demux, "No Media entry found in SDP:%s", pch); |
163 | 0 | return 0; |
164 | 0 | } |
165 | | |
166 | 0 | if( !( pch = strtok_r(NULL, " =\n", &strtok_state) ) ) /* media type */ |
167 | 0 | return 0; |
168 | | /* media type has already been checked */ |
169 | 0 | msg_Dbg(p_demux, "sdp: media type:%s", pch); |
170 | 0 | if( !( pch = strtok_r(NULL, " =\n", &strtok_state) ) ) /* port */ |
171 | 0 | return 0; |
172 | 0 | msg_Dbg(p_demux, "sdp: port:%s", pch); |
173 | 0 | if( !( pch = strtok_r(NULL, " =\n", &strtok_state) ) ) /* protocol */ |
174 | 0 | return 0; |
175 | 0 | msg_Dbg(p_demux, "sdp: protocol:%s", pch); |
176 | |
|
177 | 0 | if( !( pch = strtok_r(NULL, " =\n", &strtok_state) ) ) /* fmt */ |
178 | 0 | return 0; |
179 | | |
180 | 0 | bool codec_set = false; |
181 | | /* process rtp types until we get an attribute field or end of sdp */ |
182 | 0 | while( pch && pch[0] != 'a' ) |
183 | 0 | { |
184 | 0 | int rtp_payload = atoi(pch); |
185 | 0 | msg_Dbg(p_demux, "sdp: payload type:%d", rtp_payload); |
186 | |
|
187 | 0 | if( !codec_set ) |
188 | 0 | { |
189 | | /* Payload types 34 and under have a set type and can be identified here */ |
190 | 0 | switch( rtp_payload ) |
191 | 0 | { |
192 | 0 | case 3: |
193 | 0 | p_fmt->i_codec = VLC_CODEC_GSM; |
194 | 0 | codec_set = true; |
195 | 0 | break; |
196 | 0 | default: |
197 | 0 | break; |
198 | 0 | } |
199 | 0 | } |
200 | 0 | pch = strtok_r(NULL, " =\n", &strtok_state); /* attribute or additional payload type */ |
201 | 0 | if( !pch && !codec_set ) |
202 | 0 | return 0; |
203 | 0 | } |
204 | | |
205 | 0 | while( pch && pch[0] == 'a' ) |
206 | 0 | { |
207 | 0 | if( !( pch = strtok_r(NULL, " :=\n", &strtok_state) ) ) /* attribute type */ |
208 | 0 | return 0; |
209 | 0 | msg_Dbg(p_demux, "sdp: attribute type:%s", pch); |
210 | |
|
211 | 0 | if( !strcmp(pch, "rtpmap") ) |
212 | 0 | { |
213 | 0 | if( !( pch = strtok_r(NULL, " :=\n", &strtok_state) ) ) /* payload type */ |
214 | 0 | return 0; |
215 | 0 | msg_Dbg(p_demux, "sdp: payload type:%s", pch); |
216 | 0 | if( !(pch = strtok_r(NULL, " /:=\n", &strtok_state) ) ) /* encoding name */ |
217 | 0 | return 0; |
218 | 0 | msg_Dbg(p_demux, "sdp: encoding name:%s", pch); |
219 | | |
220 | | /* Simply adding codec recognition should work for most codecs */ |
221 | | /* Codecs using slices need their picture constructed from sample */ |
222 | 0 | if( !strcmp(pch, "H264") ) |
223 | 0 | { |
224 | 0 | p_fmt->i_codec = VLC_CODEC_H264; |
225 | | /* ******* sending AnnexB ! */ |
226 | 0 | p_fmt->b_packetized = false; |
227 | 0 | } |
228 | 0 | else if( !strcmp(pch, "GSM") ) |
229 | 0 | { |
230 | 0 | p_fmt->i_codec = VLC_CODEC_GSM; |
231 | 0 | } |
232 | 0 | else if( !strcmp(pch, "Speex") ) |
233 | 0 | { |
234 | 0 | p_fmt->i_codec = VLC_CODEC_SPEEX; |
235 | 0 | } |
236 | 0 | else if( !codec_set ) |
237 | 0 | { |
238 | 0 | msg_Err(p_demux, "Support for codec contained in RTP \ |
239 | 0 | Reception Hint Track RTP stream has not been added"); |
240 | 0 | return 0; |
241 | 0 | } |
242 | | |
243 | 0 | if( !( pch = strtok_r(NULL, " :=\n", &strtok_state) ) ) /* clock rate */ |
244 | 0 | return 0; |
245 | 0 | int clock_rate = atoi(pch); |
246 | 0 | msg_Dbg(p_demux, "sdp clock rate:%d", clock_rate); |
247 | 0 | if( p_fmt->i_cat == AUDIO_ES ) |
248 | 0 | p_fmt->audio.i_rate = clock_rate; |
249 | 0 | } |
250 | 0 | pch = strtok_r(NULL, " =\n", &strtok_state); /* next attribute */ |
251 | 0 | } |
252 | | |
253 | 0 | const MP4_Box_t *p_tims = MP4_BoxGet(p_sample, "tims"); |
254 | 0 | if( p_tims && BOXDATA(p_tims) && BOXDATA(p_tims)->i_timescale ) |
255 | 0 | { |
256 | 0 | params->i_timescale_override = BOXDATA(p_tims)->i_timescale; |
257 | 0 | } |
258 | 0 | else |
259 | 0 | { |
260 | 0 | msg_Warn(p_demux, "Missing mandatory box tims"); |
261 | 0 | return 0; |
262 | 0 | } |
263 | | #if 0 |
264 | | const MP4_Box_t *p_tssy = MP4_BoxGet(p_sample, "tssy"); |
265 | | if( p_tssy && BOXDATA(p_tssy) ) |
266 | | { |
267 | | /* take the 2 last bits which indicate the synchronization mode */ |
268 | | params->sync_mode = (RTP_timstamp_synchronization_t) |
269 | | BOXDATA(p_tssy)->i_reserved_timestamp_sync & 0x03; |
270 | | } |
271 | | |
272 | | const MP4_Box_t *p_tsro = MP4_BoxGet(p_sample, "tsro"); |
273 | | if( p_tsro && BOXDATA(p_tsro) ) |
274 | | params->i_tsro_offset = BOXDATA(p_tsro)->i_offset; |
275 | | else |
276 | | msg_Dbg(p_demux, "No tsro box present"); |
277 | | msg_Dbg(p_demux, "setting tsro: %" PRId32, p_track->i_tsro_offset); |
278 | | #endif |
279 | 0 | return 1; |
280 | 0 | } |
281 | | |
282 | | |
283 | | int SetupVideoES( demux_t *p_demux, const mp4_track_t *p_track, const MP4_Box_t *p_sample, |
284 | | es_format_t *p_fmt, track_config_t *p_cfg ) |
285 | 1.47k | { |
286 | 1.47k | track_config_t trackparams, *params = &trackparams; |
287 | | |
288 | 1.47k | const MP4_Box_data_sample_vide_t *p_vide = p_sample->data.p_sample_vide; |
289 | 1.47k | if(!p_vide) |
290 | 0 | return 0; |
291 | | |
292 | 1.47k | const uint32_t i_sample_type = GetSampleType( p_demux, p_sample ); |
293 | | |
294 | 1.47k | p_fmt->video.i_width = p_vide->i_width; |
295 | 1.47k | p_fmt->video.i_height = p_vide->i_height; |
296 | | |
297 | | /* fall on display size */ |
298 | 1.47k | if( p_fmt->video.i_width <= 0 ) |
299 | 24 | p_fmt->video.i_width = p_track->i_width; |
300 | 1.47k | if( p_fmt->video.i_height <= 0 ) |
301 | 38 | p_fmt->video.i_height = p_track->i_height; |
302 | | |
303 | | /* Find out apect ratio from display size */ |
304 | 1.47k | if( p_track->i_width > 0 && p_track->i_height > 0 && |
305 | | /* Work-around buggy muxed files */ |
306 | 1.47k | p_vide->i_width != p_track->i_width ) |
307 | 329 | { |
308 | 329 | p_fmt->video.i_sar_num = p_track->i_width * p_fmt->video.i_height; |
309 | 329 | p_fmt->video.i_sar_den = p_track->i_height * p_fmt->video.i_width; |
310 | 329 | } |
311 | | |
312 | | /* Support for cropping (eg. in H263 files) */ |
313 | 1.47k | p_fmt->video.i_visible_width = p_fmt->video.i_width; |
314 | 1.47k | p_fmt->video.i_visible_height = p_fmt->video.i_height; |
315 | | |
316 | | /* Rotation */ |
317 | 1.47k | switch( (int)p_track->f_rotation ) { |
318 | 70 | case 90: |
319 | 70 | p_fmt->video.orientation = ORIENT_ROTATED_90; |
320 | 70 | break; |
321 | 29 | case 180: |
322 | 29 | if (p_track->i_flip == 1) { |
323 | 26 | p_fmt->video.orientation = ORIENT_VFLIPPED; |
324 | 26 | } else { |
325 | 3 | p_fmt->video.orientation = ORIENT_ROTATED_180; |
326 | 3 | } |
327 | 29 | break; |
328 | 6 | case 270: |
329 | 6 | p_fmt->video.orientation = ORIENT_ROTATED_270; |
330 | 6 | break; |
331 | 1.47k | } |
332 | | |
333 | | /* Flip, unless already flipped */ |
334 | 1.47k | if (p_track->i_flip == 1 && (int)p_track->f_rotation != 180) { |
335 | 80 | video_transform_t transform = (video_transform_t)p_fmt->video.orientation; |
336 | | /* Flip first then rotate */ |
337 | 80 | p_fmt->video.orientation = ORIENT_HFLIPPED; |
338 | 80 | video_format_TransformBy(&p_fmt->video, transform); |
339 | 80 | } |
340 | | |
341 | | /* Set 360 video mode */ |
342 | 1.47k | p_fmt->video.projection_mode = PROJECTION_MODE_RECTANGULAR; |
343 | 1.47k | const MP4_Box_t *p_uuid = MP4_BoxGet( p_track->p_track, "uuid" ); |
344 | 1.47k | for( ; p_uuid; p_uuid = p_uuid->p_next) |
345 | 0 | { |
346 | 0 | if( p_uuid->i_type == ATOM_uuid |
347 | 0 | && !CmpUUID( &p_uuid->i_uuid, &XML360BoxUUID ) |
348 | 0 | && p_uuid->data.p_360 ) |
349 | 0 | { |
350 | 0 | p_fmt->video.projection_mode = p_uuid->data.p_360->i_projection_mode; |
351 | 0 | switch (p_uuid->data.p_360->e_stereo_mode) |
352 | 0 | { |
353 | 0 | case XML360_STEREOSCOPIC_TOP_BOTTOM: |
354 | 0 | p_fmt->video.multiview_mode = MULTIVIEW_STEREO_TB; |
355 | 0 | break; |
356 | 0 | case XML360_STEREOSCOPIC_LEFT_RIGHT: |
357 | 0 | p_fmt->video.multiview_mode = MULTIVIEW_STEREO_SBS; |
358 | 0 | break; |
359 | 0 | default: |
360 | 0 | p_fmt->video.multiview_mode = MULTIVIEW_2D; |
361 | 0 | break; |
362 | 0 | } |
363 | 0 | } |
364 | 0 | } |
365 | | |
366 | 1.47k | const MP4_Box_t *p_st3d = MP4_BoxGet( p_sample, "st3d" ); |
367 | 1.47k | if (p_st3d && BOXDATA(p_st3d)) |
368 | 1 | { |
369 | 1 | switch( BOXDATA(p_st3d)->i_stereo_mode ) |
370 | 1 | { |
371 | 1 | case ST3D_MONOSCOPIC: |
372 | 1 | p_fmt->video.multiview_mode = MULTIVIEW_2D; |
373 | 1 | break; |
374 | 0 | case ST3D_STEREOSCOPIC_TOP_BOTTOM: |
375 | 0 | p_fmt->video.multiview_mode = MULTIVIEW_STEREO_TB; |
376 | 0 | break; |
377 | 0 | case ST3D_STEREOSCOPIC_LEFT_RIGHT: |
378 | 0 | p_fmt->video.multiview_mode = MULTIVIEW_STEREO_SBS; |
379 | 0 | break; |
380 | 0 | default: |
381 | 0 | msg_Warn( p_demux, "Unknown stereo mode %d", BOXDATA(p_st3d)->i_stereo_mode ); |
382 | 0 | break; |
383 | 1 | } |
384 | 1 | } |
385 | 1.47k | else |
386 | 1.47k | { |
387 | 1.47k | for( p_uuid = MP4_BoxGet( p_sample, "uuid" ); p_uuid; |
388 | 1.47k | p_uuid = p_uuid->p_next ) |
389 | 1 | { |
390 | 1 | if( p_uuid->i_type == ATOM_uuid && |
391 | 1 | !CmpUUID( &p_uuid->i_uuid, &PS3DDSBoxUUID ) && |
392 | 1 | p_uuid->data.p_binary && |
393 | 1 | p_uuid->data.p_binary->i_blob == 4 && |
394 | 1 | !memcmp( p_uuid->data.p_binary->p_blob, "\x82\x81\x10\x02", 4 ) ) |
395 | 0 | { |
396 | 0 | p_fmt->video.multiview_mode = MULTIVIEW_STEREO_FRAME; |
397 | 0 | break; |
398 | 0 | } |
399 | 1 | } |
400 | 1.47k | } |
401 | | |
402 | 1.47k | const MP4_Box_t *p_prhd = MP4_BoxGet( p_sample, "sv3d/proj/prhd" ); |
403 | 1.47k | if (p_prhd && BOXDATA(p_prhd)) |
404 | 1 | { |
405 | 1 | vlc_viewpoint_from_euler(&p_fmt->video.pose, |
406 | 1 | BOXDATA(p_prhd)->f_pose_yaw_degrees, |
407 | 1 | BOXDATA(p_prhd)->f_pose_pitch_degrees, |
408 | 1 | BOXDATA(p_prhd)->f_pose_roll_degrees); |
409 | 1 | } |
410 | | |
411 | 1.47k | const MP4_Box_t *p_equi = MP4_BoxGet( p_sample, "sv3d/proj/equi" ); |
412 | 1.47k | const MP4_Box_t *p_cbmp = MP4_BoxGet( p_sample, "sv3d/proj/cbmp" ); |
413 | 1.47k | if (p_equi && BOXDATA(p_equi)) |
414 | 1 | p_fmt->video.projection_mode = PROJECTION_MODE_EQUIRECTANGULAR; |
415 | 1.47k | else if (p_cbmp && BOXDATA(p_cbmp)) |
416 | 0 | p_fmt->video.projection_mode = PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD; |
417 | | |
418 | | /* It's a little ugly but .. there are special cases */ |
419 | 1.47k | switch( i_sample_type ) |
420 | 1.47k | { |
421 | 0 | case( VLC_FOURCC( 's', '2', '6', '3' ) ): |
422 | 0 | p_fmt->i_codec = VLC_CODEC_H263; |
423 | 0 | break; |
424 | 0 | case VLC_FOURCC('y','v','1','2'): |
425 | 0 | p_fmt->i_codec = VLC_CODEC_YV12; |
426 | 0 | break; |
427 | 0 | case VLC_FOURCC('y','u','v','2'): |
428 | 0 | p_fmt->i_codec = VLC_CODEC_YUV2; |
429 | 0 | break; |
430 | 0 | case VLC_FOURCC('A','B','G','R'): |
431 | 0 | p_fmt->i_codec = VLC_CODEC_ARGB; |
432 | 0 | break; |
433 | 0 | case VLC_FOURCC('2','4','B','G'): |
434 | 0 | p_fmt->i_codec = VLC_CODEC_BGR24; |
435 | 0 | break; |
436 | 0 | case VLC_FOURCC('r','a','w',' '): |
437 | 0 | switch( p_vide->i_depth ) { |
438 | 0 | case 16: |
439 | 0 | p_fmt->i_codec = VLC_CODEC_RGB555BE; |
440 | 0 | break; |
441 | 0 | case 24: |
442 | 0 | p_fmt->i_codec = VLC_CODEC_RGB24; |
443 | 0 | break; |
444 | 0 | case 32: |
445 | 0 | p_fmt->i_codec = VLC_CODEC_ARGB; |
446 | 0 | break; |
447 | 0 | case 32 + 8: |
448 | 0 | p_fmt->i_codec = VLC_CODEC_GREY; |
449 | 0 | break; |
450 | 0 | default: |
451 | 0 | msg_Dbg( p_demux, "Unrecognized raw video format (depth = %d)", |
452 | 0 | p_vide->i_depth ); |
453 | 0 | p_fmt->i_codec = i_sample_type; |
454 | 0 | break; |
455 | 0 | } |
456 | 0 | break; |
457 | 0 | case( VLC_FOURCC( 'r', 'r', 't', 'p' ) ): /* RTP Reception Hint Track */ |
458 | 0 | { |
459 | 0 | if( !SetupRTPReceptionHintTrack( p_demux, p_track, p_sample, p_fmt, params ) ) |
460 | 0 | p_fmt->i_codec = i_sample_type; |
461 | 0 | break; |
462 | 0 | } |
463 | 1.47k | default: |
464 | 1.47k | p_fmt->i_codec = i_sample_type; |
465 | 1.47k | break; |
466 | 1.47k | } |
467 | | |
468 | | |
469 | | /* Read extensions */ |
470 | | |
471 | 1.47k | const MP4_Box_t *p_clap = MP4_BoxGet( p_sample, "clap" ); |
472 | 1.47k | if( p_clap && BOXDATA(p_clap) && |
473 | 1.47k | BOXDATA(p_clap)->i_width + BOXDATA(p_clap)->i_x_offset <= p_fmt->video.i_width && |
474 | 1.47k | BOXDATA(p_clap)->i_height + BOXDATA(p_clap)->i_y_offset <= p_fmt->video.i_height ) |
475 | 6 | { |
476 | 6 | p_fmt->video.i_visible_width = BOXDATA(p_clap)->i_width; |
477 | 6 | p_fmt->video.i_visible_height = BOXDATA(p_clap)->i_height; |
478 | 6 | p_fmt->video.i_x_offset = BOXDATA(p_clap)->i_x_offset; |
479 | 6 | p_fmt->video.i_y_offset = BOXDATA(p_clap)->i_y_offset; |
480 | 6 | } |
481 | | |
482 | | /* Set up A/R from extension atom */ |
483 | 1.47k | const MP4_Box_t *p_pasp = MP4_BoxGet( p_sample, "pasp" ); |
484 | 1.47k | if( p_pasp && BOXDATA(p_pasp) && BOXDATA(p_pasp)->i_horizontal_spacing > 0 && |
485 | 1.47k | BOXDATA(p_pasp)->i_vertical_spacing > 0 ) |
486 | 63 | { |
487 | 63 | p_fmt->video.i_sar_num = BOXDATA(p_pasp)->i_horizontal_spacing; |
488 | 63 | p_fmt->video.i_sar_den = BOXDATA(p_pasp)->i_vertical_spacing; |
489 | 63 | } |
490 | | |
491 | 1.47k | const MP4_Box_t *p_fiel = MP4_BoxGet( p_sample, "fiel" ); |
492 | 1.47k | if( p_fiel && BOXDATA(p_fiel) ) |
493 | 16 | { |
494 | 16 | p_cfg->i_block_flags = BOXDATA(p_fiel)->i_flags; |
495 | 16 | } |
496 | | |
497 | 1.47k | const MP4_Box_t *p_colr = MP4_BoxGet( p_sample, "colr" ); |
498 | 1.47k | if ( p_colr != NULL ) |
499 | 118 | { |
500 | 118 | if ( BOXDATA(p_colr)->i_type == VLC_FOURCC( 'n', 'c', 'l', 'c' ) || |
501 | 118 | BOXDATA(p_colr)->i_type == VLC_FOURCC( 'n', 'c', 'l', 'x' ) ) |
502 | 108 | { |
503 | 108 | p_fmt->video.primaries = |
504 | 108 | iso_23001_8_cp_to_vlc_primaries( BOXDATA( p_colr )->nclc.i_primary_idx ); |
505 | 108 | p_fmt->video.transfer = |
506 | 108 | iso_23001_8_tc_to_vlc_xfer( BOXDATA( p_colr )->nclc.i_transfer_function_idx ); |
507 | 108 | p_fmt->video.space = |
508 | 108 | iso_23001_8_mc_to_vlc_coeffs( BOXDATA( p_colr )->nclc.i_matrix_idx ); |
509 | 108 | if ( BOXDATA(p_colr)->i_type == VLC_FOURCC( 'n', 'c', 'l', 'x' ) && |
510 | 108 | (BOXDATA(p_colr)->nclc.i_full_range >> 7) != 0 ) |
511 | 1 | p_fmt->video.color_range = COLOR_RANGE_FULL; |
512 | 107 | else |
513 | 107 | p_fmt->video.color_range = COLOR_RANGE_LIMITED; |
514 | 108 | } |
515 | 118 | } |
516 | | |
517 | 1.47k | const MP4_Box_t *p_dvcC = MP4_BoxGet( p_sample, "dvcC" ); |
518 | 1.47k | if( !p_dvcC ) |
519 | 1.47k | p_dvcC = MP4_BoxGet( p_sample, "dvvC" ); |
520 | 1.47k | if( !p_dvcC ) |
521 | 1.47k | p_dvcC = MP4_BoxGet( p_sample, "dvwC" ); |
522 | 1.47k | if( p_dvcC && BOXDATA(p_dvcC) ) |
523 | 3 | { |
524 | 3 | const MP4_Box_data_dvcC_t *p_data = BOXDATA( p_dvcC ); |
525 | 3 | p_fmt->video.dovi.version_major = p_data->i_version_major; |
526 | 3 | p_fmt->video.dovi.version_minor = p_data->i_version_minor; |
527 | 3 | p_fmt->video.dovi.profile = p_data->i_profile; |
528 | 3 | p_fmt->video.dovi.level = p_data->i_level; |
529 | 3 | p_fmt->video.dovi.rpu_present = p_data->i_rpu_present; |
530 | 3 | p_fmt->video.dovi.bl_present = p_data->i_bl_present; |
531 | 3 | p_fmt->video.dovi.el_present = p_data->i_el_present; |
532 | 3 | } |
533 | | |
534 | 1.47k | SetupGlobalExtensions( p_sample, p_fmt ); |
535 | | |
536 | | /* now see if esds is present and if so create a data packet |
537 | | with decoder_specific_info */ |
538 | 1.47k | MP4_Box_t *p_esds = MP4_BoxGet( p_sample, "esds" ); |
539 | 1.47k | if ( p_esds && BOXDATA(p_esds) && BOXDATA(p_esds)->es_descriptor.p_decConfigDescr ) |
540 | 0 | { |
541 | 0 | assert(i_sample_type == ATOM_mp4v); |
542 | 0 | SetupESDS( p_demux, p_track, BOXDATA(p_esds)->es_descriptor.p_decConfigDescr, p_fmt ); |
543 | 0 | } |
544 | 1.47k | else switch( i_sample_type ) |
545 | 1.47k | { |
546 | | /* qt decoder, send the complete chunk */ |
547 | 0 | case VLC_FOURCC ('h', 'd', 'v', '1'): // HDV 720p30 |
548 | 0 | case VLC_FOURCC ('h', 'd', 'v', '2'): // HDV 1080i60 |
549 | 0 | case VLC_FOURCC ('h', 'd', 'v', '3'): // HDV 1080i50 |
550 | 0 | case VLC_FOURCC ('h', 'd', 'v', '5'): // HDV 720p25 |
551 | 0 | case VLC_FOURCC ('m', 'x', '5', 'n'): // MPEG2 IMX NTSC 525/60 50mb/s produced by FCP |
552 | 0 | case VLC_FOURCC ('m', 'x', '5', 'p'): // MPEG2 IMX PAL 625/60 50mb/s produced by FCP |
553 | 0 | case VLC_FOURCC ('m', 'x', '4', 'n'): // MPEG2 IMX NTSC 525/60 40mb/s produced by FCP |
554 | 0 | case VLC_FOURCC ('m', 'x', '4', 'p'): // MPEG2 IMX PAL 625/60 40mb/s produced by FCP |
555 | 0 | case VLC_FOURCC ('m', 'x', '3', 'n'): // MPEG2 IMX NTSC 525/60 30mb/s produced by FCP |
556 | 0 | case VLC_FOURCC ('m', 'x', '3', 'p'): // MPEG2 IMX PAL 625/50 30mb/s produced by FCP |
557 | 0 | case VLC_FOURCC ('x', 'd', 'v', '2'): // XDCAM HD 1080i60 |
558 | 0 | case VLC_FOURCC ('A', 'V', 'm', 'p'): // AVID IMX PAL |
559 | 0 | p_fmt->i_codec = VLC_CODEC_MPGV; |
560 | 0 | break; |
561 | | /* qt decoder, send the complete chunk */ |
562 | 5 | case VLC_CODEC_SVQ1: |
563 | 6 | case VLC_CODEC_SVQ3: |
564 | 7 | case VLC_FOURCC( 'V', 'P', '3', '1' ): |
565 | 7 | case VLC_FOURCC( '3', 'I', 'V', '1' ): |
566 | 7 | case VLC_FOURCC( 'Z', 'y', 'G', 'o' ): |
567 | 7 | { |
568 | 7 | CopyExtradata( p_sample->data.p_sample_vide->p_qt_image_description, |
569 | 7 | p_sample->data.p_sample_vide->i_qt_image_description, |
570 | 7 | p_fmt ); |
571 | 7 | break; |
572 | 7 | } |
573 | | |
574 | 0 | case VLC_FOURCC( 'A', 'V', 'j', '2' ): |
575 | 0 | p_fmt->i_codec = VLC_CODEC_JPEG2000; |
576 | | /* final decoded resolution stored in ARES w, h, nbfields to group |
577 | | * but since avcodec can't tell... */ |
578 | 0 | break; |
579 | | |
580 | 0 | case VLC_FOURCC('j', 'p', 'e', 'g'): |
581 | 0 | p_fmt->i_codec = VLC_CODEC_MJPG; |
582 | 0 | break; |
583 | | |
584 | 0 | case VLC_CODEC_FFV1: |
585 | 0 | { |
586 | 0 | MP4_Box_t *p_binary = MP4_BoxGet( p_sample, "glbl" ); |
587 | 0 | if( p_binary && BOXDATA(p_binary) ) |
588 | 0 | { |
589 | 0 | CopyExtradata( BOXDATA(p_binary)->p_blob, |
590 | 0 | BOXDATA(p_binary)->i_blob, |
591 | 0 | p_fmt ); |
592 | 0 | } |
593 | 0 | break; |
594 | 7 | } |
595 | | |
596 | 57 | case VLC_FOURCC( 'v', 'c', '-', '1' ): |
597 | 57 | { |
598 | 57 | MP4_Box_t *p_dvc1 = MP4_BoxGet( p_sample, "dvc1" ); |
599 | 57 | if( p_dvc1 && BOXDATA(p_dvc1) ) |
600 | 53 | { |
601 | 53 | CopyExtradata( BOXDATA(p_dvc1)->p_vc1, |
602 | 53 | BOXDATA(p_dvc1)->i_vc1, |
603 | 53 | p_fmt ); |
604 | 53 | } |
605 | 4 | else |
606 | 4 | { |
607 | 4 | msg_Err( p_demux, "missing dvc1" ); |
608 | 4 | } |
609 | 57 | break; |
610 | 7 | } |
611 | | |
612 | 64 | case ATOM_av01: |
613 | 64 | { |
614 | 64 | static_assert(ATOM_av01 == VLC_CODEC_AV1, "VLC_CODEC_AV1 != ATOM_av01"); |
615 | 64 | MP4_Box_t *p_av1C = MP4_BoxGet( p_sample, "av1C" ); |
616 | 64 | if( p_av1C && BOXDATA(p_av1C) ) |
617 | 0 | { |
618 | 0 | p_fmt->i_profile = BOXDATA(p_av1C)->i_profile; |
619 | 0 | p_fmt->i_level = BOXDATA(p_av1C)->i_level; |
620 | 0 | CopyExtradata( BOXDATA(p_av1C)->p_av1C, |
621 | 0 | BOXDATA(p_av1C)->i_av1C, |
622 | 0 | p_fmt ); |
623 | 0 | if (p_fmt->i_extra <= 4) |
624 | 0 | p_fmt->b_packetized = false; // force full extradata by the packetizer |
625 | 0 | } |
626 | 64 | break; |
627 | 7 | } |
628 | | |
629 | 1 | case VLC_FOURCC( 'v', 'v', 'c', '1' ): |
630 | 1 | { |
631 | 1 | MP4_Box_t *p_vvcC = MP4_BoxGet( p_sample, "vvcC" ); |
632 | 1 | if( p_vvcC && p_vvcC->data.p_binary && |
633 | 1 | p_vvcC->data.p_binary->i_blob > 4 ) |
634 | 0 | { |
635 | 0 | CopyExtradata( ((uint8_t *)p_vvcC->data.p_binary->p_blob) + 4, |
636 | 0 | p_vvcC->data.p_binary->i_blob - 4, |
637 | 0 | p_fmt ); |
638 | 0 | } |
639 | 1 | break; |
640 | 7 | } |
641 | | |
642 | | /* avc1: send avcC (h264 without annexe B, ie without start code)*/ |
643 | 5 | case VLC_FOURCC( 'a', 'v', 'c', '3' ): |
644 | 682 | case VLC_FOURCC( 'a', 'v', 'c', '1' ): |
645 | 682 | case VLC_FOURCC( 'd', 'v', 'a', '1' ): /* DolbyVision */ |
646 | 682 | case VLC_FOURCC( 'd', 'v', 'a', 'v' ): /* DolbyVision */ |
647 | 682 | { |
648 | 682 | MP4_Box_t *p_avcC = MP4_BoxGet( p_sample, "avcC" ); |
649 | | |
650 | 682 | if( p_avcC && BOXDATA(p_avcC) ) |
651 | 632 | { |
652 | 632 | p_fmt->i_profile = BOXDATA(p_avcC)->i_profile; |
653 | 632 | p_fmt->i_level = BOXDATA(p_avcC)->i_level; |
654 | 632 | CopyExtradata( BOXDATA(p_avcC)->p_avcC, |
655 | 632 | BOXDATA(p_avcC)->i_avcC, |
656 | 632 | p_fmt ); |
657 | 632 | } |
658 | 50 | else |
659 | 50 | { |
660 | 50 | msg_Err( p_demux, "missing avcC" ); |
661 | 50 | } |
662 | 682 | break; |
663 | 682 | } |
664 | 1 | case VLC_FOURCC( 'h', 'v', 'c', '1' ): |
665 | 12 | case VLC_FOURCC( 'h', 'e', 'v', '1' ): |
666 | 12 | case VLC_FOURCC( 'd', 'v', 'h', 'e' ): /* DolbyVision */ |
667 | 12 | case VLC_FOURCC( 'd', 'v', 'h', '1' ): /* DolbyVision */ |
668 | 12 | { |
669 | 12 | MP4_Box_t *p_hvcC = MP4_BoxGet( p_sample, "hvcC" ); |
670 | | |
671 | | /* Handle DV fourcc collision at demux level */ |
672 | 12 | if( i_sample_type == VLC_FOURCC( 'd', 'v', 'h', '1' ) ) |
673 | 0 | p_fmt->i_codec = VLC_FOURCC( 'd', 'v', 'h', 'e' ); |
674 | | |
675 | 12 | if( p_hvcC && p_hvcC->data.p_binary ) |
676 | 11 | { |
677 | 11 | CopyExtradata( p_hvcC->data.p_binary->p_blob, |
678 | 11 | p_hvcC->data.p_binary->i_blob, |
679 | 11 | p_fmt ); |
680 | 11 | } |
681 | 1 | else |
682 | 1 | { |
683 | 1 | msg_Err( p_demux, "missing hvcC" ); |
684 | 1 | } |
685 | 12 | break; |
686 | 12 | } |
687 | | |
688 | 0 | case ATOM_vp08: |
689 | 1 | case ATOM_vp09: |
690 | 1 | case ATOM_vp10: |
691 | 1 | { |
692 | 1 | const MP4_Box_t *p_vpcC = MP4_BoxGet( p_sample, "vpcC" ); |
693 | 1 | if( p_vpcC && BOXDATA(p_vpcC) ) |
694 | 0 | { |
695 | 0 | const MP4_Box_data_vpcC_t *p_data = BOXDATA(p_vpcC); |
696 | 0 | if( i_sample_type == ATOM_vp10 ) |
697 | 0 | p_fmt->i_codec = VLC_CODEC_VP10; |
698 | 0 | else if( i_sample_type == ATOM_vp09 ) |
699 | 0 | p_fmt->i_codec = VLC_CODEC_VP9; |
700 | 0 | else |
701 | 0 | p_fmt->i_codec = VLC_CODEC_VP8; |
702 | 0 | p_fmt->i_profile = p_data->i_profile; |
703 | 0 | p_fmt->i_level = p_data->i_level; |
704 | |
|
705 | 0 | if( p_data->i_version == 0 ) /* old deprecated */ |
706 | 0 | { |
707 | 0 | const uint8_t colorspacesmapping[] = |
708 | 0 | { |
709 | 0 | COLOR_SPACE_UNDEF, |
710 | 0 | COLOR_SPACE_BT601, |
711 | 0 | COLOR_SPACE_BT709, |
712 | 0 | COLOR_SPACE_SMPTE_170, |
713 | 0 | COLOR_SPACE_SMPTE_240, |
714 | 0 | COLOR_SPACE_BT2020, |
715 | 0 | COLOR_SPACE_BT2020, |
716 | 0 | COLOR_SPACE_SRGB, |
717 | 0 | }; |
718 | 0 | if( p_data->i_color_primaries < ARRAY_SIZE(colorspacesmapping) ) |
719 | 0 | p_fmt->video.space = colorspacesmapping[p_data->i_color_primaries]; |
720 | |
|
721 | 0 | if( p_data->i_xfer_function == 0 ) |
722 | 0 | p_fmt->video.transfer = TRANSFER_FUNC_BT709; |
723 | 0 | else if ( p_data->i_xfer_function == 1 ) |
724 | 0 | p_fmt->video.transfer = TRANSFER_FUNC_SMPTE_ST2084; |
725 | 0 | } |
726 | 0 | else |
727 | 0 | { |
728 | 0 | p_fmt->video.primaries = |
729 | 0 | iso_23001_8_cp_to_vlc_primaries( p_data->i_color_primaries ); |
730 | 0 | p_fmt->video.transfer = |
731 | 0 | iso_23001_8_tc_to_vlc_xfer( p_data->i_xfer_function ); |
732 | 0 | p_fmt->video.space = |
733 | 0 | iso_23001_8_mc_to_vlc_coeffs( p_data->i_matrix_coeffs ); |
734 | 0 | } |
735 | |
|
736 | 0 | p_fmt->video.color_range = p_data->i_fullrange ? COLOR_RANGE_FULL : COLOR_RANGE_LIMITED; |
737 | 0 | if (p_fmt->i_profile == -1 && p_fmt->i_level == -1) |
738 | | // HACK: keep the bits per sample in i_level |
739 | 0 | p_fmt->i_level = p_data->i_bit_depth; |
740 | |
|
741 | 0 | CopyExtradata( p_data->p_codec_init_data, |
742 | 0 | p_data->i_codec_init_datasize, |
743 | 0 | p_fmt ); |
744 | |
|
745 | 0 | const MP4_Box_t *p_SmDm = MP4_BoxGet( p_sample, "SmDm" ); |
746 | 0 | if( !p_SmDm ) |
747 | 0 | p_SmDm = MP4_BoxGet( p_sample, "mdcv" ); |
748 | 0 | if( p_SmDm && BOXDATA(p_SmDm) ) |
749 | 0 | { |
750 | 0 | memcpy( p_fmt->video.mastering.primaries, |
751 | 0 | BOXDATA(p_SmDm)->primaries, sizeof(p_fmt->video.mastering.primaries) ); |
752 | 0 | memcpy( p_fmt->video.mastering.white_point, |
753 | 0 | BOXDATA(p_SmDm)->white_point, sizeof(p_fmt->video.mastering.white_point) ); |
754 | 0 | p_fmt->video.mastering.max_luminance = BOXDATA(p_SmDm)->i_luminanceMax; |
755 | 0 | p_fmt->video.mastering.min_luminance = BOXDATA(p_SmDm)->i_luminanceMin; |
756 | 0 | } |
757 | |
|
758 | 0 | const MP4_Box_t *p_CoLL = MP4_BoxGet( p_sample, "CoLL" ); |
759 | 0 | if( !p_CoLL ) |
760 | 0 | p_CoLL = MP4_BoxGet( p_sample, "clli" ); |
761 | 0 | if( p_CoLL && BOXDATA(p_CoLL) ) |
762 | 0 | { |
763 | 0 | p_fmt->video.lighting.MaxCLL = BOXDATA(p_CoLL)->i_maxCLL; |
764 | 0 | p_fmt->video.lighting.MaxFALL = BOXDATA(p_CoLL)->i_maxFALL; |
765 | 0 | } |
766 | 0 | } |
767 | 1 | } |
768 | 1 | break; |
769 | | |
770 | 9 | case ATOM_WMV3: |
771 | 9 | p_cfg->p_asf = MP4_BoxGet( p_sample, "ASF " ); |
772 | | /* fallthrough */ |
773 | 9 | case ATOM_H264: |
774 | 9 | case VLC_FOURCC('W','V','C','1'): |
775 | 9 | { |
776 | 9 | MP4_Box_t *p_strf = MP4_BoxGet( p_sample, "strf" ); |
777 | 9 | if ( p_strf && BOXDATA(p_strf) ) |
778 | 0 | { |
779 | 0 | p_fmt->video.i_width = BOXDATA(p_strf)->bmiHeader.biWidth; |
780 | 0 | p_fmt->video.i_visible_width = p_fmt->video.i_width; |
781 | 0 | p_fmt->video.i_height = BOXDATA(p_strf)->bmiHeader.biHeight; |
782 | 0 | p_fmt->video.i_visible_height =p_fmt->video.i_height; |
783 | 0 | CopyExtradata( BOXDATA(p_strf)->p_extra, |
784 | 0 | BOXDATA(p_strf)->i_extra, |
785 | 0 | p_fmt ); |
786 | 0 | } |
787 | | /* Mostly bogus muxs with old codecs |
788 | | * see 71c4cc66456facb59cd0eef1626be1be1befeb39 */ |
789 | 9 | p_cfg->b_ignore_implicit_pts = true; |
790 | 9 | break; |
791 | 9 | } |
792 | | |
793 | 0 | case VLC_FOURCC( 'a', 'i', '5', 'p' ): |
794 | 0 | case VLC_FOURCC( 'a', 'i', '5', 'q' ): |
795 | 0 | case VLC_FOURCC( 'a', 'i', '5', '2' ): |
796 | 0 | case VLC_FOURCC( 'a', 'i', '5', '3' ): |
797 | 0 | case VLC_FOURCC( 'a', 'i', '5', '5' ): |
798 | 0 | case VLC_FOURCC( 'a', 'i', '5', '6' ): |
799 | 0 | case VLC_FOURCC( 'a', 'i', '1', 'p' ): |
800 | 0 | case VLC_FOURCC( 'a', 'i', '1', 'q' ): |
801 | 0 | case VLC_FOURCC( 'a', 'i', '1', '2' ): |
802 | 0 | case VLC_FOURCC( 'a', 'i', '1', '3' ): |
803 | 0 | case VLC_FOURCC( 'a', 'i', '1', '5' ): |
804 | 1 | case VLC_FOURCC( 'a', 'i', '1', '6' ): |
805 | 1 | { |
806 | 1 | if( !p_fmt->i_extra && p_fmt->video.i_width < UINT16_MAX && |
807 | 1 | p_fiel && BOXDATA(p_fiel) ) |
808 | 0 | { |
809 | 0 | p_fmt->p_extra = |
810 | 0 | AVCi_create_AnnexB( p_fmt->video.i_width, |
811 | 0 | !!BOXDATA(p_fiel)->i_flags, &p_fmt->i_extra ); |
812 | 0 | } |
813 | 1 | break; |
814 | 0 | } |
815 | | |
816 | 0 | case VLC_FOURCC('s','m','c',' '): |
817 | 1 | case VLC_FOURCC('8','B','P','S'): |
818 | 1 | { |
819 | 1 | if( p_sample->data.p_sample_vide->p_palette ) |
820 | 1 | { |
821 | 1 | p_fmt->video.p_palette = malloc(sizeof(video_palette_t)); |
822 | 1 | if( p_fmt->video.p_palette ) |
823 | 1 | *p_fmt->video.p_palette = *p_sample->data.p_sample_vide->p_palette; |
824 | 1 | } |
825 | 0 | else if(qt_palette_depth_has_default(p_sample->data.p_sample_vide->i_depth)) |
826 | 0 | { |
827 | 0 | p_fmt->video.p_palette = qt_make_palette(p_sample->data.p_sample_vide->i_depth); |
828 | 0 | } |
829 | 1 | break; |
830 | 0 | } |
831 | | |
832 | 642 | default: |
833 | 642 | msg_Dbg( p_demux, "Unrecognized FourCC %4.4s", (char *)&i_sample_type ); |
834 | 642 | break; |
835 | 1.47k | } |
836 | | |
837 | | /* Codec like QTRLE will need to provide depth. */ |
838 | 1.47k | if (p_fmt->i_profile == -1 && p_fmt->i_level == -1 && |
839 | 1.47k | p_fmt->video.i_chroma == 0) |
840 | 845 | p_fmt->i_level = p_vide->i_depth; |
841 | 1.47k | return 1; |
842 | 1.47k | } |
843 | | |
844 | | static bool SetupAudioFromWaveFormatEx( const MP4_Box_t *p_WMA2, es_format_t *p_fmt ) |
845 | 124 | { |
846 | 124 | if( p_WMA2 && BOXDATA(p_WMA2) ) |
847 | 99 | { |
848 | 99 | wf_tag_to_fourcc(BOXDATA(p_WMA2)->Format.wFormatTag, &p_fmt->i_codec, NULL); |
849 | 99 | p_fmt->audio.i_channels = BOXDATA(p_WMA2)->Format.nChannels; |
850 | 99 | p_fmt->audio.i_rate = BOXDATA(p_WMA2)->Format.nSamplesPerSec; |
851 | 99 | p_fmt->i_bitrate = BOXDATA(p_WMA2)->Format.nAvgBytesPerSec * 8; |
852 | 99 | p_fmt->audio.i_blockalign = BOXDATA(p_WMA2)->Format.nBlockAlign; |
853 | 99 | p_fmt->audio.i_bitspersample = BOXDATA(p_WMA2)->Format.wBitsPerSample; |
854 | 99 | CopyExtradata( BOXDATA(p_WMA2)->p_extra, |
855 | 99 | BOXDATA(p_WMA2)->i_extra, |
856 | 99 | p_fmt ); |
857 | 99 | return true; |
858 | 99 | } |
859 | 25 | return false; |
860 | 124 | } |
861 | | |
862 | | int SetupAudioES( demux_t *p_demux, const mp4_track_t *p_track, |
863 | | const MP4_Box_t *p_sample, es_format_t *p_fmt, |
864 | | track_config_t *p_cfg ) |
865 | 1.60k | { |
866 | 1.60k | const MP4_Box_data_sample_soun_t *p_soun = p_sample->data.p_sample_soun; |
867 | 1.60k | if(!p_soun) |
868 | 0 | return 0; |
869 | | |
870 | 1.60k | const uint32_t i_sample_type = GetSampleType( p_demux, p_sample ); |
871 | 1.60k | p_fmt->i_original_fourcc = i_sample_type; |
872 | | |
873 | 1.60k | p_fmt->audio.i_channels = p_soun->i_channelcount; |
874 | 1.60k | p_fmt->audio.i_rate = p_soun->i_sampleratehi; |
875 | 1.60k | if( p_soun->i_qt_version == 0 ) /* otherwise defaults to meaningless 16 */ |
876 | 1.27k | { |
877 | 1.27k | p_fmt->audio.i_bitspersample = p_soun->i_samplesize; |
878 | 1.27k | p_fmt->i_bitrate = p_soun->i_channelcount * p_soun->i_sampleratehi * |
879 | 1.27k | p_soun->i_samplesize; |
880 | 1.27k | } |
881 | | |
882 | | /* Endianness atom */ |
883 | 1.60k | const MP4_Box_t *p_enda = MP4_BoxGet( p_sample, "wave/enda" ); |
884 | 1.60k | if( !p_enda ) |
885 | 1.60k | p_enda = MP4_BoxGet( p_sample, "enda" ); |
886 | | |
887 | | /* It's a little ugly but .. there are special cases */ |
888 | 1.60k | switch( i_sample_type ) |
889 | 1.60k | { |
890 | 2 | case( VLC_FOURCC( 'r', 'r', 't', 'p' ) ): /* RTP Reception Hint Track */ |
891 | 2 | { |
892 | 2 | if( !SetupRTPReceptionHintTrack( p_demux, p_track, p_sample, p_fmt, p_cfg ) ) |
893 | 2 | return 0; |
894 | 0 | break; |
895 | 2 | } |
896 | 16 | case ATOM_agsm: /* Apple gsm 33 bytes != MS GSM (agsm fourcc, 65 bytes) */ |
897 | 16 | p_fmt->i_codec = VLC_CODEC_GSM; |
898 | 16 | break; |
899 | 2 | case( VLC_FOURCC( '.', 'm', 'p', '3' ) ): |
900 | 11 | case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ): |
901 | 11 | { |
902 | 11 | p_fmt->i_codec = VLC_CODEC_MP3; |
903 | 11 | p_fmt->b_packetized = false; |
904 | 11 | break; |
905 | 2 | } |
906 | 1 | case ATOM_XiVs: |
907 | 1 | { |
908 | 1 | const MP4_Box_t *p_vCtH = MP4_BoxGet( p_sample, "wave/vCtH" ); /* kCookieTypeVorbisHeader */ |
909 | 1 | const MP4_Box_t *p_vCtd = MP4_BoxGet( p_sample, "wave/vCt#" ); /* kCookieTypeVorbisComments */ |
910 | 1 | const MP4_Box_t *p_vCtC = MP4_BoxGet( p_sample, "wave/vCtC" ); /* kCookieTypeVorbisCodebooks */ |
911 | 1 | if( p_vCtH && p_vCtH->data.p_binary && |
912 | 1 | p_vCtd && p_vCtd->data.p_binary && |
913 | 1 | p_vCtC && p_vCtC->data.p_binary ) |
914 | 0 | { |
915 | 0 | size_t headers_sizes[3] = { |
916 | 0 | p_vCtH->data.p_binary->i_blob, |
917 | 0 | p_vCtd->data.p_binary->i_blob, |
918 | 0 | p_vCtC->data.p_binary->i_blob |
919 | 0 | }; |
920 | |
|
921 | 0 | const void * headers[3] = { |
922 | 0 | p_vCtH->data.p_binary->p_blob, |
923 | 0 | p_vCtd->data.p_binary->p_blob, |
924 | 0 | p_vCtC->data.p_binary->p_blob |
925 | 0 | }; |
926 | |
|
927 | 0 | if( xiph_PackHeaders( &p_fmt->i_extra, &p_fmt->p_extra, |
928 | 0 | headers_sizes, headers, 3 ) == VLC_SUCCESS ) |
929 | 0 | { |
930 | 0 | p_fmt->i_codec = VLC_CODEC_VORBIS; |
931 | 0 | p_fmt->b_packetized = false; |
932 | 0 | } |
933 | 0 | } |
934 | 1 | break; |
935 | 2 | } |
936 | 1 | case ATOM_XiFL: |
937 | 1 | { |
938 | 1 | const MP4_Box_t *p_fCtS = MP4_BoxGet( p_sample, "wave/fCtS" ); /* kCookieTypeFLACStreaminfo */ |
939 | 1 | if( p_fCtS && p_fCtS->data.p_binary ) |
940 | 0 | { |
941 | 0 | size_t i_extra = 8 + p_fCtS->data.p_binary->i_blob; |
942 | 0 | uint8_t *p_extra = malloc(i_extra); |
943 | 0 | if( p_extra ) |
944 | 0 | { |
945 | 0 | p_fmt->i_extra = i_extra; |
946 | 0 | p_fmt->p_extra = p_extra; |
947 | 0 | memcpy( p_extra, "fLaC", 4 ); |
948 | 0 | SetDWBE( &p_extra[4], p_fCtS->data.p_binary->i_blob ); /* want the lowest 24bits */ |
949 | 0 | p_extra[4] = 0x80; /* 0x80 Last metablock | 0x00 StreamInfo */ |
950 | 0 | memcpy( &p_extra[8], p_fCtS->data.p_binary->p_blob, p_fCtS->data.p_binary->i_blob ); |
951 | |
|
952 | 0 | p_fmt->i_codec = VLC_CODEC_FLAC; |
953 | 0 | p_fmt->b_packetized = false; |
954 | 0 | } |
955 | 0 | } |
956 | 1 | break; |
957 | 2 | } |
958 | 1 | case ATOM_fLaC: |
959 | 1 | { |
960 | 1 | const MP4_Box_t *p_dfLa = MP4_BoxGet( p_sample, "dfLa" ); |
961 | 1 | if( p_dfLa && p_dfLa->data.p_binary->i_blob > 4 && |
962 | 1 | GetDWBE(p_dfLa->data.p_binary->p_blob) == 0 ) /* fullbox header, avoids creating dedicated parser */ |
963 | 0 | { |
964 | 0 | size_t i_extra = p_dfLa->data.p_binary->i_blob; |
965 | 0 | uint8_t *p_extra = malloc(i_extra); |
966 | 0 | if( likely( p_extra ) ) |
967 | 0 | { |
968 | 0 | p_fmt->i_extra = i_extra; |
969 | 0 | p_fmt->p_extra = p_extra; |
970 | 0 | memcpy( p_extra, p_dfLa->data.p_binary->p_blob, p_dfLa->data.p_binary->i_blob); |
971 | 0 | memcpy( p_extra, "fLaC", 4 ); |
972 | 0 | p_fmt->i_codec = VLC_CODEC_FLAC; |
973 | 0 | } |
974 | 0 | } |
975 | 1 | break; |
976 | 2 | } |
977 | 1 | case ATOM_Opus: |
978 | 1 | { |
979 | 1 | const MP4_Box_t *p_dOps = MP4_BoxGet( p_sample, "dOps" ); |
980 | 1 | if( p_dOps && p_dOps->data.p_binary->i_blob > 10 ) |
981 | 0 | { |
982 | 0 | size_t i_src = p_dOps->data.p_binary->i_blob; |
983 | 0 | const uint8_t *p_src = p_dOps->data.p_binary->p_blob; |
984 | 0 | if(p_src[0] != 0x00 || (SIZE_MAX - p_dOps->data.p_binary->i_blob < 26)) |
985 | 0 | break; |
986 | 0 | size_t i_dst = 2 + 8 + p_dOps->data.p_binary->i_blob + 8 + 8; |
987 | 0 | uint8_t *p_dst = malloc(i_dst); |
988 | 0 | if( likely( p_dst ) ) |
989 | 0 | { |
990 | 0 | p_dst[0] = 0x01; |
991 | 0 | p_dst[1] = 8 + i_src; |
992 | 0 | memcpy(&p_dst[2], "OpusHead", 8); |
993 | 0 | memcpy(&p_dst[10], p_src, i_src); |
994 | 0 | p_dst[10] = 0x01; // set version != ISOBMFF mapping |
995 | 0 | SetWLE(&p_dst[12], GetWBE(&p_dst[12])); // swap endianness for PreSkip |
996 | 0 | SetDWLE(&p_dst[14], GetDWBE(&p_dst[14])); // swap endianness for InputSampleRate |
997 | 0 | SetWLE(&p_dst[18], GetWBE(&p_dst[18])); // swap endianness for OutputGain |
998 | 0 | memcpy(&p_dst[10 + i_src], "OpusTags\x00\x00\x00\x00\x00\x00\x00", 16); |
999 | 0 | p_fmt->i_extra = i_dst; |
1000 | 0 | p_fmt->p_extra = p_dst; |
1001 | 0 | p_fmt->i_codec = VLC_CODEC_OPUS; |
1002 | 0 | } |
1003 | 0 | } |
1004 | 1 | break; |
1005 | 1 | } |
1006 | 1 | case( ATOM_eac3 ): |
1007 | 1 | { |
1008 | 1 | p_fmt->i_codec = VLC_CODEC_EAC3; |
1009 | | /* TS 102.366. F6 The values of the ChannelCount and SampleSize fields |
1010 | | * within the EC3SampleEntry Box shall be ignored. */ |
1011 | 1 | p_fmt->audio.i_channels = 0; |
1012 | 1 | p_fmt->audio.i_bitspersample = 0; |
1013 | | |
1014 | 1 | const MP4_Box_t *p_dec3 = MP4_BoxGet( p_sample, "dec3" ); |
1015 | 1 | if( p_dec3 && BOXDATA(p_dec3) ) |
1016 | 0 | { |
1017 | 0 | p_fmt->i_bitrate = BOXDATA(p_dec3)->i_data_rate * 1000; |
1018 | 0 | } |
1019 | 1 | break; |
1020 | 1 | } |
1021 | 0 | case( ATOM_AC3 ): |
1022 | 2 | case( ATOM_ac3 ): |
1023 | 2 | { |
1024 | 2 | p_fmt->i_codec = VLC_CODEC_A52; |
1025 | | /* TS 102.366. F3 The values of the ChannelCount and SampleSize fields |
1026 | | * within the AC3SampleEntry Box shall be ignored */ |
1027 | 2 | p_fmt->audio.i_channels = 0; |
1028 | 2 | p_fmt->audio.i_bitspersample = 0; |
1029 | | |
1030 | 2 | MP4_Box_t *p_dac3 = MP4_BoxGet( p_sample, "dac3" ); |
1031 | 2 | if( p_dac3 && BOXDATA(p_dac3) ) |
1032 | 0 | { |
1033 | 0 | static const int pi_bitrate[] = { |
1034 | 0 | 32, 40, 48, 56, |
1035 | 0 | 64, 80, 96, 112, |
1036 | 0 | 128, 160, 192, 224, |
1037 | 0 | 256, 320, 384, 448, |
1038 | 0 | 512, 576, 640, |
1039 | 0 | }; |
1040 | 0 | p_fmt->i_bitrate = 0; |
1041 | 0 | if( BOXDATA(p_dac3)->i_bitrate_code < sizeof(pi_bitrate)/sizeof(*pi_bitrate) ) |
1042 | 0 | { |
1043 | 0 | p_fmt->i_bitrate = pi_bitrate[BOXDATA(p_dac3)->i_bitrate_code] * 1000; |
1044 | |
|
1045 | 0 | if (pi_bitrate[BOXDATA(p_dac3)->i_bitrate_code] == 640 |
1046 | 0 | && BOXDATA(p_dac3)->i_acmod == 7 |
1047 | 0 | && BOXDATA(p_dac3)->i_lfeon == 1) |
1048 | 0 | { |
1049 | | /* DD+ can be an optional codec, and is deployed as an |
1050 | | * extension to a "core" AC-3 5.1 640kbit/s audiotrack. |
1051 | | * In that case, the AC-3 track might have an EAC3 |
1052 | | * extension, therefore trigger the A52 packetizer to |
1053 | | * detect it (this is needed for aout passhthrough |
1054 | | * configuration). */ |
1055 | |
|
1056 | 0 | p_fmt->b_packetized = false; |
1057 | 0 | } |
1058 | 0 | } |
1059 | 0 | } |
1060 | 2 | break; |
1061 | 0 | } |
1062 | 1 | case VLC_FOURCC( 'm', 'l', 'p', 'a' ): |
1063 | | /* spec violation: 32 bits rate instead of fixed point */ |
1064 | 1 | p_fmt->i_codec = VLC_CODEC_TRUEHD; |
1065 | 1 | p_fmt->audio.i_rate = (p_soun->i_sampleratehi << 16) | p_soun->i_sampleratelo; |
1066 | 1 | break; |
1067 | | |
1068 | 0 | case ATOM_dtsc: /* DTS */ |
1069 | 0 | { |
1070 | 0 | p_fmt->i_codec = VLC_CODEC_DTS; |
1071 | 0 | p_fmt->i_profile = PROFILE_DTS; |
1072 | 0 | break; |
1073 | 0 | } |
1074 | 1 | case ATOM_dtse: /* DTS LBR */ |
1075 | 1 | { |
1076 | 1 | p_fmt->i_codec = VLC_CODEC_DTS; |
1077 | 1 | p_fmt->i_profile = PROFILE_DTS_EXPRESS; |
1078 | 1 | break; |
1079 | 0 | } |
1080 | 6 | case ATOM_dtsh: /* DTS‐HD audio formats */ |
1081 | 7 | case ATOM_dtsl: /* DTS‐HD Lossless formats */ |
1082 | 7 | { |
1083 | 7 | p_fmt->i_codec = VLC_CODEC_DTS; |
1084 | 7 | p_fmt->i_profile = PROFILE_DTS_HD; |
1085 | 7 | break; |
1086 | 6 | } |
1087 | | |
1088 | 1 | case VLC_FOURCC( 't', 'w', 'o', 's' ): |
1089 | 1 | p_fmt->i_codec = VLC_CODEC_S16B; |
1090 | 1 | p_fmt->i_original_fourcc = i_sample_type; |
1091 | 1 | p_fmt->audio.i_bitspersample = 16; |
1092 | 1 | break; |
1093 | | |
1094 | 18 | case VLC_FOURCC( 's', 'o', 'w', 't' ): |
1095 | 18 | p_fmt->i_codec = VLC_CODEC_S16L; |
1096 | 18 | p_fmt->i_original_fourcc = i_sample_type; |
1097 | 18 | p_fmt->audio.i_bitspersample = 16; |
1098 | 18 | break; |
1099 | | |
1100 | 27 | case 0x0000000: |
1101 | 35 | case( VLC_FOURCC( 'r', 'a', 'w', ' ' ) ): |
1102 | 35 | case( VLC_FOURCC( 'N', 'O', 'N', 'E' ) ): |
1103 | 35 | { |
1104 | 35 | if( (p_soun->i_samplesize+7)/8 == 1 ) |
1105 | 9 | { |
1106 | 9 | p_fmt->i_codec = VLC_CODEC_U8; |
1107 | 9 | p_fmt->audio.i_bitspersample = 8; |
1108 | 9 | } |
1109 | 26 | else |
1110 | 26 | { |
1111 | 26 | p_fmt->i_codec = VLC_CODEC_S16B; |
1112 | 26 | p_fmt->audio.i_bitspersample = 16; |
1113 | 26 | } |
1114 | 35 | p_fmt->i_original_fourcc = p_fmt->i_codec; |
1115 | | |
1116 | | /* Buggy files workaround */ |
1117 | 35 | if( p_track->i_timescale != p_soun->i_sampleratehi && p_soun->i_qt_version == 0 ) |
1118 | 15 | { |
1119 | 15 | msg_Warn( p_demux, "i_timescale (%"PRId32") != i_sampleratehi " |
1120 | 15 | "(%u), making both equal (report any problem).", |
1121 | 15 | p_track->i_timescale, p_soun->i_sampleratehi ); |
1122 | | |
1123 | 15 | if( p_soun->i_sampleratehi != 0 ) |
1124 | 9 | p_cfg->i_timescale_override = p_soun->i_sampleratehi; |
1125 | 6 | else |
1126 | 6 | p_fmt->audio.i_rate = p_track->i_timescale; |
1127 | 15 | } |
1128 | 35 | break; |
1129 | 35 | } |
1130 | | |
1131 | 0 | case ATOM_ipcm: |
1132 | 0 | case ATOM_fpcm: |
1133 | 0 | { |
1134 | 0 | const MP4_Box_t *p_pcmC = MP4_BoxGet( p_sample, "pcmC" ); |
1135 | 0 | if( p_pcmC ) |
1136 | 0 | { |
1137 | 0 | const vlc_fourcc_t lookup = i_sample_type + |
1138 | 0 | BOXDATA(p_pcmC)->i_sample_size + |
1139 | 0 | (BOXDATA(p_pcmC)->i_format_flags & 0x01); |
1140 | 0 | const vlc_fourcc_t lookuptable[10][2] = |
1141 | 0 | { |
1142 | 0 | { ATOM_fpcm + 32 + 0, VLC_CODEC_F32B }, |
1143 | 0 | { ATOM_fpcm + 32 + 1, VLC_CODEC_F32L }, |
1144 | 0 | { ATOM_fpcm + 64 + 0, VLC_CODEC_F64B }, |
1145 | 0 | { ATOM_fpcm + 64 + 1, VLC_CODEC_F64L }, |
1146 | 0 | { ATOM_ipcm + 16 + 0, VLC_CODEC_S16B }, |
1147 | 0 | { ATOM_ipcm + 16 + 1, VLC_CODEC_S16L }, |
1148 | 0 | { ATOM_ipcm + 24 + 0, VLC_CODEC_S24B }, |
1149 | 0 | { ATOM_ipcm + 24 + 1, VLC_CODEC_S24L }, |
1150 | 0 | { ATOM_ipcm + 32 + 0, VLC_CODEC_S32B }, |
1151 | 0 | { ATOM_ipcm + 32 + 1, VLC_CODEC_S32L }, |
1152 | 0 | }; |
1153 | 0 | for( size_t i = 0; i<10; i++ ) |
1154 | 0 | if( lookuptable[i][0] == lookup ) |
1155 | 0 | p_fmt->i_codec = lookuptable[i][1]; |
1156 | 0 | } |
1157 | 0 | break; |
1158 | 0 | } |
1159 | | |
1160 | 2 | case ATOM_in24: |
1161 | 2 | p_fmt->i_original_fourcc = |
1162 | 2 | p_fmt->i_codec = p_enda && BOXDATA(p_enda)->i_little_endian == 1 ? |
1163 | 2 | VLC_CODEC_S24L : VLC_CODEC_S24B; |
1164 | 2 | break; |
1165 | 2 | case ATOM_in32: |
1166 | 2 | p_fmt->i_original_fourcc = |
1167 | 2 | p_fmt->i_codec = p_enda && BOXDATA(p_enda)->i_little_endian == 1 ? |
1168 | 2 | VLC_CODEC_S32L : VLC_CODEC_S32B; |
1169 | 2 | break; |
1170 | 9 | case ATOM_fl32: |
1171 | 9 | p_fmt->i_original_fourcc = |
1172 | 9 | p_fmt->i_codec = p_enda && BOXDATA(p_enda)->i_little_endian == 1 ? |
1173 | 9 | VLC_CODEC_F32L : VLC_CODEC_F32B; |
1174 | 9 | break; |
1175 | 3 | case ATOM_fl64: |
1176 | 3 | p_fmt->i_original_fourcc = |
1177 | 3 | p_fmt->i_codec = p_enda && BOXDATA(p_enda)->i_little_endian == 1 ? |
1178 | 3 | VLC_CODEC_F64L : VLC_CODEC_F64B; |
1179 | 3 | break; |
1180 | | |
1181 | 10 | case VLC_CODEC_DVD_LPCM: |
1182 | 10 | { |
1183 | 10 | if( p_soun->i_qt_version == 2 ) |
1184 | 0 | { |
1185 | | /* Flags: |
1186 | | * 0x01: IsFloat |
1187 | | * 0x02: IsBigEndian |
1188 | | * 0x04: IsSigned |
1189 | | */ |
1190 | 0 | static const struct { |
1191 | 0 | unsigned i_flags; |
1192 | 0 | unsigned i_mask; |
1193 | 0 | unsigned i_bits; |
1194 | 0 | vlc_fourcc_t i_codec; |
1195 | 0 | } p_formats[] = { |
1196 | 0 | { 0x01, 0x03, 32, VLC_CODEC_F32L }, |
1197 | 0 | { 0x01, 0x03, 64, VLC_CODEC_F64L }, |
1198 | 0 | { 0x01|0x02, 0x03, 32, VLC_CODEC_F32B }, |
1199 | 0 | { 0x01|0x02, 0x03, 64, VLC_CODEC_F64B }, |
1200 | |
|
1201 | 0 | { 0x00, 0x05, 8, VLC_CODEC_U8 }, |
1202 | 0 | { 0x00| 0x04, 0x05, 8, VLC_CODEC_S8 }, |
1203 | |
|
1204 | 0 | { 0x00, 0x07, 16, VLC_CODEC_U16L }, |
1205 | 0 | { 0x00|0x02, 0x07, 16, VLC_CODEC_U16B }, |
1206 | 0 | { 0x00 |0x04, 0x07, 16, VLC_CODEC_S16L }, |
1207 | 0 | { 0x00|0x02|0x04, 0x07, 16, VLC_CODEC_S16B }, |
1208 | |
|
1209 | 0 | { 0x00, 0x07, 24, VLC_CODEC_U24L }, |
1210 | 0 | { 0x00|0x02, 0x07, 24, VLC_CODEC_U24B }, |
1211 | 0 | { 0x00 |0x04, 0x07, 24, VLC_CODEC_S24L }, |
1212 | 0 | { 0x00|0x02|0x04, 0x07, 24, VLC_CODEC_S24B }, |
1213 | |
|
1214 | 0 | { 0x00, 0x07, 32, VLC_CODEC_U32L }, |
1215 | 0 | { 0x00|0x02, 0x07, 32, VLC_CODEC_U32B }, |
1216 | 0 | { 0x00 |0x04, 0x07, 32, VLC_CODEC_S32L }, |
1217 | 0 | { 0x00|0x02|0x04, 0x07, 32, VLC_CODEC_S32B }, |
1218 | |
|
1219 | 0 | {0, 0, 0, 0} |
1220 | 0 | }; |
1221 | |
|
1222 | 0 | for( int i = 0; p_formats[i].i_codec; i++ ) |
1223 | 0 | { |
1224 | 0 | if( p_formats[i].i_bits == p_soun->i_constbitsperchannel && |
1225 | 0 | (p_soun->i_formatflags & p_formats[i].i_mask) == p_formats[i].i_flags ) |
1226 | 0 | { |
1227 | 0 | p_fmt->i_codec = p_formats[i].i_codec; |
1228 | 0 | p_fmt->audio.i_bitspersample = p_soun->i_constbitsperchannel; |
1229 | 0 | p_fmt->audio.i_blockalign = |
1230 | 0 | p_soun->i_channelcount * p_soun->i_constbitsperchannel / 8; |
1231 | 0 | p_cfg->i_sample_size_override = p_fmt->audio.i_blockalign; |
1232 | 0 | break; |
1233 | 0 | } |
1234 | 0 | } |
1235 | 0 | } |
1236 | 10 | break; |
1237 | 0 | } |
1238 | 1.47k | default: |
1239 | 1.47k | p_fmt->i_codec = i_sample_type; |
1240 | 1.47k | break; |
1241 | 1.60k | } |
1242 | | |
1243 | | |
1244 | | /* Process extensions */ |
1245 | | |
1246 | | /* Lookup for then channels extension */ |
1247 | 1.60k | const MP4_Box_t *p_chan = MP4_BoxGet( p_sample, "chan" ); |
1248 | 1.60k | if ( p_chan ) |
1249 | 13 | { |
1250 | 13 | uint16_t i_vlc_mapping = 0; |
1251 | 13 | uint8_t i_channels = 0; |
1252 | 13 | const uint32_t *p_rg_chans_order = NULL; |
1253 | | |
1254 | 13 | if ( CoreAudio_Layout_to_vlc( &BOXDATA(p_chan)->layout, |
1255 | 13 | &i_vlc_mapping, &i_channels, |
1256 | 13 | &p_rg_chans_order ) != VLC_SUCCESS ) |
1257 | 0 | { |
1258 | 0 | msg_Warn( p_demux, "discarding chan mapping" ); |
1259 | 0 | } |
1260 | 13 | else if( i_vlc_mapping ) |
1261 | 12 | { |
1262 | 12 | const unsigned i_bps = aout_BitsPerSample( p_fmt->i_codec ); |
1263 | | /* Uncompressed audio */ |
1264 | 12 | if( i_bps && aout_CheckChannelReorder( p_rg_chans_order, NULL, |
1265 | 0 | i_vlc_mapping, |
1266 | 0 | p_cfg->rgi_chans_reordering ) ) |
1267 | 0 | p_cfg->b_chans_reorder = true; |
1268 | | |
1269 | | /* we can only set bitmap for VLC mapping or [re]mapped pcm audio |
1270 | | * as vlc can't enumerate channels for compressed content */ |
1271 | 12 | if( i_bps ) |
1272 | 0 | { |
1273 | 0 | p_fmt->audio.i_channels = stdc_count_ones(i_vlc_mapping); |
1274 | 0 | p_fmt->audio.i_physical_channels = i_vlc_mapping; |
1275 | 0 | } |
1276 | 12 | } |
1277 | 13 | } |
1278 | | |
1279 | 1.60k | const MP4_Box_t *p_srat = MP4_BoxGet( p_sample, "srat" ); |
1280 | 1.60k | if ( p_srat ) |
1281 | 1 | p_fmt->audio.i_rate = BOXDATA(p_srat)->i_sample_rate; |
1282 | | |
1283 | 1.60k | SetupGlobalExtensions( p_sample, p_fmt ); |
1284 | | |
1285 | | /* now see if esds is present and if so create a data packet |
1286 | | with decoder_specific_info */ |
1287 | 1.60k | MP4_Box_t *p_esds = MP4_BoxGet( p_sample, "esds" ); |
1288 | 1.60k | if ( !p_esds ) p_esds = MP4_BoxGet( p_sample, "wave/esds" ); |
1289 | 1.60k | if ( p_esds && BOXDATA(p_esds) && BOXDATA(p_esds)->es_descriptor.p_decConfigDescr ) |
1290 | 344 | { |
1291 | 344 | assert(i_sample_type == ATOM_mp4a); |
1292 | 344 | SetupESDS( p_demux, p_track, BOXDATA(p_esds)->es_descriptor.p_decConfigDescr, p_fmt ); |
1293 | 344 | } |
1294 | 1.25k | else switch( i_sample_type ) |
1295 | 1.25k | { |
1296 | 3 | case VLC_CODEC_AMR_NB: |
1297 | 3 | p_fmt->audio.i_rate = 8000; |
1298 | 3 | break; |
1299 | 1 | case VLC_CODEC_AMR_WB: |
1300 | 1 | p_fmt->audio.i_rate = 16000; |
1301 | 1 | break; |
1302 | 1 | case VLC_CODEC_QDMC: |
1303 | 3 | case VLC_CODEC_QDM2: |
1304 | 7 | case VLC_CODEC_ALAC: |
1305 | 7 | { |
1306 | 7 | CopyExtradata( p_sample->data.p_sample_soun->p_qt_description, |
1307 | 7 | p_sample->data.p_sample_soun->i_qt_description, |
1308 | 7 | p_fmt ); |
1309 | 7 | if( p_fmt->i_extra == 56 && i_sample_type == VLC_CODEC_ALAC ) |
1310 | 1 | { |
1311 | 1 | p_fmt->audio.i_channels = *((uint8_t*)p_fmt->p_extra + 41); |
1312 | 1 | p_fmt->audio.i_rate = GetDWBE((uint8_t*)p_fmt->p_extra + 52); |
1313 | 1 | } |
1314 | 7 | break; |
1315 | 3 | } |
1316 | 7 | case VLC_CODEC_ADPCM_MS: |
1317 | 44 | case VLC_CODEC_ADPCM_IMA_WAV: |
1318 | 48 | case VLC_CODEC_QCELP: |
1319 | 48 | { |
1320 | 48 | p_fmt->audio.i_blockalign = p_sample->data.p_sample_soun->i_bytes_per_frame; |
1321 | 48 | break; |
1322 | 44 | } |
1323 | 1 | case ATOM_WMA2: |
1324 | 1 | { |
1325 | 1 | if( SetupAudioFromWaveFormatEx( MP4_BoxGet( p_sample, "wave/WMA2" ), p_fmt ) ) |
1326 | 0 | { |
1327 | 0 | p_cfg->p_asf = MP4_BoxGet( p_sample, "wave/ASF " ); |
1328 | 0 | } |
1329 | 1 | else |
1330 | 1 | { |
1331 | 1 | msg_Err( p_demux, "missing WMA2 %4.4s", (char*) &p_sample->p_father->i_type ); |
1332 | 1 | } |
1333 | 1 | break; |
1334 | 44 | } |
1335 | 123 | case ATOM_wma: /* isml wmapro */ |
1336 | 123 | { |
1337 | 123 | if( !SetupAudioFromWaveFormatEx( MP4_BoxGet( p_sample, "wfex" ), p_fmt ) ) |
1338 | 123 | msg_Err( p_demux, "missing wfex for wma" ); |
1339 | 123 | break; |
1340 | 44 | } |
1341 | | |
1342 | 1.07k | default: |
1343 | 1.07k | if(p_fmt->i_codec == 0) |
1344 | 1.07k | msg_Dbg( p_demux, "Unrecognized FourCC %4.4s", (char *)&i_sample_type ); |
1345 | 1.07k | break; |
1346 | 1.25k | } |
1347 | | |
1348 | | /* Ambisonics */ |
1349 | 1.60k | const MP4_Box_t *p_SA3D = MP4_BoxGet(p_sample, "SA3D"); |
1350 | 1.60k | if (p_SA3D && BOXDATA(p_SA3D)) |
1351 | 1 | p_fmt->audio.channel_type = AUDIO_CHANNEL_TYPE_AMBISONICS; |
1352 | | |
1353 | 1.60k | return 1; |
1354 | 1.60k | } |
1355 | | |
1356 | | int SetupSpuES( demux_t *p_demux, const mp4_track_t *p_track, |
1357 | | const MP4_Box_t *p_sample, es_format_t *p_fmt, |
1358 | | track_config_t *p_cfg ) |
1359 | 148 | { |
1360 | 148 | const uint32_t i_sample_type = GetSampleType( p_demux, p_sample ); |
1361 | | |
1362 | | /* It's a little ugly but .. there are special cases */ |
1363 | 148 | switch( i_sample_type ) |
1364 | 148 | { |
1365 | 1 | case VLC_FOURCC('s','t','p','p'): |
1366 | 1 | p_fmt->i_codec = VLC_CODEC_TTML; |
1367 | 1 | break; |
1368 | 0 | case ATOM_wvtt: |
1369 | 0 | p_fmt->i_codec = VLC_CODEC_WEBVTT; |
1370 | 0 | break; |
1371 | 0 | case ATOM_c608: /* EIA608 closed captions */ |
1372 | 0 | p_fmt->i_codec = VLC_CODEC_CEA608; |
1373 | 0 | p_fmt->subs.cc.i_reorder_depth = -1; |
1374 | 0 | break; |
1375 | 1 | case ATOM_c708: /* EIA708 closed captions */ |
1376 | 1 | p_fmt->i_codec = VLC_CODEC_CEA708; |
1377 | 1 | p_fmt->subs.cc.i_reorder_depth = -1; |
1378 | 1 | break; |
1379 | | |
1380 | 21 | case( VLC_FOURCC( 't', 'e', 'x', 't' ) ): |
1381 | 85 | case( VLC_FOURCC( 't', 'x', '3', 'g' ) ): |
1382 | 85 | { |
1383 | 85 | const MP4_Box_data_sample_generic_t *p_text = p_sample->data.p_sample_gen; |
1384 | 85 | if(!p_text) |
1385 | 0 | return 0; |
1386 | | |
1387 | 85 | if( i_sample_type == VLC_FOURCC( 't', 'e', 'x', 't' ) ) |
1388 | 21 | p_fmt->i_codec = VLC_CODEC_QTXT; |
1389 | 64 | else |
1390 | 64 | p_fmt->i_codec = VLC_CODEC_TX3G; |
1391 | | |
1392 | 85 | if( p_text->i_data > 4 && GetDWBE(p_text->p_data) & 0xC0000000 ) |
1393 | 6 | { |
1394 | 6 | p_fmt->i_priority = ES_PRIORITY_SELECTABLE_MIN + 1; |
1395 | 6 | p_cfg->b_forced_spu = true; |
1396 | 6 | } |
1397 | | |
1398 | 85 | CopyExtradata( p_text->p_data, p_text->i_data, p_fmt ); |
1399 | | |
1400 | | /* FIXME UTF-8 doesn't work here ? */ |
1401 | 85 | if( p_track->b_mac_encoding ) |
1402 | 32 | p_fmt->subs.psz_encoding = strdup( "MAC" ); |
1403 | 53 | else |
1404 | 53 | p_fmt->subs.psz_encoding = strdup( "UTF-8" ); |
1405 | 85 | break; |
1406 | 85 | } |
1407 | | |
1408 | 61 | default: |
1409 | 61 | p_fmt->i_codec = i_sample_type; |
1410 | 61 | break; |
1411 | 148 | } |
1412 | | |
1413 | 148 | SetupGlobalExtensions( p_sample, p_fmt ); |
1414 | | |
1415 | | /* now see if esds is present and if so create a data packet |
1416 | | with decoder_specific_info */ |
1417 | 148 | MP4_Box_t *p_esds = MP4_BoxGet( p_sample, "esds" ); |
1418 | 148 | if ( p_esds && BOXDATA(p_esds) && BOXDATA(p_esds)->es_descriptor.p_decConfigDescr ) |
1419 | 0 | { |
1420 | 0 | SetupESDS( p_demux, p_track, BOXDATA(p_esds)->es_descriptor.p_decConfigDescr, p_fmt ); |
1421 | 0 | } |
1422 | | |
1423 | 148 | return 1; |
1424 | 148 | } |