Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / ISOBMFF reader filter
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include "isoffin.h"
27 : #include <gpac/iso639.h>
28 : #include <gpac/base_coding.h>
29 : #include <gpac/media_tools.h>
30 :
31 : #ifndef GPAC_DISABLE_ISOM
32 :
33 : #if 0 //deprecated - we need to rework chapter information to deal with static chapters and chapter tracks
34 : void isor_emulate_chapters(GF_ISOFile *file, GF_InitialObjectDescriptor *iod)
35 : {
36 : GF_Segment *prev_seg;
37 : u64 prev_start;
38 : u64 start;
39 : u32 i, count;
40 : if (!iod || gf_list_count(iod->OCIDescriptors)) return;
41 : count = gf_isom_get_chapter_count(file, 0);
42 : if (!count) return;
43 :
44 : prev_seg = NULL;
45 : start = prev_start = 0;
46 : for (i=0; i<count; i++) {
47 : const char *name;
48 : GF_Segment *seg;
49 : gf_isom_get_chapter(file, 0, i+1, &start, &name);
50 : seg = (GF_Segment *) gf_odf_desc_new(GF_ODF_SEGMENT_TAG);
51 : seg->startTime = (Double) (s64) start;
52 : seg->startTime /= 1000;
53 : seg->SegmentName = gf_strdup(name);
54 : gf_list_add(iod->OCIDescriptors, seg);
55 : if (prev_seg) {
56 : prev_seg->Duration = (Double) (s64) (start - prev_start);
57 : prev_seg->Duration /= 1000;
58 : } else if (start) {
59 : prev_seg = (GF_Segment *) gf_odf_desc_new(GF_ODF_SEGMENT_TAG);
60 : prev_seg->startTime = 0;
61 : prev_seg->Duration = (Double) (s64) (start);
62 : prev_seg->Duration /= 1000;
63 : gf_list_insert(iod->OCIDescriptors, prev_seg, 0);
64 : }
65 : prev_seg = seg;
66 : prev_start = start;
67 : }
68 : if (prev_seg) {
69 : start = 1000*gf_isom_get_duration(file);
70 : start /= gf_isom_get_timescale(file);
71 : if (start>prev_start) {
72 : prev_seg->Duration = (Double) (s64) (start - prev_start);
73 : prev_seg->Duration /= 1000;
74 : }
75 : }
76 : }
77 : #endif
78 :
79 1199 : static void isor_declare_track(ISOMReader *read, ISOMChannel *ch, u32 track, u32 stsd_idx, u32 streamtype, Bool use_iod)
80 : {
81 : u32 w, h, sr, nb_ch, nb_bps, codec_id, depends_on_id, esid, avg_rate, max_rate, buffer_size, sample_count, max_size, nb_refs, exp_refs, base_track, audio_fmt, pix_fmt;
82 : GF_ESD *an_esd;
83 : const char *mime, *encoding, *stxtcfg, *namespace, *schemaloc, *mime_cfg;
84 : #if !defined(GPAC_DISABLE_ISOM_WRITE)
85 : u8 *tk_template;
86 : u32 tk_template_size;
87 : #endif
88 : GF_Language *lang_desc = NULL;
89 : Bool external_base=GF_FALSE;
90 : Bool has_scalable_layers = GF_FALSE;
91 1199 : u8 *dsi = NULL, *enh_dsi = NULL;
92 1199 : u32 dsi_size = 0, enh_dsi_size = 0;
93 : Double track_dur=0;
94 1199 : u32 srd_id=0, srd_indep=0, srd_x=0, srd_y=0, srd_w=0, srd_h=0;
95 1199 : u32 base_tile_track=0;
96 1199 : Bool srd_full_frame=GF_FALSE;
97 : u32 mtype, m_subtype;
98 : GF_GenericSampleDescription *udesc = NULL;
99 : GF_Err e;
100 : u32 ocr_es_id;
101 : Bool first_config = GF_FALSE;
102 :
103 :
104 1199 : depends_on_id = avg_rate = max_rate = buffer_size = 0;
105 1199 : mime = encoding = stxtcfg = namespace = schemaloc = mime_cfg = NULL;
106 :
107 1199 : if ( gf_isom_is_media_encrypted(read->mov, track, stsd_idx)) {
108 217 : gf_isom_get_original_format_type(read->mov, track, stsd_idx, &m_subtype);
109 : } else {
110 982 : m_subtype = gf_isom_get_media_subtype(read->mov, track, stsd_idx);
111 : }
112 :
113 : audio_fmt = 0;
114 : pix_fmt = 0;
115 : ocr_es_id = 0;
116 1199 : an_esd = gf_media_map_esd(read->mov, track, stsd_idx);
117 1199 : if (an_esd && an_esd->decoderConfig) {
118 921 : if (an_esd->decoderConfig->streamType==GF_STREAM_INTERACT) {
119 4 : gf_odf_desc_del((GF_Descriptor *)an_esd);
120 4 : return;
121 : }
122 917 : streamtype = an_esd->decoderConfig->streamType;
123 917 : if (an_esd->decoderConfig->objectTypeIndication < GF_CODECID_LAST_MPEG4_MAPPING) {
124 782 : codec_id = gf_codecid_from_oti(streamtype, an_esd->decoderConfig->objectTypeIndication);
125 : } else {
126 : codec_id = an_esd->decoderConfig->objectTypeIndication;
127 : }
128 917 : ocr_es_id = an_esd->OCRESID;
129 917 : depends_on_id = an_esd->dependsOnESID;
130 917 : lang_desc = an_esd->langDesc;
131 917 : an_esd->langDesc = NULL;
132 917 : esid = an_esd->ESID;
133 :
134 917 : if (an_esd->decoderConfig->decoderSpecificInfo && an_esd->decoderConfig->decoderSpecificInfo->data) {
135 894 : dsi = an_esd->decoderConfig->decoderSpecificInfo->data;
136 894 : dsi_size = an_esd->decoderConfig->decoderSpecificInfo->dataLength;
137 894 : an_esd->decoderConfig->decoderSpecificInfo->data = NULL;
138 894 : an_esd->decoderConfig->decoderSpecificInfo->dataLength = 0;
139 : }
140 :
141 917 : gf_odf_desc_del((GF_Descriptor *)an_esd);
142 :
143 : #ifndef GPAC_DISABLE_AV_PARSERS
144 917 : if (dsi && (codec_id==GF_CODECID_AAC_MPEG4)) {
145 : GF_M4ADecSpecInfo acfg;
146 198 : gf_m4a_get_config(dsi, dsi_size, &acfg);
147 198 : if (acfg.base_object_type == GF_M4A_USAC)
148 : codec_id = GF_CODECID_USAC;
149 : }
150 : #endif
151 :
152 : } else {
153 : u32 pcm_flags, pcm_size;
154 : Bool load_default = GF_FALSE;
155 :
156 278 : if (an_esd)
157 0 : gf_odf_desc_del((GF_Descriptor *)an_esd);
158 :
159 278 : lang_desc = (GF_Language *) gf_odf_desc_new(GF_ODF_LANG_TAG);
160 278 : gf_isom_get_media_language(read->mov, track, &lang_desc->full_lang_code);
161 278 : esid = gf_isom_get_track_id(read->mov, track);
162 :
163 278 : if (!streamtype) streamtype = gf_codecid_type(m_subtype);
164 : codec_id = 0;
165 :
166 278 : switch (m_subtype) {
167 27 : case GF_ISOM_SUBTYPE_STXT:
168 : case GF_ISOM_SUBTYPE_METT:
169 : case GF_ISOM_SUBTYPE_SBTT:
170 : case GF_ISOM_MEDIA_SUBT:
171 :
172 : codec_id = GF_CODECID_SIMPLE_TEXT;
173 27 : gf_isom_stxt_get_description(read->mov, track, stsd_idx, &mime, &encoding, &stxtcfg);
174 27 : break;
175 13 : case GF_ISOM_SUBTYPE_STPP:
176 : codec_id = GF_CODECID_SUBS_XML;
177 13 : gf_isom_xml_subtitle_get_description(read->mov, track, stsd_idx, &namespace, &schemaloc, &mime);
178 13 : break;
179 3 : case GF_ISOM_SUBTYPE_METX:
180 : codec_id = GF_CODECID_META_XML;
181 3 : gf_isom_xml_subtitle_get_description(read->mov, track, stsd_idx, &namespace, &schemaloc, &mime);
182 3 : break;
183 4 : case GF_ISOM_SUBTYPE_WVTT:
184 : codec_id = GF_CODECID_WEBVTT;
185 4 : stxtcfg = gf_isom_get_webvtt_config(read->mov, track, stsd_idx);
186 4 : break;
187 7 : case GF_ISOM_SUBTYPE_MJP2:
188 : codec_id = GF_CODECID_J2K;
189 7 : gf_isom_get_jp2_config(read->mov, track, stsd_idx, &dsi, &dsi_size);
190 7 : break;
191 105 : case GF_ISOM_SUBTYPE_HVT1:
192 : codec_id = GF_CODECID_HEVC_TILES;
193 105 : gf_isom_get_reference(read->mov, track, GF_ISOM_REF_TBAS, 1, &base_tile_track);
194 105 : if (base_tile_track) {
195 105 : depends_on_id = gf_isom_get_track_id(read->mov, base_tile_track);
196 : }
197 105 : gf_isom_get_tile_info(read->mov, track, 1, NULL, &srd_id, &srd_indep, &srd_full_frame, &srd_x, &srd_y, &srd_w, &srd_h);
198 105 : break;
199 24 : case GF_ISOM_SUBTYPE_TEXT:
200 : case GF_ISOM_SUBTYPE_TX3G:
201 : {
202 24 : GF_TextSampleDescriptor *txtcfg = NULL;
203 : codec_id = GF_CODECID_TX3G;
204 24 : e = gf_isom_get_text_description(read->mov, track, stsd_idx, &txtcfg);
205 24 : if (e) {
206 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Track %d unable to fetch TX3G config\n", track));
207 : }
208 24 : if (txtcfg) {
209 24 : gf_odf_tx3g_write(txtcfg, &dsi, &dsi_size);
210 24 : gf_odf_desc_del((GF_Descriptor *) txtcfg);
211 : }
212 : }
213 24 : break;
214 :
215 2 : case GF_ISOM_SUBTYPE_FLAC:
216 : codec_id = GF_CODECID_FLAC;
217 2 : gf_isom_flac_config_get(read->mov, track, stsd_idx, &dsi, &dsi_size);
218 2 : break;
219 0 : case GF_ISOM_SUBTYPE_OPUS:
220 : codec_id = GF_CODECID_OPUS;
221 0 : gf_isom_opus_config_get(read->mov, track, stsd_idx, &dsi, &dsi_size);
222 0 : break;
223 :
224 24 : case GF_QT_SUBTYPE_TWOS:
225 : case GF_QT_SUBTYPE_SOWT:
226 : case GF_QT_SUBTYPE_FL32:
227 : case GF_QT_SUBTYPE_FL64:
228 : case GF_QT_SUBTYPE_IN24:
229 : case GF_QT_SUBTYPE_IN32:
230 : codec_id = GF_CODECID_RAW;
231 24 : audio_fmt = gf_audio_fmt_from_isobmf(m_subtype);
232 24 : break;
233 : case GF_ISOM_MEDIA_TIMECODE:
234 : codec_id = GF_CODECID_TMCD;
235 : streamtype = GF_STREAM_METADATA;
236 : break;
237 :
238 0 : case GF_QT_SUBTYPE_RAW:
239 : codec_id = GF_CODECID_RAW;
240 0 : if (streamtype==GF_STREAM_AUDIO)
241 : audio_fmt = GF_AUDIO_FMT_U8;
242 : else
243 : pix_fmt = GF_PIXEL_RGB;
244 : break;
245 0 : case GF_QT_SUBTYPE_YUV422_10:
246 : codec_id = GF_CODECID_V210;
247 0 : break;
248 :
249 3 : case GF_ISOM_SUBTYPE_IPCM:
250 3 : if (gf_isom_get_pcm_config(read->mov, track, stsd_idx, &pcm_flags, &pcm_size) == GF_OK) {
251 : codec_id = GF_CODECID_RAW;
252 3 : if (pcm_size==16) audio_fmt = GF_AUDIO_FMT_S16;
253 2 : else if (pcm_size==24) audio_fmt = GF_AUDIO_FMT_S24;
254 1 : else if (pcm_size==32) audio_fmt = GF_AUDIO_FMT_S32;
255 : }
256 : break;
257 2 : case GF_ISOM_SUBTYPE_FPCM:
258 2 : if (gf_isom_get_pcm_config(read->mov, track, stsd_idx, &pcm_flags, &pcm_size) == GF_OK) {
259 : codec_id = GF_CODECID_RAW;
260 2 : audio_fmt = (pcm_size==64) ? GF_AUDIO_FMT_DBL : GF_AUDIO_FMT_FLT;
261 : }
262 : break;
263 :
264 0 : case GF_ISOM_SUBTYPE_VVC1:
265 : case GF_ISOM_SUBTYPE_VVI1:
266 : {
267 0 : GF_VVCConfig *vvccfg = gf_isom_vvc_config_get(read->mov, track, stsd_idx);
268 0 : if (vvccfg) {
269 0 : gf_odf_vvc_cfg_write(vvccfg, &dsi, &dsi_size);
270 0 : gf_odf_vvc_cfg_del(vvccfg);
271 : }
272 : codec_id = GF_CODECID_VVC;
273 : }
274 : break;
275 :
276 9 : case GF_ISOM_SUBTYPE_AC3:
277 : case GF_ISOM_SUBTYPE_EC3:
278 : {
279 9 : GF_AC3Config *ac3cfg = gf_isom_ac3_config_get(read->mov, track, stsd_idx);
280 9 : codec_id = (m_subtype==GF_ISOM_SUBTYPE_AC3) ? GF_CODECID_AC3 : GF_CODECID_EAC3;
281 9 : if (ac3cfg) {
282 9 : gf_odf_ac3_cfg_write(ac3cfg, &dsi, &dsi_size);
283 9 : gf_free(ac3cfg);
284 : }
285 : }
286 : break;
287 :
288 1 : case GF_ISOM_SUBTYPE_MLPA:
289 : {
290 : u32 fmt, prate;
291 1 : if (gf_isom_truehd_config_get(read->mov, track, stsd_idx, &fmt, &prate) == GF_OK) {
292 1 : GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
293 1 : gf_bs_write_u32(bs, fmt);
294 1 : gf_bs_write_int(bs, prate, 15);
295 1 : gf_bs_write_int(bs, 0, 1);
296 1 : gf_bs_write_u32(bs, 0);
297 1 : gf_bs_get_content(bs, &dsi, &dsi_size);
298 1 : gf_bs_del(bs);
299 : codec_id = GF_CODECID_TRUEHD;
300 : }
301 : break;
302 : }
303 :
304 :
305 51 : default:
306 51 : codec_id = gf_codec_id_from_isobmf(m_subtype);
307 51 : if (!codec_id) {
308 3 : pix_fmt = gf_pixel_fmt_from_qt_type(m_subtype);
309 3 : if (pix_fmt) {
310 : codec_id = GF_CODECID_RAW;
311 : } else {
312 : load_default = GF_TRUE;
313 : }
314 : }
315 : break;
316 : }
317 :
318 278 : if (load_default) {
319 3 : if (!codec_id) {
320 3 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Track %d type %s not natively handled\n", track, gf_4cc_to_str(m_subtype) ));
321 :
322 3 : codec_id = m_subtype;
323 : }
324 3 : udesc = gf_isom_get_generic_sample_description(read->mov, track, stsd_idx);
325 3 : if (udesc) {
326 0 : dsi = udesc->extension_buf;
327 0 : dsi_size = udesc->extension_buf_size;
328 0 : udesc->extension_buf = NULL;
329 0 : udesc->extension_buf_size = 0;
330 : }
331 : }
332 : }
333 1195 : if (!streamtype || !codec_id) {
334 0 : if (udesc) gf_free(udesc);
335 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[IsoMedia] Failed to %s pid for track %d, could not extract codec/streamtype info\n", ch ? "update" : "create", track));
336 0 : if (lang_desc) gf_odf_desc_del((GF_Descriptor *)lang_desc);
337 0 : if (dsi) gf_free(dsi);
338 : return;
339 : }
340 :
341 1195 : mime_cfg = gf_isom_subtitle_get_mime(read->mov, track, stsd_idx);
342 :
343 : //first setup, creation of PID and channel
344 1195 : if (!ch) {
345 : Bool use_sidx_dur = GF_FALSE;
346 : GF_FilterPid *pid;
347 : first_config = GF_TRUE;
348 :
349 1138 : gf_isom_get_reference(read->mov, track, GF_ISOM_REF_BASE, 1, &base_track);
350 :
351 1138 : if (base_track) {
352 : u32 base_subtype=0;
353 6 : if (read->smode==MP4DMX_SINGLE)
354 : depends_on_id = 0;
355 :
356 6 : switch (m_subtype) {
357 0 : case GF_ISOM_SUBTYPE_LHV1:
358 : case GF_ISOM_SUBTYPE_LHE1:
359 0 : base_subtype = gf_isom_get_media_subtype(read->mov, base_track, stsd_idx);
360 0 : switch (base_subtype) {
361 : case GF_ISOM_SUBTYPE_HVC1:
362 : case GF_ISOM_SUBTYPE_HEV1:
363 : case GF_ISOM_SUBTYPE_HVC2:
364 : case GF_ISOM_SUBTYPE_HEV2:
365 : break;
366 : default:
367 : external_base=GF_TRUE;
368 : break;
369 : }
370 : }
371 : if (external_base) {
372 0 : depends_on_id = gf_isom_get_track_id(read->mov, base_track);
373 : has_scalable_layers = GF_TRUE;
374 : } else {
375 6 : switch (gf_isom_get_hevc_lhvc_type(read->mov, track, stsd_idx)) {
376 2 : case GF_ISOM_HEVCTYPE_HEVC_LHVC:
377 : case GF_ISOM_HEVCTYPE_LHVC_ONLY:
378 : has_scalable_layers = GF_TRUE;
379 2 : break;
380 : //this is likely temporal sublayer of base
381 0 : case GF_ISOM_HEVCTYPE_HEVC_ONLY:
382 : has_scalable_layers = GF_FALSE;
383 0 : if (gf_isom_get_reference_count(read->mov, track, GF_ISOM_REF_SCAL)<=0) {
384 0 : depends_on_id = gf_isom_get_track_id(read->mov, base_track);
385 : }
386 : break;
387 : default:
388 : break;
389 : }
390 : }
391 : } else {
392 1132 : switch (gf_isom_get_hevc_lhvc_type(read->mov, track, stsd_idx)) {
393 : case GF_ISOM_HEVCTYPE_HEVC_LHVC:
394 : case GF_ISOM_HEVCTYPE_LHVC_ONLY:
395 : has_scalable_layers = GF_TRUE;
396 : break;
397 : default:
398 : break;
399 : }
400 :
401 : if (!has_scalable_layers) {
402 : u32 i;
403 1129 : GF_ISOTrackID track_id = gf_isom_get_track_id(read->mov, track);
404 5041 : for (i=0; i<gf_isom_get_track_count(read->mov); i++) {
405 2787 : if (gf_isom_get_reference_count(read->mov, i+1, GF_ISOM_REF_BASE)>=0) {
406 : GF_ISOTrackID tkid;
407 2787 : gf_isom_get_reference_ID(read->mov, i+1, GF_ISOM_REF_BASE, 1, &tkid);
408 2787 : if (tkid==track_id) {
409 : has_scalable_layers = GF_TRUE;
410 4 : break;
411 : }
412 : }
413 : }
414 : }
415 : }
416 :
417 1138 : if (base_track && !ocr_es_id) {
418 0 : ocr_es_id = gf_isom_get_track_id(read->mov, base_track);
419 : }
420 1138 : if (!ocr_es_id) ocr_es_id = esid;
421 :
422 : //OK declare PID
423 1138 : pid = gf_filter_pid_new(read->filter);
424 1138 : if (read->pid)
425 844 : gf_filter_pid_copy_properties(pid, read->pid);
426 :
427 1138 : gf_filter_pid_set_property(pid, GF_PROP_PID_ID, &PROP_UINT(esid));
428 1138 : gf_filter_pid_set_property(pid, GF_PROP_PID_CLOCK_ID, &PROP_UINT(ocr_es_id));
429 1138 : if (depends_on_id && (depends_on_id != esid))
430 114 : gf_filter_pid_set_property(pid, GF_PROP_PID_DEPENDENCY_ID, &PROP_UINT(depends_on_id));
431 :
432 1138 : if (gf_isom_get_track_count(read->mov)>1) {
433 : char szPName[1024];
434 323 : const char *szST = gf_stream_type_name(streamtype);
435 323 : sprintf(szPName, "%c%d", szST[0], esid);
436 323 : gf_filter_pid_set_name(pid, szPName);
437 : }
438 :
439 : //MPEG-4 systems present
440 1138 : if (use_iod)
441 47 : gf_filter_pid_set_property(pid, GF_PROP_PID_ESID, &PROP_UINT(esid));
442 :
443 1138 : if (gf_isom_is_track_in_root_od(read->mov, track)) {
444 30 : switch (streamtype) {
445 30 : case GF_STREAM_SCENE:
446 : case GF_STREAM_OD:
447 30 : gf_filter_pid_set_property(pid, GF_PROP_PID_IN_IOD, &PROP_BOOL(GF_TRUE));
448 30 : break;
449 : }
450 : }
451 :
452 1138 : gf_filter_pid_set_property(pid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(streamtype));
453 1138 : gf_filter_pid_set_property(pid, GF_PROP_PID_TIMESCALE, &PROP_UINT( gf_isom_get_media_timescale(read->mov, track) ) );
454 :
455 1138 : if (!gf_sys_is_test_mode())
456 23 : gf_filter_pid_set_property(pid, GF_PROP_PID_TRACK_NUM, &PROP_UINT(track) );
457 :
458 : //Dolby Vision
459 1138 : if (m_subtype == GF_ISOM_SUBTYPE_DVHE) {
460 1 : GF_DOVIDecoderConfigurationRecord *dovi = gf_isom_dovi_config_get(read->mov, track, 1);
461 1 : if (dovi) {
462 1 : u8 *data = NULL;
463 1 : u32 size = 0;
464 1 : GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
465 1 : gf_odf_dovi_cfg_write_bs(dovi, bs);
466 1 : gf_bs_get_content(bs, &data, &size);
467 1 : gf_filter_pid_set_property(pid, GF_PROP_PID_DOLBY_VISION, &PROP_DATA_NO_COPY(data, size));
468 1 : gf_bs_del(bs);
469 1 : gf_odf_dovi_cfg_del(dovi);
470 : }
471 : }
472 :
473 : //create our channel
474 1138 : ch = isor_create_channel(read, pid, track, 0, (codec_id==GF_CODECID_LHVC) ? GF_TRUE : GF_FALSE);
475 :
476 1138 : if (lang_desc) {
477 279 : char *lang=NULL;
478 279 : gf_isom_get_media_language(read->mov, track, &lang);
479 : //s32 idx = gf_lang_find(lang);
480 279 : gf_filter_pid_set_property(pid, GF_PROP_PID_LANGUAGE, &PROP_STRING( lang ));
481 279 : if (lang) gf_free(lang);
482 279 : gf_odf_desc_del((GF_Descriptor *)lang_desc);
483 : lang_desc = NULL;
484 : }
485 :
486 :
487 1138 : if (has_scalable_layers)
488 9 : gf_filter_pid_set_property(pid, GF_PROP_PID_SCALABLE, &PROP_BOOL(GF_TRUE));
489 :
490 1138 : if (gf_isom_get_reference_count(read->mov, track, GF_ISOM_REF_SABT)>0) {
491 12 : gf_filter_pid_set_property(pid, GF_PROP_PID_TILE_BASE, &PROP_BOOL(GF_TRUE));
492 : }
493 :
494 1138 : if (srd_w && srd_h) {
495 81 : gf_filter_pid_set_property(pid, GF_PROP_PID_CROP_POS, &PROP_VEC2I_INT(srd_x, srd_y) );
496 81 : if (base_tile_track) {
497 81 : gf_isom_get_visual_info(read->mov, base_tile_track, stsd_idx, &w, &h);
498 81 : if (w && h) {
499 81 : gf_filter_pid_set_property(pid, GF_PROP_PID_ORIG_SIZE, &PROP_VEC2I_INT(w, h) );
500 : }
501 : }
502 : }
503 :
504 3414 : for (exp_refs=0; exp_refs<3; exp_refs++) {
505 3414 : u32 rtype = (exp_refs==2) ? GF_ISOM_REF_TBAS : exp_refs ? GF_ISOM_REF_SABT : GF_ISOM_REF_SCAL;
506 3414 : const char *rname = (exp_refs==2) ? "isom:tbas" : exp_refs ? "isom:sabt" : "isom:scal";
507 3414 : if (!exp_refs && (codec_id==GF_CODECID_LHVC))
508 0 : continue;
509 :
510 3414 : nb_refs = gf_isom_get_reference_count(read->mov, track, rtype);
511 3414 : if (nb_refs) {
512 : u32 j;
513 : GF_PropertyValue prop;
514 126 : prop.type = GF_PROP_4CC_LIST;
515 126 : prop.value.uint_list.nb_items = nb_refs;
516 126 : prop.value.uint_list.vals = gf_malloc(sizeof(u32)*nb_refs);
517 474 : for (j=0; j<nb_refs; j++) {
518 : u32 ref_tk;
519 222 : gf_isom_get_reference(read->mov, track, rtype, j+1, &ref_tk );
520 222 : prop.value.uint_list.vals[j] = gf_isom_get_track_id(read->mov, ref_tk);
521 : }
522 126 : gf_filter_pid_set_property_str(pid, rname, &prop);
523 126 : gf_free(prop.value.uint_list.vals);
524 : }
525 : }
526 :
527 1138 : ch->duration = gf_isom_get_track_duration(read->mov, ch->track);
528 1138 : if (!ch->duration) {
529 272 : ch->duration = gf_isom_get_duration(read->mov);
530 : }
531 1138 : sample_count = gf_isom_get_sample_count(read->mov, ch->track);
532 :
533 1138 : if (read->frag_type && !read->input_loaded) {
534 : u32 ts;
535 : u64 dur;
536 1 : if (gf_isom_get_sidx_duration(read->mov, &dur, &ts)==GF_OK) {
537 0 : dur *= read->time_scale;
538 0 : dur /= ts;
539 0 : ch->duration = dur;
540 : use_sidx_dur = GF_TRUE;
541 : sample_count = 0;
542 : }
543 : }
544 :
545 1138 : if (!read->mem_load_mode) {
546 : //if no edit list (whether complex or simple TS offset) and no sidx, use media duration
547 1134 : if (!ch->has_edit_list && !use_sidx_dur && !ch->ts_offset) {
548 : //no specific edit list type but edit present, use the duration in the edit
549 918 : if (gf_isom_get_edits_count(read->mov, ch->track)) {
550 34 : u64 dur = gf_isom_get_track_duration(read->mov, ch->track);
551 34 : gf_filter_pid_set_property(pid, GF_PROP_PID_DURATION, &PROP_FRAC64_INT(dur, read->time_scale));
552 : } else {
553 884 : u64 dur = gf_isom_get_media_duration(read->mov, ch->track);
554 884 : gf_filter_pid_set_property(pid, GF_PROP_PID_DURATION, &PROP_FRAC64_INT(dur, ch->time_scale));
555 : }
556 : }
557 : //otherwise trust track duration
558 : else {
559 216 : gf_filter_pid_set_property(pid, GF_PROP_PID_DURATION, &PROP_FRAC64_INT(ch->duration, read->time_scale));
560 : }
561 1134 : gf_filter_pid_set_property(pid, GF_PROP_PID_NB_FRAMES, &PROP_UINT(sample_count));
562 : }
563 :
564 1138 : if (sample_count && (streamtype==GF_STREAM_VISUAL)) {
565 564 : u64 mdur = gf_isom_get_media_duration(read->mov, track);
566 564 : mdur /= sample_count;
567 564 : gf_filter_pid_set_property(pid, GF_PROP_PID_FPS, &PROP_FRAC_INT(ch->time_scale, (u32) mdur));
568 : }
569 :
570 1138 : track_dur = (Double) (s64) ch->duration;
571 1138 : track_dur /= read->time_scale;
572 : //move channel duration in media timescale
573 1138 : ch->duration = (u64) (track_dur * ch->time_scale);
574 :
575 :
576 : //set stream subtype
577 1138 : mtype = gf_isom_get_media_type(read->mov, track);
578 1138 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_SUBTYPE, &PROP_4CC(mtype) );
579 :
580 1138 : if (!read->mem_load_mode) {
581 1134 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_MEDIA_DATA_SIZE, &PROP_LONGUINT(gf_isom_get_media_data_size(read->mov, track) ) );
582 : }
583 : //in no cache mode, depending on fetch speed we may have fetched a fragment or not, resulting in has_rap set
584 : //always for HAS_SYNC to false
585 4 : else if (gf_sys_is_test_mode() && !sample_count) {
586 1 : gf_filter_pid_set_property(pid, GF_PROP_PID_HAS_SYNC, &PROP_BOOL(GF_FALSE) );
587 : }
588 :
589 :
590 1138 : w = gf_isom_get_constant_sample_size(read->mov, track);
591 1138 : if (w)
592 106 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_FRAME_SIZE, &PROP_UINT(w));
593 :
594 1138 : if (read->mem_load_mode) {
595 4 : gf_filter_pid_set_property(pid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_NONE) );
596 : } else {
597 1134 : gf_filter_pid_set_property(pid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_REWIND) );
598 : }
599 :
600 : GF_PropertyValue brands;
601 1138 : brands.type = GF_PROP_4CC_LIST;
602 1138 : u32 major_brand=0;
603 1138 : gf_isom_get_brand_info(read->mov, &major_brand, NULL, &brands.value.uint_list.nb_items);
604 1138 : brands.value.uint_list.vals = (u32 *) gf_isom_get_brands(read->mov);
605 1138 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_BRANDS, &brands);
606 1138 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_MBRAND, &PROP_4CC(major_brand) );
607 :
608 : //we cannot expose average size/dur in mem mode with fragmented files (sample_count=0)
609 1138 : if (sample_count) {
610 883 : max_size = gf_isom_get_max_sample_size(read->mov, ch->track);
611 883 : if (max_size) gf_filter_pid_set_property(pid, GF_PROP_PID_MAX_FRAME_SIZE, &PROP_UINT(max_size) );
612 :
613 883 : max_size = gf_isom_get_avg_sample_size(read->mov, ch->track);
614 883 : if (max_size) gf_filter_pid_set_property(pid, GF_PROP_PID_AVG_FRAME_SIZE, &PROP_UINT(max_size) );
615 :
616 883 : max_size = gf_isom_get_max_sample_delta(read->mov, ch->track);
617 883 : if (max_size) gf_filter_pid_set_property(pid, GF_PROP_PID_MAX_TS_DELTA, &PROP_UINT(max_size) );
618 :
619 883 : max_size = gf_isom_get_max_sample_cts_offset(read->mov, ch->track);
620 883 : if (max_size) gf_filter_pid_set_property(pid, GF_PROP_PID_MAX_CTS_OFFSET, &PROP_UINT(max_size) );
621 :
622 883 : max_size = gf_isom_get_constant_sample_duration(read->mov, ch->track);
623 883 : if (max_size) gf_filter_pid_set_property(pid, GF_PROP_PID_CONSTANT_DURATION, &PROP_UINT(max_size) );
624 : }
625 :
626 :
627 : u32 media_pl=0;
628 1138 : if (streamtype==GF_STREAM_VISUAL) {
629 751 : media_pl = gf_isom_get_pl_indication(read->mov, GF_ISOM_PL_VISUAL);
630 387 : } else if (streamtype==GF_STREAM_AUDIO) {
631 277 : media_pl = gf_isom_get_pl_indication(read->mov, GF_ISOM_PL_AUDIO);
632 : }
633 1138 : if (media_pl && (media_pl!=0xFF) ) gf_filter_pid_set_property(pid, GF_PROP_PID_PROFILE_LEVEL, &PROP_UINT(media_pl) );
634 :
635 : #if !defined(GPAC_DISABLE_ISOM_WRITE)
636 1138 : e = gf_isom_get_track_template(read->mov, ch->track, &tk_template, &tk_template_size);
637 1138 : if (e == GF_OK) {
638 1138 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_TRACK_TEMPLATE, &PROP_DATA_NO_COPY(tk_template, tk_template_size) );
639 : } else {
640 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Failed to serialize track box: %s\n", gf_error_to_string(e) ));
641 : }
642 :
643 1138 : e = gf_isom_get_trex_template(read->mov, ch->track, &tk_template, &tk_template_size);
644 1138 : if (e == GF_OK) {
645 264 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_TREX_TEMPLATE, &PROP_DATA_NO_COPY(tk_template, tk_template_size) );
646 : }
647 :
648 1138 : e = gf_isom_get_raw_user_data(read->mov, &tk_template, &tk_template_size);
649 1138 : if (e==GF_OK) {
650 1138 : if (tk_template_size)
651 191 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_UDTA, &PROP_DATA_NO_COPY(tk_template, tk_template_size) );
652 : } else {
653 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Failed to serialize moov UDTA box: %s\n", gf_error_to_string(e) ));
654 : }
655 : #endif
656 :
657 : GF_Fraction64 moov_time;
658 1138 : moov_time.num = gf_isom_get_duration(read->mov);
659 1138 : moov_time.den = gf_isom_get_timescale(read->mov);
660 1138 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_MOVIE_TIME, &PROP_FRAC64(moov_time) );
661 :
662 :
663 : u32 i;
664 : s32 tx, ty;
665 : s16 l;
666 1138 : gf_isom_get_track_layout_info(read->mov, ch->track, &w, &h, &tx, &ty, &l);
667 1138 : if (w && h) {
668 809 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_WIDTH, &PROP_UINT(w) );
669 809 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_HEIGHT, &PROP_UINT(h) );
670 809 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_TRANS_X, &PROP_SINT(tx) );
671 809 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_TRANS_Y, &PROP_SINT(ty) );
672 809 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ZORDER, &PROP_SINT(l) );
673 : }
674 1138 : if (codec_id==GF_CODECID_TX3G) {
675 24 : u32 m_w = w;
676 24 : u32 m_h = h;
677 94 : for (i=0; i<gf_isom_get_track_count(read->mov); i++) {
678 46 : switch (gf_isom_get_media_type(read->mov, i+1)) {
679 11 : case GF_ISOM_MEDIA_SCENE:
680 : case GF_ISOM_MEDIA_VISUAL:
681 : case GF_ISOM_MEDIA_AUXV:
682 : case GF_ISOM_MEDIA_PICT:
683 11 : gf_isom_get_track_layout_info(read->mov, i+1, &w, &h, &tx, &ty, &l);
684 11 : if (w>m_w) m_w = w;
685 11 : if (h>m_h) m_h = h;
686 : break;
687 : default:
688 : break;
689 : }
690 : }
691 24 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_WIDTH_MAX, &PROP_UINT(m_w) );
692 24 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_HEIGHT_MAX, &PROP_UINT(m_h) );
693 : char *tx3g_config_sdp = NULL;
694 72 : for (i=0; i<gf_isom_get_sample_description_count(read->mov, ch->track); i++) {
695 : u8 *tx3g;
696 : u32 l1;
697 : u32 tx3g_len, len;
698 24 : e = gf_isom_text_get_encoded_tx3g(read->mov, ch->track, i+1, GF_RTP_TX3G_SIDX_OFFSET, &tx3g, &tx3g_len);
699 24 : if (e==GF_OK) {
700 : char buffer[2000];
701 24 : len = gf_base64_encode(tx3g, tx3g_len, buffer, 2000);
702 24 : gf_free(tx3g);
703 24 : buffer[len] = 0;
704 :
705 24 : l1 = tx3g_config_sdp ? (u32) strlen(tx3g_config_sdp) : 0;
706 24 : tx3g_config_sdp = gf_realloc(tx3g_config_sdp, len+3+l1);
707 24 : tx3g_config_sdp[l1] = 0;
708 24 : if (i) strcat(tx3g_config_sdp, ", ");
709 : strcat(tx3g_config_sdp, buffer);
710 : }
711 : }
712 24 : if (tx3g_config_sdp) {
713 24 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_DECODER_CONFIG_ENHANCEMENT, &PROP_STRING_NO_COPY(tx3g_config_sdp) );
714 : }
715 : }
716 :
717 : u32 idx=0;
718 6 : while (1) {
719 : u32 data_len, int_val2, flags;
720 : u64 int_val;
721 : const char *name;
722 : const u8 *data;
723 : GF_ISOiTunesTag itag;
724 : u32 itype = 0;
725 : s32 tag_idx;
726 :
727 1144 : e = gf_isom_apple_enum_tag(read->mov, idx, &itag, &data, &data_len, &int_val, &int_val2, &flags);
728 1144 : if (e) break;
729 6 : idx++;
730 :
731 6 : tag_idx = gf_itags_find_by_itag(itag);
732 6 : if (tag_idx>=0)
733 6 : itype = gf_itags_get_type(tag_idx);
734 :
735 6 : name = gf_itags_get_name(tag_idx);
736 6 : switch (itype) {
737 0 : case GF_ITAG_BOOL:
738 0 : gf_filter_pid_set_property_str(ch->pid, name, &PROP_BOOL((Bool) int_val ) );
739 0 : break;
740 0 : case GF_ITAG_INT8:
741 : case GF_ITAG_INT16:
742 : case GF_ITAG_INT32:
743 0 : gf_filter_pid_set_property_str(ch->pid, name, &PROP_UINT((u32) int_val ) );
744 0 : break;
745 0 : case GF_ITAG_INT64:
746 0 : gf_filter_pid_set_property_str(ch->pid, name, &PROP_LONGUINT(int_val) );
747 0 : break;
748 0 : case GF_ITAG_FRAC8:
749 : case GF_ITAG_FRAC6:
750 0 : gf_filter_pid_set_property_str(ch->pid, name, &PROP_FRAC_INT((s32) int_val, int_val2) );
751 0 : break;
752 0 : case GF_ITAG_FILE:
753 0 : if (data && data_len)
754 0 : gf_filter_pid_set_property_str(ch->pid, name, &PROP_DATA((u8 *)data, data_len) );
755 : break;
756 6 : default:
757 6 : if (data && data_len) {
758 6 : if (gf_utf8_is_legal(data, data_len))
759 6 : gf_filter_pid_set_property_str(ch->pid, name, &PROP_STRING(data) );
760 : else
761 0 : gf_filter_pid_set_property_str(ch->pid, name, &PROP_DATA((u8 *)data, data_len) );
762 : }
763 : break;
764 : }
765 : }
766 :
767 1138 : if (codec_id==GF_CODECID_TMCD) {
768 3 : u32 tmcd_flags=0, tmcd_fps_num=0, tmcd_fps_den=0, tmcd_fpt=0;
769 3 : gf_isom_get_tmcd_config(read->mov, track, stsd_idx, &tmcd_flags, &tmcd_fps_num, &tmcd_fps_den, &tmcd_fpt);
770 3 : gf_filter_pid_set_property_str(ch->pid, "tmcd:flags", &PROP_UINT(tmcd_flags) );
771 3 : gf_filter_pid_set_property_str(ch->pid, "tmcd:framerate", &PROP_FRAC_INT(tmcd_fps_num, tmcd_fps_den) );
772 3 : gf_filter_pid_set_property_str(ch->pid, "tmcd:frames_per_tick", &PROP_UINT(tmcd_fpt) );
773 :
774 : }
775 :
776 1138 : if (gf_sys_old_arch_compat()) {
777 : Bool gf_isom_has_time_offset_table(GF_ISOFile *the_file, u32 trackNumber);
778 1114 : if (gf_isom_has_time_offset_table(read->mov, ch->track))
779 228 : gf_filter_pid_set_property_str(ch->pid, "isom_force_ctts", &PROP_BOOL(GF_TRUE) );
780 : }
781 :
782 1138 : if (!gf_sys_is_test_mode()) {
783 : u32 nb_udta;
784 23 : const char *hdlr = NULL;
785 23 : gf_isom_get_handler_name(read->mov, ch->track, &hdlr);
786 23 : if (hdlr)
787 23 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_HANDLER, &PROP_STRING(hdlr));
788 :
789 23 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_TRACK_FLAGS, &PROP_UINT( gf_isom_get_track_flags(read->mov, ch->track) ));
790 :
791 23 : if (streamtype==GF_STREAM_VISUAL) {
792 : GF_PropertyValue p;
793 : u32 vals[9];
794 : memset(vals, 0, sizeof(u32)*9);
795 : memset(&p, 0, sizeof(GF_PropertyValue));
796 22 : p.type = GF_PROP_UINT_LIST;
797 22 : p.value.uint_list.nb_items = 9;
798 22 : p.value.uint_list.vals = vals;
799 22 : gf_isom_get_track_matrix(read->mov, ch->track, vals);
800 22 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_TRACK_MATRIX, &p);
801 : }
802 :
803 :
804 23 : nb_udta = gf_isom_get_udta_count(read->mov, ch->track);
805 23 : if (nb_udta) {
806 0 : for (i=0; i<nb_udta; i++) {
807 : u32 j, type, nb_items;
808 : bin128 uuid;
809 0 : gf_isom_get_udta_type(read->mov, ch->track, i+1, &type, &uuid);
810 0 : nb_items = gf_isom_get_user_data_count(read->mov, ch->track, type, uuid);
811 : //we only export 4CC udta boxes
812 0 : if (!type) continue;
813 :
814 0 : for (j=0; j<nb_items; j++) {
815 : char szName[31];
816 0 : u8 *udta=NULL;
817 : u32 udta_size;
818 0 : gf_isom_get_user_data(read->mov, ch->track, type, uuid, j+1, &udta, &udta_size);
819 0 : if (!udta) continue;
820 0 : if (nb_items>1)
821 0 : snprintf(szName, 30, "udta_%s_%d", gf_4cc_to_str(type), j+1);
822 : else
823 0 : snprintf(szName, 30, "udta_%s", gf_4cc_to_str(type));
824 0 : szName[30]=0;
825 0 : if (gf_utf8_is_legal(udta, udta_size)) {
826 0 : gf_filter_pid_set_property_dyn(ch->pid, szName, &PROP_STRING_NO_COPY(udta));
827 : } else {
828 0 : gf_filter_pid_set_property_dyn(ch->pid, szName, &PROP_DATA_NO_COPY(udta, udta_size));
829 : }
830 : }
831 : }
832 : }
833 : }
834 : }
835 :
836 : //update decoder configs
837 1195 : ch->check_avc_ps = ch->check_hevc_ps = ch->check_vvc_ps = GF_FALSE;
838 1195 : if (ch->avcc) gf_odf_avc_cfg_del(ch->avcc);
839 1195 : ch->avcc = NULL;
840 1195 : if (ch->hvcc) gf_odf_hevc_cfg_del(ch->hvcc);
841 1195 : ch->hvcc = NULL;
842 1195 : if (ch->vvcc) gf_odf_vvc_cfg_del(ch->vvcc);
843 1195 : ch->vvcc = NULL;
844 :
845 1195 : if (lang_desc) {
846 0 : gf_odf_desc_del((GF_Descriptor *)lang_desc);
847 : lang_desc = NULL;
848 : }
849 :
850 1195 : if (read->smode != MP4DMX_SINGLE) {
851 1195 : if ((codec_id==GF_CODECID_LHVC) || (codec_id==GF_CODECID_HEVC)) {
852 88 : Bool signal_lhv = (read->smode==MP4DMX_SPLIT) ? GF_TRUE : GF_FALSE;
853 88 : GF_HEVCConfig *hvcc = gf_isom_hevc_config_get(read->mov, track, stsd_idx);
854 88 : GF_HEVCConfig *lhcc = gf_isom_lhvc_config_get(read->mov, track, stsd_idx);
855 :
856 88 : if (hvcc || lhcc) {
857 86 : if (dsi) gf_free(dsi);
858 86 : dsi = NULL;
859 : //no base layer config
860 86 : if (!hvcc) signal_lhv = GF_TRUE;
861 :
862 86 : if (signal_lhv && lhcc) {
863 3 : if (hvcc) {
864 3 : hvcc->is_lhvc = GF_FALSE;
865 3 : gf_odf_hevc_cfg_write(hvcc, &dsi, &dsi_size);
866 : }
867 3 : lhcc->is_lhvc = GF_TRUE;
868 3 : gf_odf_hevc_cfg_write(lhcc, &enh_dsi, &enh_dsi_size);
869 : codec_id = GF_CODECID_LHVC;
870 : } else {
871 83 : if (hvcc) {
872 83 : hvcc->is_lhvc = GF_FALSE;
873 83 : gf_odf_hevc_cfg_write(hvcc, &dsi, &dsi_size);
874 : }
875 83 : if (lhcc) {
876 2 : lhcc->is_lhvc = GF_TRUE;
877 2 : gf_odf_hevc_cfg_write(lhcc, &enh_dsi, &enh_dsi_size);
878 : }
879 : codec_id = GF_CODECID_HEVC;
880 : }
881 : }
882 88 : if (hvcc) gf_odf_hevc_cfg_del(hvcc);
883 88 : if (lhcc) gf_odf_hevc_cfg_del(lhcc);
884 : }
885 1195 : if ((codec_id==GF_CODECID_AVC) || (codec_id==GF_CODECID_SVC) || (codec_id==GF_CODECID_MVC)) {
886 : Bool is_mvc = GF_FALSE;
887 422 : Bool signal_svc = (read->smode==MP4DMX_SPLIT) ? GF_TRUE : GF_FALSE;
888 422 : GF_AVCConfig *avcc = gf_isom_avc_config_get(read->mov, track, stsd_idx);
889 422 : GF_AVCConfig *svcc = gf_isom_svc_config_get(read->mov, track, stsd_idx);
890 422 : if (!svcc) {
891 415 : svcc = gf_isom_mvc_config_get(read->mov, track, stsd_idx);
892 : is_mvc = GF_TRUE;
893 : }
894 :
895 422 : if (avcc || svcc) {
896 420 : if (dsi) gf_free(dsi);
897 420 : dsi = NULL;
898 : //no base layer config
899 420 : if (!avcc) signal_svc = GF_TRUE;
900 :
901 420 : if (signal_svc && svcc) {
902 7 : if (avcc) {
903 1 : gf_odf_avc_cfg_write(avcc, &dsi, &dsi_size);
904 : }
905 7 : gf_odf_avc_cfg_write(svcc, &enh_dsi, &enh_dsi_size);
906 7 : codec_id = is_mvc ? GF_CODECID_MVC : GF_CODECID_SVC;
907 : } else {
908 413 : if (avcc) {
909 413 : gf_odf_avc_cfg_write(avcc, &dsi, &dsi_size);
910 : }
911 413 : if (svcc) {
912 0 : gf_odf_avc_cfg_write(svcc, &enh_dsi, &enh_dsi_size);
913 : }
914 : codec_id = GF_CODECID_AVC;
915 : }
916 : }
917 422 : if (avcc) gf_odf_avc_cfg_del(avcc);
918 422 : if (svcc) gf_odf_avc_cfg_del(svcc);
919 : }
920 :
921 1195 : if (!gf_sys_is_test_mode()) {
922 : u64 create_date, modif_date;
923 23 : gf_isom_get_creation_time(read->mov, &create_date, &modif_date);
924 23 : gf_filter_pid_set_property_str(ch->pid, "isom:creation_date", &PROP_LONGUINT(create_date));
925 23 : gf_filter_pid_set_property_str(ch->pid, "isom:modification_date", &PROP_LONGUINT(modif_date));
926 : }
927 :
928 : }
929 :
930 : //all stsd specific init/reconfig
931 1195 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_CODECID, &PROP_UINT(codec_id));
932 1195 : if (dsi) {
933 931 : ch->dsi_crc = gf_crc_32(dsi, dsi_size);
934 931 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA_NO_COPY(dsi, dsi_size));
935 : }
936 1195 : if (enh_dsi) {
937 12 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_DECODER_CONFIG_ENHANCEMENT, &PROP_DATA_NO_COPY(enh_dsi, enh_dsi_size));
938 : }
939 1195 : if (audio_fmt) {
940 29 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(audio_fmt));
941 29 : if (codec_id == GF_CODECID_RAW) {
942 29 : gf_isom_enable_raw_pack(read->mov, track, read->frame_size);
943 : }
944 : }
945 1195 : if (pix_fmt) {
946 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_PIXFMT, &PROP_UINT(pix_fmt));
947 : }
948 :
949 1195 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_CONFIG_IDX, &PROP_UINT(stsd_idx) );
950 :
951 1195 : w = h = 0;
952 1195 : gf_isom_get_visual_info(read->mov, track, stsd_idx, &w, &h);
953 1195 : if (w && h) {
954 : GF_ISOM_Y3D_Info yt3d;
955 : u32 hspace, vspace;
956 826 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_WIDTH, &PROP_UINT(w));
957 826 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_HEIGHT, &PROP_UINT(h));
958 :
959 826 : gf_isom_get_pixel_aspect_ratio(read->mov, track, stsd_idx, &hspace, &vspace);
960 826 : if (hspace != vspace)
961 4 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_SAR, &PROP_FRAC_INT(hspace, vspace) );
962 :
963 :
964 826 : e = gf_isom_get_y3d_info(ch->owner->mov, ch->track, stsd_idx, &yt3d);
965 826 : if (e==GF_OK) {
966 0 : if (yt3d.stereo_type) {
967 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_STEREO_TYPE, &PROP_UINT(yt3d.stereo_type));
968 : } else {
969 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_STEREO_TYPE, NULL);
970 : }
971 :
972 0 : if (yt3d.projection_type) {
973 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_PROJECTION_TYPE, &PROP_UINT(yt3d.projection_type));
974 0 : if (yt3d.projection_type==GF_PROJ360_CUBE_MAP) {
975 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_CUBE_MAP_PAD, yt3d.padding ? &PROP_UINT(yt3d.padding) : NULL);
976 : }
977 0 : else if (yt3d.projection_type==GF_PROJ360_EQR) {
978 0 : if (yt3d.top || yt3d.bottom || yt3d.left || yt3d.right)
979 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_EQR_CLAMP, &PROP_VEC4I_INT(yt3d.top, yt3d.bottom , yt3d.left , yt3d.right));
980 : else
981 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_EQR_CLAMP, NULL);
982 : }
983 : } else {
984 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_PROJECTION_TYPE, NULL);
985 : }
986 0 : if (yt3d.pose_present) {
987 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_VR_POSE, &PROP_VEC3I_INT(yt3d.yaw, yt3d.pitch, yt3d.roll) );
988 : } else {
989 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_VR_POSE, NULL);
990 : }
991 : }
992 : }
993 1195 : sr = nb_ch = nb_bps = 0;
994 1195 : gf_isom_get_audio_info(read->mov,track, stsd_idx, &sr, &nb_ch, &nb_bps);
995 1195 : if (streamtype==GF_STREAM_AUDIO) {
996 277 : if (!sr) sr = gf_isom_get_media_timescale(read->mov, track);
997 : }
998 : //nb_ch may be set to 0 for "not applicable" (3D / object coding audio)
999 1195 : if (sr) {
1000 : u32 d1, d2;
1001 277 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT(sr));
1002 277 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(nb_ch));
1003 :
1004 : //to remove once we deprecate master
1005 277 : if (!gf_sys_old_arch_compat()) {
1006 : GF_AudioChannelLayout layout;
1007 1 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_AUDIO_BPS, &PROP_UINT(nb_bps));
1008 :
1009 1 : if (gf_isom_get_audio_layout(read->mov, track, stsd_idx, &layout)==GF_OK) {
1010 0 : if (layout.definedLayout) {
1011 0 : u64 lay = gf_audio_fmt_get_layout_from_cicp(layout.definedLayout);
1012 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_CHANNEL_LAYOUT, &PROP_LONGUINT(lay));
1013 : }
1014 :
1015 : }
1016 :
1017 : }
1018 :
1019 277 : if (first_config ) {
1020 277 : d1 = gf_isom_get_sample_duration(read->mov, ch->track, 1);
1021 277 : d2 = gf_isom_get_sample_duration(read->mov, ch->track, 2);
1022 277 : if (d1 && d2 && (d1==d2)) {
1023 207 : d1 *= sr;
1024 207 : d1 /= ch->time_scale;
1025 207 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_SAMPLES_PER_FRAME, &PROP_UINT(d1));
1026 : }
1027 : }
1028 :
1029 277 : if ((codec_id==GF_CODECID_MPHA) || (codec_id==GF_CODECID_MHAS)) {
1030 : u32 nb_profiles;
1031 1 : const u8 *prof_compat = gf_isom_get_mpegh_compatible_profiles(read->mov, ch->track, stsd_idx, &nb_profiles);
1032 1 : if (prof_compat) {
1033 : u32 j;
1034 : GF_PropertyValue prop;
1035 0 : prop.type = GF_PROP_UINT_LIST;
1036 0 : prop.value.uint_list.nb_items = nb_profiles;
1037 0 : prop.value.uint_list.vals = gf_malloc(sizeof(u32)*nb_profiles);
1038 0 : for (j=0; j<nb_profiles; j++)
1039 0 : prop.value.uint_list.vals[j] = prof_compat[j];
1040 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_MHA_COMPATIBLE_PROFILES, &prop);
1041 0 : gf_free(prop.value.uint_list.vals);
1042 : }
1043 : }
1044 : }
1045 :
1046 :
1047 1195 : gf_isom_get_bitrate(read->mov, ch->track, stsd_idx, &avg_rate, &max_rate, &buffer_size);
1048 :
1049 1195 : if (!avg_rate) {
1050 184 : if (first_config && ch->duration) {
1051 91 : u64 avgrate = 8 * gf_isom_get_media_data_size(read->mov, ch->track);
1052 91 : avgrate = (u64) (avgrate / track_dur);
1053 91 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_BITRATE, &PROP_UINT((u32) avgrate));
1054 : }
1055 : } else {
1056 1011 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_BITRATE, &PROP_UINT((u32) avg_rate));
1057 1011 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_MAXRATE, &PROP_UINT((u32) max_rate));
1058 1011 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_DBSIZE, &PROP_UINT((u32) buffer_size));
1059 : }
1060 :
1061 1195 : if (mime) gf_filter_pid_set_property_str(ch->pid, "meta:mime", &PROP_STRING(mime) );
1062 1195 : if (encoding) gf_filter_pid_set_property_str(ch->pid, "meta:encoding", &PROP_STRING(encoding) );
1063 1195 : if (namespace) gf_filter_pid_set_property_str(ch->pid, "meta:xmlns", &PROP_STRING(namespace) );
1064 1195 : if (schemaloc) gf_filter_pid_set_property_str(ch->pid, "meta:schemaloc", &PROP_STRING(schemaloc) );
1065 1195 : if (mime_cfg) gf_filter_pid_set_property_str(ch->pid, "meta:mime", &PROP_STRING(mime_cfg) );
1066 1195 : else if ((m_subtype==GF_ISOM_SUBTYPE_STPP) && namespace && strstr(namespace, "ns/ttml")) {
1067 : mime_cfg = "application/ttml+xml;codecs=im1t";
1068 10 : if (gf_isom_sample_has_subsamples(read->mov, track, 0, 0) )
1069 : mime_cfg = "application/ttml+xml;codecs=im1i";
1070 10 : gf_filter_pid_set_property_str(ch->pid, "meta:mime", &PROP_STRING(mime_cfg) );
1071 : }
1072 :
1073 1195 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_SUBTYPE, &PROP_4CC(m_subtype) );
1074 1195 : if (stxtcfg) gf_filter_pid_set_property(ch->pid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA((char *)stxtcfg, (u32) strlen(stxtcfg) ));
1075 :
1076 :
1077 : #if !defined(GPAC_DISABLE_ISOM_WRITE)
1078 1195 : tk_template=NULL;
1079 1195 : tk_template_size=0;
1080 1195 : e = gf_isom_get_stsd_template(read->mov, ch->track, stsd_idx, &tk_template, &tk_template_size);
1081 1195 : if (e == GF_OK) {
1082 1195 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_STSD_TEMPLATE, &PROP_DATA_NO_COPY(tk_template, tk_template_size) );
1083 : } else {
1084 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Failed to serialize stsd box: %s\n", gf_error_to_string(e) ));
1085 : }
1086 : #endif
1087 :
1088 1195 : if (codec_id == GF_CODECID_DIMS) {
1089 : GF_DIMSDescription dims;
1090 : memset(&dims, 0, sizeof(GF_DIMSDescription));
1091 :
1092 2 : gf_isom_get_dims_description(read->mov, ch->track, stsd_idx, &dims);
1093 2 : gf_filter_pid_set_property_str(ch->pid, "dims:profile", &PROP_UINT(dims.profile));
1094 2 : gf_filter_pid_set_property_str(ch->pid, "dims:level", &PROP_UINT(dims.level));
1095 2 : gf_filter_pid_set_property_str(ch->pid, "dims:pathComponents", &PROP_UINT(dims.pathComponents));
1096 2 : gf_filter_pid_set_property_str(ch->pid, "dims:fullRequestHost", &PROP_BOOL(dims.fullRequestHost));
1097 2 : gf_filter_pid_set_property_str(ch->pid, "dims:streamType", &PROP_BOOL(dims.streamType));
1098 2 : gf_filter_pid_set_property_str(ch->pid, "dims:redundant", &PROP_BOOL(dims.containsRedundant));
1099 2 : if (dims.content_script_types)
1100 0 : gf_filter_pid_set_property_str(ch->pid, "dims:scriptTypes", &PROP_STRING(dims.content_script_types));
1101 2 : if (dims.textEncoding)
1102 2 : gf_filter_pid_set_property_str(ch->pid, "meta:encoding", &PROP_STRING(dims.textEncoding));
1103 2 : if (dims.contentEncoding)
1104 2 : gf_filter_pid_set_property_str(ch->pid, "meta:content_encoding", &PROP_STRING(dims.contentEncoding));
1105 2 : if (dims.xml_schema_loc)
1106 0 : gf_filter_pid_set_property_str(ch->pid, "meta:schemaloc", &PROP_STRING(dims.xml_schema_loc));
1107 2 : if (dims.mime_type)
1108 0 : gf_filter_pid_set_property_str(ch->pid, "meta:mime", &PROP_STRING(dims.mime_type));
1109 : }
1110 1193 : else if (codec_id==GF_CODECID_AVC)
1111 415 : ch->check_avc_ps = (ch->owner->xps_check==MP4DMX_XPS_REMOVE) ? GF_TRUE : GF_FALSE;
1112 778 : else if (codec_id==GF_CODECID_HEVC)
1113 85 : ch->check_hevc_ps = (ch->owner->xps_check==MP4DMX_XPS_REMOVE) ? GF_TRUE : GF_FALSE;
1114 693 : else if (codec_id==GF_CODECID_VVC)
1115 0 : ch->check_vvc_ps = (ch->owner->xps_check==MP4DMX_XPS_REMOVE) ? GF_TRUE : GF_FALSE;
1116 693 : else if (codec_id==GF_CODECID_MHAS) {
1117 1 : if (!dsi) {
1118 1 : ch->check_mhas_pl = GF_TRUE;
1119 1 : GF_ISOSample *samp = gf_isom_get_sample(ch->owner->mov, ch->track, 1, NULL);
1120 1 : if (samp) {
1121 1 : u64 ch_layout=0;
1122 1 : s32 PL = gf_mpegh_get_mhas_pl(samp->data, samp->dataLength, &ch_layout);
1123 1 : if (PL>0) {
1124 1 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_PROFILE_LEVEL, &PROP_UINT((u32) PL));
1125 1 : ch->check_mhas_pl = GF_FALSE;
1126 1 : if (ch_layout)
1127 1 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_CHANNEL_LAYOUT, &PROP_LONGUINT(ch_layout));
1128 : }
1129 1 : gf_isom_sample_del(&samp);
1130 : }
1131 : }
1132 : }
1133 :
1134 1195 : if (udesc) {
1135 0 : gf_filter_pid_set_property_str(ch->pid, "codec_vendor", &PROP_UINT(udesc->vendor_code));
1136 0 : gf_filter_pid_set_property_str(ch->pid, "codec_version", &PROP_UINT(udesc->version));
1137 0 : gf_filter_pid_set_property_str(ch->pid, "codec_revision", &PROP_UINT(udesc->revision));
1138 0 : gf_filter_pid_set_property_str(ch->pid, "compressor_name", &PROP_STRING(udesc->compressor_name));
1139 0 : gf_filter_pid_set_property_str(ch->pid, "temporal_quality", &PROP_UINT(udesc->temporal_quality));
1140 0 : gf_filter_pid_set_property_str(ch->pid, "spatial_quality", &PROP_UINT(udesc->spatial_quality));
1141 0 : if (udesc->h_res) {
1142 0 : gf_filter_pid_set_property_str(ch->pid, "hres", &PROP_UINT(udesc->h_res));
1143 0 : gf_filter_pid_set_property_str(ch->pid, "vres", &PROP_UINT(udesc->v_res));
1144 0 : } else if (udesc->nb_channels) {
1145 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(udesc->nb_channels));
1146 0 : switch (udesc->bits_per_sample) {
1147 0 : case 8:
1148 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_U8));
1149 0 : break;
1150 0 : case 16:
1151 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_S16));
1152 0 : break;
1153 0 : case 24:
1154 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_S24));
1155 0 : break;
1156 0 : case 32:
1157 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_S32));
1158 0 : break;
1159 0 : default:
1160 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Track %d unsupported audio bit depth %d\n", track, udesc->bits_per_sample ));
1161 : break;
1162 : }
1163 0 : }
1164 0 : gf_filter_pid_set_property(ch->pid, GF_PROP_PID_BIT_DEPTH_Y, &PROP_UINT(udesc->depth));
1165 :
1166 0 : gf_free(udesc);
1167 : }
1168 :
1169 :
1170 1195 : if (ch->check_avc_ps) {
1171 331 : ch->avcc = gf_isom_avc_config_get(ch->owner->mov, ch->track, ch->last_sample_desc_index ? ch->last_sample_desc_index : 1);
1172 : }
1173 864 : else if (ch->check_hevc_ps) {
1174 63 : ch->hvcc = gf_isom_hevc_config_get(ch->owner->mov, ch->track, ch->last_sample_desc_index ? ch->last_sample_desc_index : 1);
1175 : }
1176 801 : else if (ch->check_vvc_ps) {
1177 0 : ch->vvcc = gf_isom_vvc_config_get(ch->owner->mov, ch->track, ch->last_sample_desc_index ? ch->last_sample_desc_index : 1);
1178 : }
1179 : }
1180 :
1181 57 : void isor_update_channel_config(ISOMChannel *ch)
1182 : {
1183 57 : isor_declare_track(ch->owner, ch, ch->track, ch->last_sample_desc_index, GF_STREAM_UNKNOWN, GF_FALSE);
1184 :
1185 57 : }
1186 :
1187 947 : GF_Err isor_declare_objects(ISOMReader *read)
1188 : {
1189 : const u8 *tag;
1190 : u32 tlen;
1191 : u32 i, count, j, track_id;
1192 : Bool highest_stream;
1193 : Bool single_media_found = GF_FALSE;
1194 : Bool use_iod = GF_FALSE;
1195 : GF_Err e;
1196 : Bool isom_contains_video = GF_FALSE;
1197 947 : GF_Descriptor *od = gf_isom_get_root_od(read->mov);
1198 947 : if (od && gf_list_count(((GF_ObjectDescriptor*)od)->ESDescriptors)) {
1199 : use_iod = GF_TRUE;
1200 : }
1201 947 : if (od) gf_odf_desc_del(od);
1202 :
1203 : /*TODO
1204 : check for alternate tracks
1205 : */
1206 947 : count = gf_isom_get_track_count(read->mov);
1207 3027 : for (i=0; i<count; i++) {
1208 : u32 mtype, m_subtype, streamtype, stsd_idx;
1209 :
1210 1168 : mtype = gf_isom_get_media_type(read->mov, i+1);
1211 :
1212 1168 : if (read->tkid) {
1213 51 : u32 for_id=0;
1214 51 : if (sscanf(read->tkid, "%d", &for_id)) {
1215 0 : u32 id = gf_isom_get_track_id(read->mov, i+1);
1216 16 : if (id != for_id) continue;
1217 51 : } else if (!strcmp(read->tkid, "audio")) {
1218 32 : if (mtype!=GF_ISOM_MEDIA_AUDIO) continue;
1219 19 : } else if (!strcmp(read->tkid, "video")) {
1220 19 : if (mtype!=GF_ISOM_MEDIA_VISUAL) continue;
1221 0 : } else if (strlen(read->tkid)==4) {
1222 0 : u32 t = GF_4CC(read->tkid[0], read->tkid[1], read->tkid[2], read->tkid[3]);
1223 0 : if (mtype!=t) continue;
1224 : } else {
1225 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[IsoMedia] Bad format for tkid option %s, no match\n", read->tkid));
1226 0 : return GF_BAD_PARAM;
1227 : }
1228 : }
1229 :
1230 1152 : switch (mtype) {
1231 : case GF_ISOM_MEDIA_AUDIO:
1232 : streamtype = GF_STREAM_AUDIO;
1233 : break;
1234 751 : case GF_ISOM_MEDIA_VISUAL:
1235 : case GF_ISOM_MEDIA_AUXV:
1236 : case GF_ISOM_MEDIA_PICT:
1237 : case GF_ISOM_MEDIA_QTVR:
1238 : streamtype = GF_STREAM_VISUAL;
1239 : isom_contains_video = GF_TRUE;
1240 751 : break;
1241 61 : case GF_ISOM_MEDIA_TEXT:
1242 : case GF_ISOM_MEDIA_SUBT:
1243 : case GF_ISOM_MEDIA_SUBPIC:
1244 : case GF_ISOM_MEDIA_MPEG_SUBT:
1245 : case GF_ISOM_MEDIA_CLOSED_CAPTION:
1246 : streamtype = GF_STREAM_TEXT;
1247 61 : break;
1248 24 : case GF_ISOM_MEDIA_FLASH:
1249 : case GF_ISOM_MEDIA_DIMS:
1250 : case GF_ISOM_MEDIA_SCENE:
1251 : streamtype = GF_STREAM_SCENE;
1252 24 : break;
1253 12 : case GF_ISOM_MEDIA_OD:
1254 : streamtype = GF_STREAM_OD;
1255 12 : break;
1256 19 : case GF_ISOM_MEDIA_META:
1257 : case GF_ISOM_MEDIA_TIMECODE:
1258 : streamtype = GF_STREAM_METADATA;
1259 19 : break;
1260 : /*hint tracks are never exported*/
1261 0 : case GF_ISOM_MEDIA_HINT:
1262 0 : continue;
1263 0 : default:
1264 0 : if (!read->allt) {
1265 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Track %d type %s not supported, ignoring track - you may retry by specifying allt option\n", i+1, gf_4cc_to_str(mtype) ));
1266 0 : continue;
1267 : }
1268 : streamtype = GF_STREAM_UNKNOWN;
1269 : break;
1270 : }
1271 :
1272 1152 : if (!read->alltk && !read->tkid && !gf_isom_is_track_enabled(read->mov, i+1)) {
1273 0 : if (count>1) {
1274 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Track %d is disabled, ignoring track - you may retry by specifying alltk option\n", i+1));
1275 0 : continue;
1276 : } else {
1277 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Track %d is disabled but single track in file, considering it enabled\n", i+1 ));
1278 : }
1279 : }
1280 :
1281 1152 : stsd_idx = read->stsd ? read->stsd : 1;
1282 : //some subtypes are not declared as readable objects
1283 1152 : m_subtype = gf_isom_get_media_subtype(read->mov, i+1, stsd_idx);
1284 1152 : switch (m_subtype) {
1285 105 : case GF_ISOM_SUBTYPE_HVT1:
1286 105 : if (read->smode == MP4DMX_SINGLE)
1287 0 : continue;
1288 :
1289 : break;
1290 : default:
1291 : break;
1292 : }
1293 :
1294 : /*we declare only the highest video track (i.e the track we play)*/
1295 : highest_stream = GF_TRUE;
1296 1152 : track_id = gf_isom_get_track_id(read->mov, i+1);
1297 1152 : if (read->play_only_track_id && (read->play_only_track_id != track_id)) continue;
1298 :
1299 1152 : if (read->play_only_first_media) {
1300 11 : if (read->play_only_first_media != mtype) continue;
1301 1 : if (single_media_found) continue;
1302 : single_media_found = GF_TRUE;
1303 : }
1304 :
1305 5103 : for (j = 0; j < count; j++) {
1306 2828 : if (gf_isom_has_track_reference(read->mov, j+1, GF_ISOM_REF_SCAL, track_id) > 0) {
1307 : highest_stream = GF_FALSE;
1308 : break;
1309 : }
1310 2819 : if (gf_isom_has_track_reference(read->mov, j+1, GF_ISOM_REF_BASE, track_id) > 0) {
1311 : highest_stream = GF_FALSE;
1312 : break;
1313 : }
1314 : }
1315 :
1316 1142 : if ((read->smode==MP4DMX_SINGLE) && (gf_isom_get_media_type(read->mov, i+1) == GF_ISOM_MEDIA_VISUAL) && !highest_stream)
1317 0 : continue;
1318 :
1319 :
1320 1142 : isor_declare_track(read, NULL, i+1, stsd_idx, streamtype, use_iod);
1321 :
1322 1142 : if (read->tkid)
1323 : break;
1324 : }
1325 :
1326 947 : if (!read->tkid) {
1327 : /*declare image items*/
1328 912 : count = gf_isom_get_meta_item_count(read->mov, GF_TRUE, 0);
1329 1879 : for (i=0; i<count; i++) {
1330 59 : if (! isor_declare_item_properties(read, NULL, i+1))
1331 13 : continue;
1332 :
1333 46 : if (read->itt) break;
1334 : }
1335 : }
1336 :
1337 : /*if cover art, declare a video pid*/
1338 947 : if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_COVER_ART, &tag, &tlen)==GF_OK) {
1339 :
1340 : /*write cover data*/
1341 : assert(!(tlen & 0x80000000));
1342 0 : tlen &= 0x7FFFFFFF;
1343 :
1344 0 : if (read->expart && !isom_contains_video) {
1345 0 : GF_FilterPid *cover_pid=NULL;
1346 0 : e = gf_filter_pid_raw_new(read->filter, NULL, NULL, NULL, NULL, (char *) tag, tlen, GF_FALSE, &cover_pid);
1347 0 : if (e) {
1348 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[MP3Dmx] error setting up video pid for cover art: %s\n", gf_error_to_string(e) ));
1349 : }
1350 0 : if (cover_pid) {
1351 : u8 *out_buffer;
1352 : GF_FilterPacket *dst_pck;
1353 0 : gf_filter_pid_set_property(cover_pid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_FILE) );
1354 0 : gf_filter_pid_set_name(cover_pid, "CoverArt");
1355 0 : dst_pck = gf_filter_pck_new_alloc(cover_pid, tlen, &out_buffer);
1356 0 : if (dst_pck) {
1357 0 : gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
1358 0 : memcpy(out_buffer, tag, tlen);
1359 0 : gf_filter_pck_send(dst_pck);
1360 : }
1361 0 : gf_filter_pid_set_eos(cover_pid);
1362 : }
1363 : }
1364 : }
1365 : return GF_OK;
1366 : }
1367 :
1368 89 : Bool isor_declare_item_properties(ISOMReader *read, ISOMChannel *ch, u32 item_idx)
1369 : {
1370 : GF_ImageItemProperties props;
1371 : GF_FilterPid *pid;
1372 : GF_ESD *esd;
1373 89 : u32 item_id=0;
1374 89 : u32 scheme_type=0, scheme_version=0, item_type;
1375 : const char *item_name, *item_mime_type, *item_encoding;
1376 :
1377 89 : if (item_idx>gf_isom_get_meta_item_count(read->mov, GF_TRUE, 0))
1378 : return GF_FALSE;
1379 :
1380 85 : item_name = item_mime_type = item_encoding = NULL;
1381 85 : gf_isom_get_meta_item_info(read->mov, GF_TRUE, 0, item_idx, &item_id, &item_type, &scheme_type, &scheme_version, NULL, NULL, NULL, &item_name, &item_mime_type, &item_encoding);
1382 :
1383 85 : if (!item_id) return GF_FALSE;
1384 85 : if (item_type==GF_ISOM_ITEM_TYPE_AUXI) return GF_FALSE;
1385 :
1386 72 : gf_isom_get_meta_image_props(read->mov, GF_TRUE, 0, item_id, &props);
1387 :
1388 : //check we support the protection scheme
1389 72 : switch (scheme_type) {
1390 : case GF_ISOM_CBC_SCHEME:
1391 : case GF_ISOM_CENS_SCHEME:
1392 : case GF_ISOM_CBCS_SCHEME:
1393 : case GF_ISOM_CENC_SCHEME:
1394 : case GF_ISOM_PIFF_SCHEME:
1395 : case 0:
1396 : break;
1397 : default:
1398 : return GF_FALSE;
1399 : }
1400 :
1401 :
1402 72 : esd = gf_media_map_item_esd(read->mov, item_id);
1403 72 : if (!esd) return GF_FALSE;
1404 :
1405 :
1406 : //OK declare PID
1407 72 : if (!ch)
1408 46 : pid = gf_filter_pid_new(read->filter);
1409 : else {
1410 26 : pid = ch->pid;
1411 26 : ch->item_id = item_id;
1412 : }
1413 :
1414 :
1415 : //do not override PID ID if itt is set
1416 72 : if (!ch) {
1417 46 : if (read->pid)
1418 23 : gf_filter_pid_copy_properties(pid, read->pid);
1419 46 : gf_filter_pid_set_property(pid, GF_PROP_PID_ID, &PROP_UINT(esd->ESID));
1420 : }
1421 :
1422 72 : if (read->itemid)
1423 72 : gf_filter_pid_set_property(pid, GF_PROP_PID_ITEM_ID, &PROP_UINT(item_id));
1424 :
1425 : //TODO: no support for LHEVC images
1426 : //gf_filter_pid_set_property(pid, GF_PROP_PID_DEPENDENCY_ID, &PROP_UINT(esd->dependsOnESID));
1427 :
1428 72 : gf_filter_pid_set_property(pid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(esd->decoderConfig->streamType));
1429 72 : gf_filter_pid_set_property(pid, GF_PROP_PID_CODECID, &PROP_UINT(esd->decoderConfig->objectTypeIndication));
1430 72 : gf_filter_pid_set_property(pid, GF_PROP_PID_TIMESCALE, &PROP_UINT(1000));
1431 72 : if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) {
1432 72 : gf_filter_pid_set_property(pid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA_NO_COPY(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength));
1433 :
1434 72 : esd->decoderConfig->decoderSpecificInfo->data=NULL;
1435 72 : esd->decoderConfig->decoderSpecificInfo->dataLength=0;
1436 : }
1437 :
1438 72 : if (props.width && props.height) {
1439 72 : gf_filter_pid_set_property(pid, GF_PROP_PID_WIDTH, &PROP_UINT(props.width));
1440 72 : gf_filter_pid_set_property(pid, GF_PROP_PID_HEIGHT, &PROP_UINT(props.height));
1441 : }
1442 72 : if (props.hidden) {
1443 0 : gf_filter_pid_set_property(pid, GF_PROP_PID_HIDDEN, &PROP_BOOL(props.hidden));
1444 : }
1445 :
1446 72 : if (gf_isom_get_meta_primary_item_id(read->mov, GF_TRUE, 0) == item_id) {
1447 10 : gf_filter_pid_set_property(pid, GF_PROP_PID_PRIMARY_ITEM, &PROP_BOOL(GF_TRUE));
1448 : } else {
1449 62 : gf_filter_pid_set_property(pid, GF_PROP_PID_PRIMARY_ITEM, &PROP_BOOL(GF_FALSE));
1450 : }
1451 :
1452 72 : if (!gf_sys_is_test_mode() && !read->itt)
1453 0 : gf_filter_pid_set_property(pid, GF_PROP_PID_ITEM_NUM, &PROP_UINT(item_idx) );
1454 :
1455 72 : gf_filter_pid_set_property_str(pid, "meta:mime", item_mime_type ? &PROP_STRING(item_mime_type) : NULL );
1456 72 : gf_filter_pid_set_property_str(pid, "meta:name", item_name ? &PROP_STRING(item_name) : NULL );
1457 72 : gf_filter_pid_set_property_str(pid, "meta:encoding", item_encoding ? &PROP_STRING(item_encoding) : NULL );
1458 :
1459 :
1460 : //setup cenc
1461 72 : if (scheme_type) {
1462 13 : gf_filter_pid_set_property(pid, GF_PROP_PID_PROTECTION_SCHEME_TYPE, &PROP_4CC(scheme_type) );
1463 13 : gf_filter_pid_set_property(pid, GF_PROP_PID_PROTECTION_SCHEME_VERSION, &PROP_UINT(scheme_version) );
1464 13 : gf_filter_pid_set_property(pid, GF_PROP_PID_ENCRYPTED, &PROP_BOOL(GF_TRUE) );
1465 :
1466 13 : gf_filter_pid_set_property(pid, GF_PROP_PID_ORIG_STREAM_TYPE, &PROP_UINT(esd->decoderConfig->streamType));
1467 13 : gf_filter_pid_set_property(pid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_ENCRYPTED) );
1468 : }
1469 :
1470 72 : gf_odf_desc_del((GF_Descriptor *)esd);
1471 :
1472 72 : if (!ch) {
1473 46 : ch = isor_create_channel(read, pid, 0, item_id, GF_FALSE);
1474 46 : if (ch && scheme_type) {
1475 13 : ch->is_cenc = GF_TRUE;
1476 13 : ch->is_encrypted = GF_TRUE;
1477 :
1478 13 : isor_declare_pssh(ch);
1479 :
1480 : }
1481 : }
1482 : return GF_TRUE;
1483 : }
1484 :
1485 : #endif /*GPAC_DISABLE_ISOM*/
1486 :
1487 :
1488 :
|