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