1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Jean Le Feuvre
5  *			Copyright (c) Telecom ParisTech 2000-2018
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 
isor_declare_track(ISOMReader * read,ISOMChannel * ch,u32 track,u32 stsd_idx,u32 streamtype,Bool use_iod)79 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;
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 	u8 *dsi = NULL, *enh_dsi = NULL;
92 	u32 dsi_size = 0, enh_dsi_size = 0;
93 	Double track_dur=0;
94 	u32 srd_id=0, srd_indep=0, srd_x=0, srd_y=0, srd_w=0, srd_h=0;
95 	u32 base_tile_track=0;
96 	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 	depends_on_id = avg_rate = max_rate = buffer_size = 0;
105 	mime = encoding = stxtcfg = namespace = schemaloc = NULL;
106 
107 	if ( gf_isom_is_media_encrypted(read->mov, track, stsd_idx)) {
108 		gf_isom_get_original_format_type(read->mov, track, stsd_idx, &m_subtype);
109 	} else {
110 		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 	an_esd = gf_media_map_esd(read->mov, track, stsd_idx);
117 	if (an_esd && an_esd->decoderConfig) {
118 		if (an_esd->decoderConfig->streamType==GF_STREAM_INTERACT) {
119 			gf_odf_desc_del((GF_Descriptor *)an_esd);
120 			return;
121 		}
122 		streamtype = an_esd->decoderConfig->streamType;
123 		if (an_esd->decoderConfig->objectTypeIndication < GF_CODECID_LAST_MPEG4_MAPPING) {
124 			codec_id = gf_codecid_from_oti(streamtype, an_esd->decoderConfig->objectTypeIndication);
125 		} else {
126 			codec_id = an_esd->decoderConfig->objectTypeIndication;
127 		}
128 		ocr_es_id = an_esd->OCRESID;
129 		depends_on_id = an_esd->dependsOnESID;
130 		lang_desc = an_esd->langDesc;
131 		an_esd->langDesc = NULL;
132 		esid = an_esd->ESID;
133 
134 		if (an_esd->decoderConfig->decoderSpecificInfo && an_esd->decoderConfig->decoderSpecificInfo->data) {
135 			dsi = an_esd->decoderConfig->decoderSpecificInfo->data;
136 			dsi_size = an_esd->decoderConfig->decoderSpecificInfo->dataLength;
137 			an_esd->decoderConfig->decoderSpecificInfo->data = NULL;
138 			an_esd->decoderConfig->decoderSpecificInfo->dataLength = 0;
139 		}
140 
141 		gf_odf_desc_del((GF_Descriptor *)an_esd);
142 	} else {
143 		u32 pcm_flags, pcm_size;
144 		Bool load_default = GF_FALSE;
145 		lang_desc = (GF_Language *) gf_odf_desc_new(GF_ODF_LANG_TAG);
146 		gf_isom_get_media_language(read->mov, track, &lang_desc->full_lang_code);
147 		esid = gf_isom_get_track_id(read->mov, track);
148 
149 		if (!streamtype) streamtype = gf_codecid_type(m_subtype);
150 		codec_id = 0;
151 
152 		switch (m_subtype) {
153 		case GF_ISOM_SUBTYPE_STXT:
154 		case GF_ISOM_SUBTYPE_METT:
155 		case GF_ISOM_SUBTYPE_SBTT:
156 		case GF_ISOM_MEDIA_SUBT:
157 
158 			codec_id = GF_CODECID_SIMPLE_TEXT;
159 			gf_isom_stxt_get_description(read->mov, track, stsd_idx, &mime, &encoding, &stxtcfg);
160 			break;
161 		case GF_ISOM_SUBTYPE_STPP:
162 			codec_id = GF_CODECID_SUBS_XML;
163 			gf_isom_xml_subtitle_get_description(read->mov, track, stsd_idx, &namespace, &schemaloc, &mime);
164 			break;
165 		case GF_ISOM_SUBTYPE_METX:
166 			codec_id = GF_CODECID_META_XML;
167 			gf_isom_xml_subtitle_get_description(read->mov, track, stsd_idx, &namespace, &schemaloc, &mime);
168 			break;
169 		case GF_ISOM_SUBTYPE_WVTT:
170 			codec_id = GF_CODECID_WEBVTT;
171 			stxtcfg = gf_isom_get_webvtt_config(read->mov, track, stsd_idx);
172 			break;
173 		case GF_ISOM_SUBTYPE_MJP2:
174 			codec_id = GF_CODECID_J2K;
175 			gf_isom_get_jp2_config(read->mov, track, stsd_idx, &dsi, &dsi_size);
176 			break;
177 		case GF_ISOM_SUBTYPE_HVT1:
178 			codec_id = GF_CODECID_HEVC_TILES;
179 			gf_isom_get_reference(read->mov, track, GF_ISOM_REF_TBAS, 1, &base_tile_track);
180 			if (base_tile_track) {
181 				depends_on_id = gf_isom_get_track_id(read->mov, base_tile_track);
182 			}
183 			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);
184 			break;
185 		case GF_ISOM_SUBTYPE_TEXT:
186 		case GF_ISOM_SUBTYPE_TX3G:
187 		{
188 			GF_TextSampleDescriptor *txtcfg = NULL;
189 			codec_id = GF_CODECID_TX3G;
190 			e = gf_isom_get_text_description(read->mov, track, stsd_idx, &txtcfg);
191 			if (e) {
192 				GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Track %d unable to fetch TX3G config\n", track));
193 			}
194 			if (txtcfg) {
195 				gf_odf_tx3g_write(txtcfg, &dsi, &dsi_size);
196 				gf_odf_desc_del((GF_Descriptor *) txtcfg);
197 			}
198 		}
199 			break;
200 
201 		case GF_ISOM_SUBTYPE_FLAC:
202 			codec_id = GF_CODECID_FLAC;
203 			gf_isom_flac_config_get(read->mov, track, stsd_idx, &dsi, &dsi_size);
204 			break;
205 		case GF_ISOM_SUBTYPE_OPUS:
206 			codec_id = GF_CODECID_OPUS;
207 			gf_isom_opus_config_get(read->mov, track, stsd_idx, &dsi, &dsi_size);
208 			break;
209 
210 		case GF_QT_SUBTYPE_TWOS:
211 		case GF_QT_SUBTYPE_SOWT:
212 		case GF_QT_SUBTYPE_FL32:
213 		case GF_QT_SUBTYPE_FL64:
214 		case GF_QT_SUBTYPE_IN24:
215 		case GF_QT_SUBTYPE_IN32:
216 			codec_id = GF_CODECID_RAW;
217 			audio_fmt = gf_audio_fmt_from_isobmf(m_subtype);
218 			break;
219 		case GF_ISOM_MEDIA_TMCD:
220 			codec_id = GF_CODECID_TMCD;
221 			streamtype = GF_STREAM_METADATA;
222 			break;
223 
224 		case GF_QT_SUBTYPE_RAW:
225 			codec_id = GF_CODECID_RAW;
226 			if (streamtype==GF_STREAM_AUDIO)
227  				audio_fmt = GF_AUDIO_FMT_U8;
228 			else
229  				pix_fmt = GF_PIXEL_RGB;
230 			break;
231 		case GF_QT_SUBTYPE_YUV422:
232 			codec_id = GF_CODECID_RAW;
233 			pix_fmt = GF_PIXEL_YUV422;
234 			break;
235 		case GF_QT_SUBTYPE_YUV444:
236 			codec_id = GF_CODECID_RAW;
237 			pix_fmt = GF_PIXEL_YUV444;
238 			break;
239 		case GF_QT_SUBTYPE_YUV422_10:
240 			codec_id = GF_CODECID_RAW;
241 			pix_fmt = GF_PIXEL_YUV422_10;
242 			break;
243 		case GF_QT_SUBTYPE_YUV444_10:
244 			codec_id = GF_CODECID_RAW;
245 			pix_fmt = GF_PIXEL_YUV444_10;
246 			break;
247 		case GF_ISOM_SUBTYPE_IPCM:
248 			if (gf_isom_get_pcm_config(read->mov, track, stsd_idx, &pcm_flags, &pcm_size) == GF_OK) {
249 				codec_id = GF_CODECID_RAW;
250 				if (pcm_size==16) audio_fmt = GF_AUDIO_FMT_S16;
251 				else if (pcm_size==24) audio_fmt = GF_AUDIO_FMT_S24;
252 				else if (pcm_size==32) audio_fmt = GF_AUDIO_FMT_S32;
253 			}
254 			break;
255 		case GF_ISOM_SUBTYPE_FPCM:
256 			if (gf_isom_get_pcm_config(read->mov, track, stsd_idx, &pcm_flags, &pcm_size) == GF_OK) {
257 				codec_id = GF_CODECID_RAW;
258 				audio_fmt = (pcm_size==64) ? GF_AUDIO_FMT_DBL : GF_AUDIO_FMT_FLT;
259 			}
260 			break;
261 		case GF_ISOM_SUBTYPE_MP3:
262 			codec_id = GF_CODECID_MPEG_AUDIO;
263 			break;
264 
265 		default:
266 			codec_id = gf_codec_id_from_isobmf(m_subtype);
267 			if (!codec_id)
268 				load_default = GF_TRUE;
269 			break;
270 		}
271 
272 		if (load_default) {
273 			if (!codec_id) {
274 				GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Track %d type %s not natively handled\n", track, gf_4cc_to_str(m_subtype) ));
275 
276 				codec_id = m_subtype;
277 			}
278 			udesc = gf_isom_get_generic_sample_description(read->mov, track, stsd_idx);
279 			if (udesc) {
280 				dsi = udesc->extension_buf;
281 				dsi_size = udesc->extension_buf_size;
282 				udesc->extension_buf = NULL;
283 				udesc->extension_buf_size = 0;
284 			}
285 		}
286 	}
287 	if (!streamtype || !codec_id) {
288 		if (udesc) gf_free(udesc);
289 		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[IsoMedia] Failed to %s pid for track %d, couldnot extract codec/streamtype info\n", ch ? "update" : "create", track));
290 		if (lang_desc) gf_odf_desc_del((GF_Descriptor *)lang_desc);
291 		if (dsi) gf_free(dsi);
292 		return;
293 	}
294 
295 	//first setup, creation of PID and channel
296 	if (!ch) {
297 		Bool use_sidx_dur = GF_FALSE;
298 		GF_FilterPid *pid;
299 		first_config = GF_TRUE;
300 
301 		gf_isom_get_reference(read->mov, track, GF_ISOM_REF_BASE, 1, &base_track);
302 
303 		if (base_track) {
304 			u32 base_subtype=0;
305 			if (read->smode==MP4DMX_SINGLE)
306 				depends_on_id = 0;
307 
308 			switch (m_subtype) {
309 			case GF_ISOM_SUBTYPE_LHV1:
310 			case GF_ISOM_SUBTYPE_LHE1:
311 				base_subtype = gf_isom_get_media_subtype(read->mov, base_track, stsd_idx);
312 				switch (base_subtype) {
313 				case GF_ISOM_SUBTYPE_HVC1:
314 				case GF_ISOM_SUBTYPE_HEV1:
315 				case GF_ISOM_SUBTYPE_HVC2:
316 				case GF_ISOM_SUBTYPE_HEV2:
317 					break;
318 				default:
319 					external_base=GF_TRUE;
320 					break;
321 				}
322 			}
323 			if (external_base) {
324 				depends_on_id = gf_isom_get_track_id(read->mov, base_track);
325 				has_scalable_layers = GF_TRUE;
326 			} else {
327 				switch (gf_isom_get_hevc_lhvc_type(read->mov, track, stsd_idx)) {
328 				case GF_ISOM_HEVCTYPE_HEVC_LHVC:
329 				case GF_ISOM_HEVCTYPE_LHVC_ONLY:
330 					has_scalable_layers = GF_TRUE;
331 					break;
332 				//this is likely temporal sublayer of base
333 				case GF_ISOM_HEVCTYPE_HEVC_ONLY:
334 					has_scalable_layers = GF_FALSE;
335 					if (gf_isom_get_reference_count(read->mov, track, GF_ISOM_REF_SCAL)<=0) {
336 						depends_on_id = gf_isom_get_track_id(read->mov, base_track);
337 					}
338 					break;
339 				default:
340 					break;
341 				}
342 			}
343 		} else {
344 			switch (gf_isom_get_hevc_lhvc_type(read->mov, track, stsd_idx)) {
345 			case GF_ISOM_HEVCTYPE_HEVC_LHVC:
346 			case GF_ISOM_HEVCTYPE_LHVC_ONLY:
347 				has_scalable_layers = GF_TRUE;
348 				break;
349 			default:
350 				break;
351 			}
352 		}
353 
354 		if (base_track && !ocr_es_id) {
355 			ocr_es_id = gf_isom_get_track_id(read->mov, base_track);
356 		}
357 		if (!ocr_es_id) ocr_es_id = esid;
358 
359 		//OK declare PID
360 		pid = gf_filter_pid_new(read->filter);
361 		if (read->pid)
362 			gf_filter_pid_copy_properties(pid, read->pid);
363 
364 		gf_filter_pid_set_property(pid, GF_PROP_PID_ID, &PROP_UINT(esid));
365 		gf_filter_pid_set_property(pid, GF_PROP_PID_CLOCK_ID, &PROP_UINT(ocr_es_id));
366 		if (depends_on_id && (depends_on_id != esid))
367 			gf_filter_pid_set_property(pid, GF_PROP_PID_DEPENDENCY_ID, &PROP_UINT(depends_on_id));
368 
369 		if (gf_isom_get_track_count(read->mov)>1) {
370 			char szPName[1024];
371 			const char *szST = gf_stream_type_name(streamtype);
372 			sprintf(szPName, "%c%d", szST[0], esid);
373 			gf_filter_pid_set_name(pid, szPName);
374 		}
375 
376 		//MPEG-4 systems present
377 		if (use_iod)
378 			gf_filter_pid_set_property(pid, GF_PROP_PID_ESID, &PROP_UINT(esid));
379 
380 		if (gf_isom_is_track_in_root_od(read->mov, track)) {
381 			gf_filter_pid_set_property(pid, GF_PROP_PID_IN_IOD, &PROP_BOOL(GF_TRUE));
382 		}
383 
384 		gf_filter_pid_set_property(pid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(streamtype));
385 		gf_filter_pid_set_property(pid, GF_PROP_PID_TIMESCALE, &PROP_UINT( gf_isom_get_media_timescale(read->mov, track) ) );
386 
387 		//Dolby Vision
388 		if (m_subtype == GF_ISOM_SUBTYPE_DVHE) {
389 			GF_DOVIDecoderConfigurationRecord *dovi = gf_isom_dovi_config_get(read->mov, track, 1);
390 			if (dovi) {
391 				u8 *data = NULL;
392 				u32 size = 0;
393 				GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
394 				gf_odf_dovi_cfg_write_bs(dovi, bs);
395 				gf_bs_get_content(bs, &data, &size);
396 				gf_filter_pid_set_property(pid, GF_PROP_PID_DOLBY_VISION, &PROP_DATA_NO_COPY(data, size));
397 				gf_bs_del(bs);
398 				gf_odf_dovi_cfg_del(dovi);
399 			}
400 		}
401 
402 		//create our channel
403 		ch = isor_create_channel(read, pid, track, 0, (codec_id==GF_CODECID_LHVC) ? GF_TRUE : GF_FALSE);
404 
405 		if (lang_desc) {
406 			char *lang=NULL;
407 			gf_isom_get_media_language(read->mov, track, &lang);
408 			//s32 idx = gf_lang_find(lang);
409 			gf_filter_pid_set_property(pid, GF_PROP_PID_LANGUAGE, &PROP_STRING( lang ));
410 			if (lang) gf_free(lang);
411 			gf_odf_desc_del((GF_Descriptor *)lang_desc);
412 			lang_desc = NULL;
413 		}
414 
415 
416 		if (has_scalable_layers)
417 			gf_filter_pid_set_property(pid, GF_PROP_PID_SCALABLE, &PROP_BOOL(GF_TRUE));
418 
419 		if (gf_isom_get_reference_count(read->mov, track, GF_ISOM_REF_SABT)>0) {
420 			gf_filter_pid_set_property(pid, GF_PROP_PID_TILE_BASE, &PROP_BOOL(GF_TRUE));
421 		}
422 
423 		if (srd_w && srd_h) {
424 			gf_filter_pid_set_property(pid, GF_PROP_PID_CROP_POS, &PROP_VEC2I_INT(srd_x, srd_y) );
425 			if (base_tile_track) {
426 				gf_isom_get_visual_info(read->mov, base_tile_track, stsd_idx, &w, &h);
427 				if (w && h) {
428 					gf_filter_pid_set_property(pid, GF_PROP_PID_ORIG_SIZE, &PROP_VEC2I_INT(w, h) );
429 				}
430 			}
431 		}
432 
433 		for (exp_refs=0; exp_refs<3; exp_refs++) {
434 			u32 rtype = (exp_refs==2) ? GF_ISOM_REF_TBAS : exp_refs ? GF_ISOM_REF_SABT : GF_ISOM_REF_SCAL;
435 			const char *rname = (exp_refs==2) ? "isom:tbas" : exp_refs ? "isom:sabt" : "isom:scal";
436 			if (!exp_refs && (codec_id==GF_CODECID_LHVC))
437 				continue;
438 
439 			nb_refs = gf_isom_get_reference_count(read->mov, track, rtype);
440 			if (nb_refs) {
441 				u32 j;
442 				GF_PropertyValue prop;
443 				prop.type = GF_PROP_UINT_LIST;
444 				prop.value.uint_list.nb_items = nb_refs;
445 				prop.value.uint_list.vals = gf_malloc(sizeof(u32)*nb_refs);
446 				for (j=0; j<nb_refs; j++) {
447 					gf_isom_get_reference(read->mov, track, rtype, j+1, &prop.value.uint_list.vals[j] );
448 				}
449 				gf_filter_pid_set_property_str(pid, rname, &prop);
450 				gf_free(prop.value.uint_list.vals);
451 			}
452 		}
453 
454 		ch->duration = gf_isom_get_track_duration(read->mov, ch->track);
455 		if (!ch->duration) {
456 			ch->duration = gf_isom_get_duration(read->mov);
457 		}
458 		sample_count = gf_isom_get_sample_count(read->mov, ch->track);
459 
460 		if (read->frag_type && !read->input_loaded) {
461 			u32 ts;
462 			u64 dur;
463 			if (gf_isom_get_sidx_duration(read->mov, &dur, &ts)==GF_OK) {
464 				dur *= read->time_scale;
465 				dur /= ts;
466 				ch->duration = dur;
467 				use_sidx_dur = GF_TRUE;
468 				sample_count = 0;
469 			}
470 		}
471 
472 		if (!read->mem_load_mode) {
473 			//if no edit list (whether complex or simple TS offset) and no sidx, use media duration
474 			if (!ch->has_edit_list && !use_sidx_dur && !ch->ts_offset) {
475 				u64 dur = gf_isom_get_media_duration(read->mov, ch->track);
476 				gf_filter_pid_set_property(pid, GF_PROP_PID_DURATION, &PROP_FRAC64_INT(dur, ch->time_scale));
477 			}
478 			//otherwise trust track duration
479 			else {
480 				gf_filter_pid_set_property(pid, GF_PROP_PID_DURATION, &PROP_FRAC64_INT(ch->duration, read->time_scale));
481 			}
482 			gf_filter_pid_set_property(pid, GF_PROP_PID_NB_FRAMES, &PROP_UINT(sample_count));
483 		}
484 
485 		if (sample_count && (streamtype==GF_STREAM_VISUAL)) {
486 			u64 mdur = gf_isom_get_media_duration(read->mov, track);
487 			mdur /= sample_count;
488 			gf_filter_pid_set_property(pid, GF_PROP_PID_FPS, &PROP_FRAC_INT(ch->time_scale, (u32) mdur));
489 		}
490 
491 		track_dur = (Double) (s64) ch->duration;
492 		track_dur /= read->time_scale;
493 		//move channel duration in media timescale
494 		ch->duration = (u32) (track_dur * ch->time_scale);
495 
496 
497 		//set stream subtype
498 		mtype = gf_isom_get_media_type(read->mov, track);
499 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_SUBTYPE, &PROP_UINT(mtype) );
500 
501 		if (!read->mem_load_mode) {
502 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_MEDIA_DATA_SIZE, &PROP_LONGUINT(gf_isom_get_media_data_size(read->mov, track) ) );
503 		}
504 
505 
506 		w = gf_isom_get_constant_sample_size(read->mov, track);
507 		if (w)
508 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_FRAME_SIZE, &PROP_UINT(w));
509 
510 		if (read->mem_load_mode) {
511 			gf_filter_pid_set_property(pid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_NONE) );
512 		} else {
513 			gf_filter_pid_set_property(pid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_REWIND) );
514 		}
515 
516 		GF_PropertyValue brands;
517 		brands.type = GF_PROP_UINT_LIST;
518 		u32 major_brand=0;
519 		gf_isom_get_brand_info(read->mov, &major_brand, NULL, &brands.value.uint_list.nb_items);
520 		brands.value.uint_list.vals = (u32 *) gf_isom_get_brands(read->mov);
521 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_BRANDS, &brands);
522 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_MBRAND, &PROP_UINT(major_brand) );
523 
524 		max_size = gf_isom_get_max_sample_size(read->mov, ch->track);
525 		if (max_size) gf_filter_pid_set_property(pid, GF_PROP_PID_MAX_FRAME_SIZE, &PROP_UINT(max_size) );
526 
527 		max_size = gf_isom_get_avg_sample_size(read->mov, ch->track);
528 		if (max_size) gf_filter_pid_set_property(pid, GF_PROP_PID_AVG_FRAME_SIZE, &PROP_UINT(max_size) );
529 
530 		max_size = gf_isom_get_max_sample_delta(read->mov, ch->track);
531 		if (max_size) gf_filter_pid_set_property(pid, GF_PROP_PID_MAX_TS_DELTA, &PROP_UINT(max_size) );
532 
533 		max_size = gf_isom_get_max_sample_cts_offset(read->mov, ch->track);
534 		if (max_size) gf_filter_pid_set_property(pid, GF_PROP_PID_MAX_CTS_OFFSET, &PROP_UINT(max_size) );
535 
536 		max_size = gf_isom_get_constant_sample_duration(read->mov, ch->track);
537 		if (max_size) gf_filter_pid_set_property(pid, GF_PROP_PID_CONSTANT_DURATION, &PROP_UINT(max_size) );
538 
539 		u32 media_pl=0;
540 		if (streamtype==GF_STREAM_VISUAL) {
541 			media_pl = gf_isom_get_pl_indication(read->mov, GF_ISOM_PL_VISUAL);
542 		} else if (streamtype==GF_STREAM_AUDIO) {
543 			media_pl = gf_isom_get_pl_indication(read->mov, GF_ISOM_PL_AUDIO);
544 		}
545 		if (media_pl && (media_pl!=0xFF) ) gf_filter_pid_set_property(pid, GF_PROP_PID_PROFILE_LEVEL, &PROP_UINT(media_pl) );
546 
547 #if !defined(GPAC_DISABLE_ISOM_WRITE)
548 		e = gf_isom_get_track_template(read->mov, ch->track, &tk_template, &tk_template_size);
549 		if (e == GF_OK) {
550 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_TRACK_TEMPLATE, &PROP_DATA_NO_COPY(tk_template, tk_template_size) );
551 		} else {
552 			GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Failed to serialize track box: %s\n", gf_error_to_string(e) ));
553 		}
554 
555 		e = gf_isom_get_trex_template(read->mov, ch->track, &tk_template, &tk_template_size);
556 		if (e == GF_OK) {
557 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_TREX_TEMPLATE, &PROP_DATA_NO_COPY(tk_template, tk_template_size) );
558 		}
559 
560 		e = gf_isom_get_raw_user_data(read->mov, &tk_template, &tk_template_size);
561 		if (e==GF_OK) {
562 			if (tk_template_size)
563 				gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_UDTA, &PROP_DATA_NO_COPY(tk_template, tk_template_size) );
564 		} else {
565 			GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Failed to serialize moov UDTA box: %s\n", gf_error_to_string(e) ));
566 		}
567 #endif
568 
569 		GF_Fraction64 moov_time;
570 		moov_time.num = gf_isom_get_duration(read->mov);
571 		moov_time.den = gf_isom_get_timescale(read->mov);
572 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_MOVIE_TIME, &PROP_FRAC64(moov_time) );
573 
574 
575 		u32 i;
576 		s32 tx, ty;
577 		s16 l;
578 		gf_isom_get_track_layout_info(read->mov, ch->track, &w, &h, &tx, &ty, &l);
579 		if (w && h) {
580 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_WIDTH, &PROP_UINT(w) );
581 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_HEIGHT, &PROP_UINT(h) );
582 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_TRANS_X, &PROP_SINT(tx) );
583 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_TRANS_Y, &PROP_SINT(ty) );
584 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ZORDER, &PROP_SINT(l) );
585 		}
586 		if (codec_id==GF_CODECID_TX3G) {
587 			u32 m_w = w;
588 			u32 m_h = h;
589 			for (i=0; i<gf_isom_get_track_count(read->mov); i++) {
590 				switch (gf_isom_get_media_type(read->mov, i+1)) {
591 				case GF_ISOM_MEDIA_SCENE:
592 				case GF_ISOM_MEDIA_VISUAL:
593 				case GF_ISOM_MEDIA_AUXV:
594 				case GF_ISOM_MEDIA_PICT:
595 					gf_isom_get_track_layout_info(read->mov, i+1, &w, &h, &tx, &ty, &l);
596 					if (w>m_w) m_w = w;
597 					if (h>m_h) m_h = h;
598 					break;
599 				default:
600 					break;
601 				}
602 			}
603 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_WIDTH_MAX, &PROP_UINT(m_w) );
604 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_HEIGHT_MAX, &PROP_UINT(m_h) );
605 			char *tx3g_config_sdp = NULL;
606 			for (i=0; i<gf_isom_get_sample_description_count(read->mov, ch->track); i++) {
607 				u8 *tx3g;
608 				char buffer[2000];
609 				u32 l1;
610 				u32 tx3g_len, len;
611 				gf_isom_text_get_encoded_tx3g(read->mov, ch->track, i+1, GF_RTP_TX3G_SIDX_OFFSET, &tx3g, &tx3g_len);
612 				len = gf_base64_encode(tx3g, tx3g_len, buffer, 2000);
613 				gf_free(tx3g);
614 				buffer[len] = 0;
615 
616 				l1 = tx3g_config_sdp ? (u32) strlen(tx3g_config_sdp) : 0;
617 				tx3g_config_sdp = gf_realloc(tx3g_config_sdp, len+3+l1);
618 				tx3g_config_sdp[l1] = 0;
619 				if (i) strcat(tx3g_config_sdp, ", ");
620 				strcat(tx3g_config_sdp, buffer);
621 			}
622 			if (tx3g_config_sdp) {
623 				gf_filter_pid_set_property(ch->pid, GF_PROP_PID_DECODER_CONFIG_ENHANCEMENT, &PROP_STRING_NO_COPY(tx3g_config_sdp) );
624 			}
625 		}
626 
627 
628 		u32 tag_len;
629 		const u8 *tag;
630 		if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_NAME, &tag, &tag_len)==GF_OK)
631 			gf_filter_pid_set_info_str(ch->pid, "info:name", &PROP_STRING(tag) );
632 
633 		if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_ARTIST, &tag, &tag_len)==GF_OK)
634 			gf_filter_pid_set_info_str(ch->pid, "info:artist", &PROP_STRING(tag) );
635 
636 		if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_ALBUM, &tag, &tag_len)==GF_OK)
637 			gf_filter_pid_set_info_str(ch->pid, "info:album", &PROP_STRING(tag) );
638 
639 		if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_COMMENT, &tag, &tag_len)==GF_OK)
640 			gf_filter_pid_set_info_str(ch->pid, "info:comment", &PROP_STRING(tag) );
641 
642 		if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_TRACK, &tag, &tag_len)==GF_OK) {
643 			u16 tk_n = (tag[2]<<8)|tag[3];
644 			u16 tk_all = (tag[4]<<8)|tag[5];
645 			gf_filter_pid_set_info_str(ch->pid, "info:track", &PROP_FRAC_INT(tk_n, tk_all) );
646 		}
647 		if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_COMPOSER, &tag, &tag_len)==GF_OK)
648 			gf_filter_pid_set_info_str(ch->pid, "info:composer", &PROP_STRING(tag) );
649 		if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_WRITER, &tag, &tag_len)==GF_OK)
650 			gf_filter_pid_set_info_str(ch->pid, "info:writer", &PROP_STRING(tag) );
651 
652 		if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_GENRE, &tag, &tag_len)==GF_OK) {
653 			if (tag[0]) {
654 			} else {
655 				/*com->info.genre = (tag[0]<<8) | tag[1];*/
656 			}
657 		}
658 
659 		if (codec_id==GF_CODECID_TMCD) {
660 			u32 tmcd_flags=0, tmcd_fps_num=0, tmcd_fps_den=0, tmcd_fpt=0;
661 			gf_isom_get_tmcd_config(read->mov, track, stsd_idx, &tmcd_flags, &tmcd_fps_num, &tmcd_fps_den, &tmcd_fpt);
662 			gf_filter_pid_set_property_str(ch->pid, "tmcd:flags", &PROP_UINT(tmcd_flags) );
663 			gf_filter_pid_set_property_str(ch->pid, "tmcd:framerate", &PROP_FRAC_INT(tmcd_fps_num, tmcd_fps_den) );
664 			gf_filter_pid_set_property_str(ch->pid, "tmcd:frames_per_tick", &PROP_UINT(tmcd_fpt) );
665 
666 		}
667 
668 		if (!gf_sys_is_test_mode()) {
669 			const char *hdlr = NULL;
670 			gf_isom_get_handler_name(read->mov, ch->track, &hdlr);
671 			if (hdlr)
672 				gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_HANDLER, &PROP_STRING(hdlr));
673 
674 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_TRACK_FLAGS, &PROP_UINT( gf_isom_get_track_flags(read->mov, ch->track) ));
675 
676 			if (streamtype==GF_STREAM_VISUAL) {
677 				GF_PropertyValue p;
678 				u32 vals[9];
679 				memset(vals, 0, sizeof(u32)*9);
680 				memset(&p, 0, sizeof(GF_PropertyValue));
681 				p.type = GF_PROP_UINT_LIST;
682 				p.value.uint_list.nb_items = 9;
683 				p.value.uint_list.vals = vals;
684 				gf_isom_get_track_matrix(read->mov, ch->track, vals);
685 				gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_TRACK_MATRIX, &p);
686 			}
687 		}
688 	}
689 
690 	//update decoder configs
691 	ch->check_avc_ps = ch->check_hevc_ps = GF_FALSE;
692 	if (ch->avcc) gf_odf_avc_cfg_del(ch->avcc);
693 	ch->avcc = NULL;
694 	if (ch->hvcc) gf_odf_hevc_cfg_del(ch->hvcc);
695 	ch->hvcc = NULL;
696 
697 	if (lang_desc) {
698 		gf_odf_desc_del((GF_Descriptor *)lang_desc);
699 		lang_desc = NULL;
700 	}
701 
702 	if (read->smode != MP4DMX_SINGLE) {
703 		if ((codec_id==GF_CODECID_LHVC) || (codec_id==GF_CODECID_HEVC)) {
704 			Bool signal_lhv = (read->smode==MP4DMX_SPLIT) ? GF_TRUE : GF_FALSE;
705 			GF_HEVCConfig *hvcc = gf_isom_hevc_config_get(read->mov, track, stsd_idx);
706 			GF_HEVCConfig *lhcc = gf_isom_lhvc_config_get(read->mov, track, stsd_idx);
707 
708 			if (hvcc || lhcc) {
709 				if (dsi) gf_free(dsi);
710 				dsi = NULL;
711 				//no base layer config
712 				if (!hvcc) signal_lhv = GF_TRUE;
713 
714 				if (signal_lhv && lhcc) {
715 					if (hvcc) {
716 						hvcc->is_lhvc = GF_FALSE;
717 						gf_odf_hevc_cfg_write(hvcc, &dsi, &dsi_size);
718 					}
719 					lhcc->is_lhvc = GF_TRUE;
720 					gf_odf_hevc_cfg_write(lhcc, &enh_dsi, &enh_dsi_size);
721 					codec_id = GF_CODECID_LHVC;
722 				} else {
723 					if (hvcc) {
724 						hvcc->is_lhvc = GF_FALSE;
725 						gf_odf_hevc_cfg_write(hvcc, &dsi, &dsi_size);
726 					}
727 					if (lhcc) {
728 						lhcc->is_lhvc = GF_TRUE;
729 						gf_odf_hevc_cfg_write(lhcc, &enh_dsi, &enh_dsi_size);
730 					}
731 					codec_id = GF_CODECID_HEVC;
732 				}
733 			}
734 			if (hvcc) gf_odf_hevc_cfg_del(hvcc);
735 			if (lhcc) gf_odf_hevc_cfg_del(lhcc);
736 
737 		}
738 		if ((codec_id==GF_CODECID_AVC) || (codec_id==GF_CODECID_SVC) || (codec_id==GF_CODECID_MVC)) {
739 			Bool is_mvc = GF_FALSE;
740 			Bool signal_svc = (read->smode==MP4DMX_SPLIT) ? GF_TRUE : GF_FALSE;
741 			GF_AVCConfig *avcc = gf_isom_avc_config_get(read->mov, track, stsd_idx);
742 			GF_AVCConfig *svcc = gf_isom_svc_config_get(read->mov, track, stsd_idx);
743 			if (!svcc) {
744 				svcc = gf_isom_mvc_config_get(read->mov, track, stsd_idx);
745 				is_mvc = GF_TRUE;
746 			}
747 
748 			if (avcc || svcc) {
749 				if (dsi) gf_free(dsi);
750 				dsi = NULL;
751 				//no base layer config
752 				if (!avcc) signal_svc = GF_TRUE;
753 
754 				if (signal_svc && svcc) {
755 					if (avcc) {
756 						gf_odf_avc_cfg_write(avcc, &dsi, &dsi_size);
757 					}
758 					gf_odf_avc_cfg_write(svcc, &enh_dsi, &enh_dsi_size);
759 					codec_id = is_mvc ? GF_CODECID_MVC : GF_CODECID_SVC;
760 				} else {
761 					if (avcc) {
762 						gf_odf_avc_cfg_write(avcc, &dsi, &dsi_size);
763 					}
764 					if (svcc) {
765 						gf_odf_avc_cfg_write(svcc, &enh_dsi, &enh_dsi_size);
766 					}
767 					codec_id = GF_CODECID_AVC;
768 				}
769 			}
770 			if (avcc) gf_odf_avc_cfg_del(avcc);
771 			if (svcc) gf_odf_avc_cfg_del(svcc);
772 		}
773 	}
774 
775 	//all stsd specific init/reconfig
776 	gf_filter_pid_set_property(ch->pid, GF_PROP_PID_CODECID, &PROP_UINT(codec_id));
777 	if (dsi) {
778 		ch->dsi_crc = gf_crc_32(dsi, dsi_size);
779 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA_NO_COPY(dsi, dsi_size));
780 	}
781 	if (enh_dsi) {
782 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_DECODER_CONFIG_ENHANCEMENT, &PROP_DATA_NO_COPY(enh_dsi, enh_dsi_size));
783 	}
784 	if (audio_fmt) {
785 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(audio_fmt));
786 		if (codec_id == GF_CODECID_RAW) {
787 			gf_isom_enable_raw_pack(read->mov, track, read->frame_size);
788 		}
789 	}
790 	if (pix_fmt) {
791 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_PIXFMT, &PROP_UINT(pix_fmt));
792 	}
793 
794 	gf_filter_pid_set_property(ch->pid, GF_PROP_PID_CONFIG_IDX, &PROP_UINT(stsd_idx) );
795 
796 	w = h = 0;
797 	gf_isom_get_visual_info(read->mov, track, stsd_idx, &w, &h);
798 	if (w && h) {
799 		u32 hspace, vspace;
800 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_WIDTH, &PROP_UINT(w));
801 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_HEIGHT, &PROP_UINT(h));
802 
803 		gf_isom_get_pixel_aspect_ratio(read->mov, track, stsd_idx, &hspace, &vspace);
804 		if (hspace != vspace)
805 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_SAR, &PROP_FRAC_INT(hspace, vspace) );
806 	}
807 	sr = nb_ch = nb_bps = 0;
808 	gf_isom_get_audio_info(read->mov,track, stsd_idx, &sr, &nb_ch, &nb_bps);
809 	if (sr && nb_ch) {
810 		u32 d1, d2;
811 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT(sr));
812 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(nb_ch));
813 
814 		//to remove once we deprecate master
815 		if (!gf_sys_old_arch_compat()) {
816 			GF_AudioChannelLayout layout;
817 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_AUDIO_BPS, &PROP_UINT(nb_bps));
818 
819 			if (gf_isom_get_audio_layout(read->mov, track, stsd_idx, &layout)==GF_OK) {
820 				if (layout.definedLayout) {
821 					u64 lay = gf_audio_fmt_get_layout_from_cicp(layout.definedLayout);
822 					gf_filter_pid_set_property(ch->pid, GF_PROP_PID_CHANNEL_LAYOUT, &PROP_LONGUINT(lay));
823 				}
824 
825 			}
826 
827 		}
828 
829 		if (first_config ) {
830 			d1 = gf_isom_get_sample_duration(read->mov, ch->track, 1);
831 			d2 = gf_isom_get_sample_duration(read->mov, ch->track, 2);
832 			if (d1 && d2 && (d1==d2)) {
833 				d1 *= sr;
834 				d1 /= ch->time_scale;
835 				gf_filter_pid_set_property(ch->pid, GF_PROP_PID_SAMPLES_PER_FRAME, &PROP_UINT(d1));
836 			}
837 		}
838 	}
839 
840 	gf_isom_get_bitrate(read->mov, ch->track, stsd_idx, &avg_rate, &max_rate, &buffer_size);
841 
842 	if (!avg_rate) {
843 		if (first_config && ch->duration) {
844 			u64 avgrate = 8 * gf_isom_get_media_data_size(read->mov, ch->track);
845 			avgrate = (u64) (avgrate / track_dur);
846 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_BITRATE, &PROP_UINT((u32) avgrate));
847 		}
848 	} else {
849 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_BITRATE, &PROP_UINT((u32) avg_rate));
850 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_MAXRATE, &PROP_UINT((u32) max_rate));
851 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_DBSIZE, &PROP_UINT((u32) buffer_size));
852 	}
853 
854 	if (mime) gf_filter_pid_set_property_str(ch->pid, "meta:mime", &PROP_STRING(mime) );
855 	if (encoding) gf_filter_pid_set_property_str(ch->pid, "meta:encoding", &PROP_STRING(encoding) );
856 	if (namespace) gf_filter_pid_set_property_str(ch->pid, "meta:xmlns", &PROP_STRING(namespace) );
857 	if (schemaloc) gf_filter_pid_set_property_str(ch->pid, "meta:schemaloc", &PROP_STRING(schemaloc) );
858 
859 	gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_SUBTYPE, &PROP_UINT(m_subtype) );
860 	if (stxtcfg) gf_filter_pid_set_property(ch->pid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA((char *)stxtcfg, (u32) strlen(stxtcfg) ));
861 
862 
863 #if !defined(GPAC_DISABLE_ISOM_WRITE)
864 	tk_template=NULL;
865 	tk_template_size=0;
866 	e = gf_isom_get_stsd_template(read->mov, ch->track, stsd_idx, &tk_template, &tk_template_size);
867 	if (e == GF_OK) {
868 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_ISOM_STSD_TEMPLATE, &PROP_DATA_NO_COPY(tk_template, tk_template_size) );
869 	} else {
870 		GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Failed to serialize stsd box: %s\n", gf_error_to_string(e) ));
871 	}
872 #endif
873 
874 	if (codec_id == GF_CODECID_DIMS) {
875 		GF_DIMSDescription dims;
876 		memset(&dims, 0, sizeof(GF_DIMSDescription));
877 
878 		gf_isom_get_dims_description(read->mov, ch->track, stsd_idx, &dims);
879 		gf_filter_pid_set_property_str(ch->pid, "dims:profile", &PROP_UINT(dims.profile));
880 		gf_filter_pid_set_property_str(ch->pid, "dims:level", &PROP_UINT(dims.level));
881 		gf_filter_pid_set_property_str(ch->pid, "dims:pathComponents", &PROP_UINT(dims.pathComponents));
882 		gf_filter_pid_set_property_str(ch->pid, "dims:fullRequestHost", &PROP_BOOL(dims.fullRequestHost));
883 		gf_filter_pid_set_property_str(ch->pid, "dims:streamType", &PROP_BOOL(dims.streamType));
884 		gf_filter_pid_set_property_str(ch->pid, "dims:redundant", &PROP_BOOL(dims.containsRedundant));
885 		if (dims.content_script_types)
886 			gf_filter_pid_set_property_str(ch->pid, "dims:scriptTypes", &PROP_STRING(dims.content_script_types));
887 		if (dims.textEncoding)
888 			gf_filter_pid_set_property_str(ch->pid, "meta:encoding", &PROP_STRING(dims.textEncoding));
889 		if (dims.contentEncoding)
890 			gf_filter_pid_set_property_str(ch->pid, "meta:content_encoding", &PROP_STRING(dims.contentEncoding));
891 		if (dims.xml_schema_loc)
892 			gf_filter_pid_set_property_str(ch->pid, "meta:schemaloc", &PROP_STRING(dims.xml_schema_loc));
893 		if (dims.mime_type)
894 			gf_filter_pid_set_property_str(ch->pid, "meta:mime", &PROP_STRING(dims.mime_type));
895 	}
896 	else if (codec_id==GF_CODECID_AVC)
897 		ch->check_avc_ps = GF_TRUE;
898 	else if (codec_id==GF_CODECID_HEVC)
899 		ch->check_hevc_ps = GF_TRUE;
900 
901 	if (udesc) {
902 		gf_filter_pid_set_property_str(ch->pid, "codec_vendor", &PROP_UINT(udesc->vendor_code));
903 		gf_filter_pid_set_property_str(ch->pid, "codec_version", &PROP_UINT(udesc->version));
904 		gf_filter_pid_set_property_str(ch->pid, "codec_revision", &PROP_UINT(udesc->revision));
905 		gf_filter_pid_set_property_str(ch->pid, "compressor_name", &PROP_STRING(udesc->compressor_name));
906 		gf_filter_pid_set_property_str(ch->pid, "temporal_quality", &PROP_UINT(udesc->temporal_quality));
907 		gf_filter_pid_set_property_str(ch->pid, "spatial_quality", &PROP_UINT(udesc->spatial_quality));
908 		if (udesc->h_res) {
909 			gf_filter_pid_set_property_str(ch->pid, "hres", &PROP_UINT(udesc->h_res));
910 			gf_filter_pid_set_property_str(ch->pid, "vres", &PROP_UINT(udesc->v_res));
911 		} else if (udesc->nb_channels) {
912 			gf_filter_pid_set_property(ch->pid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(udesc->nb_channels));
913 			switch (udesc->bits_per_sample) {
914 			case 8:
915 				gf_filter_pid_set_property(ch->pid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_U8));
916 				break;
917 			case 16:
918 				gf_filter_pid_set_property(ch->pid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_S16));
919 				break;
920 			case 24:
921 				gf_filter_pid_set_property(ch->pid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_S24));
922 				break;
923 			case 32:
924 				gf_filter_pid_set_property(ch->pid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_S32));
925 				break;
926 			default:
927 				GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Track %d unsupported audio bit depth %d\n", track, udesc->bits_per_sample ));
928 				break;
929 			}
930 		}
931 		gf_filter_pid_set_property(ch->pid, GF_PROP_PID_BIT_DEPTH_Y, &PROP_UINT(udesc->depth));
932 
933 		gf_free(udesc);
934 	}
935 
936 
937 	if (ch->check_avc_ps) {
938 		ch->avcc = gf_isom_avc_config_get(ch->owner->mov, ch->track, ch->last_sample_desc_index ? ch->last_sample_desc_index : 1);
939 	}
940 	else if (ch->check_hevc_ps) {
941 		ch->hvcc = gf_isom_hevc_config_get(ch->owner->mov, ch->track, ch->last_sample_desc_index ? ch->last_sample_desc_index : 1);
942 	}
943 }
944 
isor_update_channel_config(ISOMChannel * ch)945 void isor_update_channel_config(ISOMChannel *ch)
946 {
947 	isor_declare_track(ch->owner, ch, ch->track, ch->last_sample_desc_index, GF_STREAM_UNKNOWN, GF_FALSE);
948 
949 }
950 
isor_declare_objects(ISOMReader * read)951 GF_Err isor_declare_objects(ISOMReader *read)
952 {
953 	const u8 *tag;
954 	u32 tlen;
955 	u32 i, count, j, track_id;
956 	Bool highest_stream;
957 	Bool single_media_found = GF_FALSE;
958 	Bool use_iod = GF_FALSE;
959 	GF_Err e;
960 	Bool isom_contains_video = GF_FALSE;
961 	GF_Descriptor *od = gf_isom_get_root_od(read->mov);
962 	if (od && gf_list_count(((GF_ObjectDescriptor*)od)->ESDescriptors)) {
963 		use_iod = GF_TRUE;
964 	}
965 	if (od) gf_odf_desc_del(od);
966 
967 	/*TODO
968 	 check for alternate tracks
969     */
970 	count = gf_isom_get_track_count(read->mov);
971 	for (i=0; i<count; i++) {
972 		u32 mtype, m_subtype, streamtype, stsd_idx;
973 
974 		mtype = gf_isom_get_media_type(read->mov, i+1);
975 
976 		if (read->tkid) {
977 			u32 for_id=0;
978 			if (sscanf(read->tkid, "%d", &for_id)) {
979 				u32 id = gf_isom_get_track_id(read->mov, i+1);
980 				if (id != for_id) continue;
981 			} else if (!strcmp(read->tkid, "audio")) {
982 				if (mtype!=GF_ISOM_MEDIA_AUDIO) continue;
983 			} else if (!strcmp(read->tkid, "video")) {
984 				if (mtype!=GF_ISOM_MEDIA_VISUAL) continue;
985 			} else if (strlen(read->tkid)==4) {
986 				u32 t = GF_4CC(read->tkid[0], read->tkid[1], read->tkid[2], read->tkid[3]);
987 				if (mtype!=t) continue;
988 			} else {
989 				GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[IsoMedia] Bad format for tkid option %s, no match\n", read->tkid));
990 				return GF_BAD_PARAM;
991 			}
992 		}
993 
994 		switch (mtype) {
995 		case GF_ISOM_MEDIA_AUDIO:
996 			streamtype = GF_STREAM_AUDIO;
997 			break;
998 		case GF_ISOM_MEDIA_VISUAL:
999 		case GF_ISOM_MEDIA_AUXV:
1000 		case GF_ISOM_MEDIA_PICT:
1001 		case GF_ISOM_MEDIA_QTVR:
1002 			streamtype = GF_STREAM_VISUAL;
1003 			isom_contains_video = GF_TRUE;
1004 			break;
1005 		case GF_ISOM_MEDIA_TEXT:
1006 		case GF_ISOM_MEDIA_SUBT:
1007 		case GF_ISOM_MEDIA_SUBPIC:
1008 		case GF_ISOM_MEDIA_MPEG_SUBT:
1009 		case GF_ISOM_MEDIA_CLOSED_CAPTION:
1010 			streamtype = GF_STREAM_TEXT;
1011 			break;
1012 		case GF_ISOM_MEDIA_FLASH:
1013 		case GF_ISOM_MEDIA_DIMS:
1014 		case GF_ISOM_MEDIA_SCENE:
1015 			streamtype = GF_STREAM_SCENE;
1016 			break;
1017 		case GF_ISOM_MEDIA_OD:
1018 			streamtype = GF_STREAM_OD;
1019 			break;
1020 		case GF_ISOM_MEDIA_META:
1021 		case GF_ISOM_MEDIA_TIMECODE:
1022 			streamtype = GF_STREAM_METADATA;
1023 			break;
1024 		/*hint tracks are never exported*/
1025 		case GF_ISOM_MEDIA_HINT:
1026 			continue;
1027 		default:
1028 			if (!read->allt) {
1029 				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) ));
1030 				continue;
1031 			}
1032 			streamtype = GF_STREAM_UNKNOWN;
1033 			break;
1034 		}
1035 
1036 		if (!read->alltk && !read->tkid && !gf_isom_is_track_enabled(read->mov, i+1)) {
1037 			if (count>1) {
1038 				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));
1039 				continue;
1040 			} else {
1041 				GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] Track %d is disabled but single track in file, considering it enabled\n", i+1 ));
1042 			}
1043 		}
1044 
1045 		stsd_idx = read->stsd ? read->stsd : 1;
1046 		//some subtypes are not declared as readable objects
1047 		m_subtype = gf_isom_get_media_subtype(read->mov, i+1, stsd_idx);
1048 		switch (m_subtype) {
1049 		case GF_ISOM_SUBTYPE_HVT1:
1050 			if (read->smode == MP4DMX_SINGLE)
1051 				continue;
1052 
1053 			break;
1054 		default:
1055 			break;
1056 		}
1057 
1058 		/*we declare only the highest video track (i.e the track we play)*/
1059 		highest_stream = GF_TRUE;
1060 		track_id = gf_isom_get_track_id(read->mov, i+1);
1061 		if (read->play_only_track_id && (read->play_only_track_id != track_id)) continue;
1062 
1063 		if (read->play_only_first_media) {
1064 			if (read->play_only_first_media != mtype) continue;
1065 			if (single_media_found) continue;
1066 			single_media_found = GF_TRUE;
1067 		}
1068 
1069 		for (j = 0; j < count; j++) {
1070 			if (gf_isom_has_track_reference(read->mov, j+1, GF_ISOM_REF_SCAL, track_id) > 0) {
1071 				highest_stream = GF_FALSE;
1072 				break;
1073 			}
1074 			if (gf_isom_has_track_reference(read->mov, j+1, GF_ISOM_REF_BASE, track_id) > 0) {
1075 				highest_stream = GF_FALSE;
1076 				break;
1077 			}
1078 		}
1079 
1080 		if ((read->smode==MP4DMX_SINGLE) && (gf_isom_get_media_type(read->mov, i+1) == GF_ISOM_MEDIA_VISUAL) && !highest_stream)
1081 			continue;
1082 
1083 
1084 		isor_declare_track(read, NULL, i+1, stsd_idx, streamtype, use_iod);
1085 
1086 		if (read->tkid)
1087 			break;
1088 	}
1089 
1090 	if (!read->tkid) {
1091 		/*declare image items*/
1092 		count = gf_isom_get_meta_item_count(read->mov, GF_TRUE, 0);
1093 		for (i=0; i<count; i++) {
1094 			if (! isor_declare_item_properties(read, NULL, i+1))
1095 				continue;
1096 
1097 			if (read->itt) break;
1098 		}
1099 	}
1100 
1101 	/*if cover art, declare a video pid*/
1102 	if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_COVER_ART, &tag, &tlen)==GF_OK) {
1103 
1104 		/*write cover data*/
1105 		assert(!(tlen & 0x80000000));
1106 		tlen &= 0x7FFFFFFF;
1107 
1108 		if (read->expart && !isom_contains_video) {
1109 			GF_FilterPid *cover_pid=NULL;
1110 			gf_filter_pid_set_property(cover_pid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_FILE) );
1111 
1112 			e = gf_filter_pid_raw_new(read->filter, NULL, NULL, NULL, NULL, (char *) tag, tlen, GF_FALSE, &cover_pid);
1113 			if (e) {
1114 				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[MP3Dmx] error setting up video pid for cover art: %s\n", gf_error_to_string(e) ));
1115 			}
1116 			if (cover_pid) {
1117 				u8 *out_buffer;
1118 				GF_FilterPacket *dst_pck;
1119 				gf_filter_pid_set_name(cover_pid, "CoverArt");
1120 				dst_pck = gf_filter_pck_new_alloc(cover_pid, tlen, &out_buffer);
1121 				gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
1122 				memcpy(out_buffer, tag, tlen);
1123 				gf_filter_pck_send(dst_pck);
1124 				gf_filter_pid_set_eos(cover_pid);
1125 			}
1126 		}
1127 	}
1128 	return GF_OK;
1129 }
1130 
isor_declare_item_properties(ISOMReader * read,ISOMChannel * ch,u32 item_idx)1131 Bool isor_declare_item_properties(ISOMReader *read, ISOMChannel *ch, u32 item_idx)
1132 {
1133 	GF_ImageItemProperties props;
1134 	GF_FilterPid *pid;
1135 	GF_ESD *esd;
1136 	u32 item_id=0;
1137 	const char *item_name, *item_mime_type, *item_encoding;
1138 
1139 	if (item_idx>gf_isom_get_meta_item_count(read->mov, GF_TRUE, 0))
1140 		return GF_FALSE;
1141 
1142 	item_name = item_mime_type = item_encoding = NULL;
1143 	gf_isom_get_meta_item_info(read->mov, GF_TRUE, 0, item_idx, &item_id, NULL, NULL, NULL, NULL, NULL, &item_name, &item_mime_type, &item_encoding);
1144 
1145 	if (!item_id) return GF_FALSE;
1146 
1147 	gf_isom_get_meta_image_props(read->mov, GF_TRUE, 0, item_id, &props);
1148 
1149 	esd = gf_media_map_item_esd(read->mov, item_id);
1150 	if (!esd) return GF_FALSE;
1151 
1152 	//OK declare PID
1153 	if (!ch)
1154 		pid = gf_filter_pid_new(read->filter);
1155 	else
1156 		pid = ch->pid;
1157 
1158 	if (read->pid)
1159 		gf_filter_pid_copy_properties(pid, read->pid);
1160 
1161 	gf_filter_pid_set_property(pid, GF_PROP_PID_ID, &PROP_UINT(esd->ESID));
1162 	if (read->itemid)
1163 		gf_filter_pid_set_property(pid, GF_PROP_PID_ITEM_ID, &PROP_UINT(item_id));
1164 
1165 	//TODO: no support for LHEVC images
1166 	//gf_filter_pid_set_property(pid, GF_PROP_PID_DEPENDENCY_ID, &PROP_UINT(esd->dependsOnESID));
1167 
1168 	gf_filter_pid_set_property(pid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(esd->decoderConfig->streamType));
1169 	gf_filter_pid_set_property(pid, GF_PROP_PID_CODECID, &PROP_UINT(esd->decoderConfig->objectTypeIndication));
1170 	gf_filter_pid_set_property(pid, GF_PROP_PID_TIMESCALE, &PROP_UINT(1000));
1171 	if (esd->decoderConfig->decoderSpecificInfo) {
1172 		gf_filter_pid_set_property(pid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA_NO_COPY(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength));
1173 
1174 		esd->decoderConfig->decoderSpecificInfo->data=NULL;
1175 		esd->decoderConfig->decoderSpecificInfo->dataLength=0;
1176 	}
1177 
1178 	if (props.width && props.height) {
1179 		gf_filter_pid_set_property(pid, GF_PROP_PID_WIDTH, &PROP_UINT(props.width));
1180 		gf_filter_pid_set_property(pid, GF_PROP_PID_HEIGHT, &PROP_UINT(props.height));
1181 	}
1182 	if (props.hidden) {
1183 		gf_filter_pid_set_property(pid, GF_PROP_PID_HIDDEN, &PROP_BOOL(props.hidden));
1184 	}
1185 	gf_odf_desc_del((GF_Descriptor *)esd);
1186 
1187 	if (gf_isom_get_meta_primary_item_id(read->mov, GF_TRUE, 0) == item_id) {
1188 		gf_filter_pid_set_property(pid, GF_PROP_PID_PRIMARY_ITEM, &PROP_BOOL(GF_TRUE));
1189 	} else {
1190 		gf_filter_pid_set_property(pid, GF_PROP_PID_PRIMARY_ITEM, &PROP_BOOL(GF_FALSE));
1191 	}
1192 
1193 	gf_filter_pid_set_property_str(pid, "meta:mime", item_mime_type ? &PROP_STRING(item_mime_type) : NULL );
1194 	gf_filter_pid_set_property_str(pid, "meta:name", item_name ? &PROP_STRING(item_name) : NULL );
1195 	gf_filter_pid_set_property_str(pid, "meta:encoding", item_encoding ? &PROP_STRING(item_encoding) : NULL );
1196 
1197 	if (!ch) {
1198 		/*ch = */isor_create_channel(read, pid, 0, item_id, GF_FALSE);
1199 	}
1200 	return GF_TRUE;
1201 }
1202 
1203 #endif /*GPAC_DISABLE_ISOM*/
1204 
1205 
1206 
1207