1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Jean Le Feuvre, Romain Bouqueau, Cyril Concolato
5  *			Copyright (c) Telecom ParisTech 2000-2020
6  *					All rights reserved
7  *
8  *  This file is part of GPAC / Media Tools sub-project
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 <gpac/filters.h>
27 #include <gpac/constants.h>
28 
29 
30 #include <gpac/internal/media_dev.h>
31 
32 #include <gpac/xml.h>
33 
34 
35 #ifndef GPAC_DISABLE_MEDIA_IMPORT
36 
gf_import_message(GF_MediaImporter * import,GF_Err e,char * format,...)37 GF_Err gf_import_message(GF_MediaImporter *import, GF_Err e, char *format, ...)
38 {
39 #ifndef GPAC_DISABLE_LOG
40 	if (gf_log_tool_level_on(GF_LOG_AUTHOR, e ? GF_LOG_WARNING : GF_LOG_INFO)) {
41 		va_list args;
42 		char szMsg[1024];
43 		va_start(args, format);
44 		vsnprintf(szMsg, 1024, format, args);
45 		va_end(args);
46 		GF_LOG((u32) (e ? GF_LOG_WARNING : GF_LOG_INFO), GF_LOG_AUTHOR, ("%s\n", szMsg) );
47 	}
48 #endif
49 	return e;
50 }
51 
52 
gf_media_update_bitrate_ex(GF_ISOFile * file,u32 track,Bool use_esd)53 static void gf_media_update_bitrate_ex(GF_ISOFile *file, u32 track, Bool use_esd)
54 {
55 #ifndef GPAC_DISABLE_ISOM_WRITE
56 	u32 i, count, timescale, db_size, cdur, csize;
57 	u64 time_wnd, max_rate, avg_rate, bitrate;
58 	Double br;
59 	GF_ISOSample sample;
60 
61 	db_size = 0;
62 	max_rate = avg_rate = time_wnd = bitrate = 0;
63 
64 	csize = 0;
65 	cdur = 0;
66 	if (gf_isom_get_media_type(file, track)==GF_ISOM_MEDIA_AUDIO) {
67 		csize = gf_isom_get_constant_sample_size(file, track);
68 		cdur = gf_isom_get_constant_sample_duration(file, track);
69 		if (cdur > 1) cdur = 0;
70 	}
71 
72 	memset(&sample, 0, sizeof(GF_ISOSample));
73 	timescale = gf_isom_get_media_timescale(file, track);
74 	count = gf_isom_get_sample_count(file, track);
75 
76 	if (csize && cdur) {
77 		db_size = 0;
78 		avg_rate = 8 * csize * timescale / cdur;
79 		bitrate = avg_rate;
80 	} else {
81 		u32 rate = 0;
82 		for (i=0; i<count; i++) {
83 			u32 di;
84 			GF_ISOSample *samp = gf_isom_get_sample_info_ex(file, track, i+1, &di, NULL, &sample);
85 			if (!samp) break;
86 
87 			if (samp->dataLength > db_size) db_size = samp->dataLength;
88 
89 			avg_rate += samp->dataLength;
90 			rate += samp->dataLength;
91 			if (samp->DTS > time_wnd + timescale) {
92 				if (rate > max_rate) max_rate = rate;
93 				time_wnd = samp->DTS;
94 				rate = 0;
95 			}
96 		}
97 	}
98 
99 	br = (Double) (s64) gf_isom_get_media_duration(file, track);
100 	br /= timescale;
101 	if (br) {
102 		GF_ESD *esd = NULL;
103 		if (!csize || !cdur) {
104 			bitrate = (u32) ((Double) (s64)avg_rate / br);
105 			bitrate *= 8;
106 			max_rate *= 8;
107 		}
108 		if (!max_rate) max_rate = bitrate;
109 
110 		if (use_esd) esd = gf_isom_get_esd(file, track, 1);
111 		if (esd && esd->decoderConfig) {
112 			esd->decoderConfig->avgBitrate = (u32) bitrate;
113 			esd->decoderConfig->maxBitrate = (u32) max_rate;
114 			esd->decoderConfig->bufferSizeDB = db_size;
115 			gf_isom_change_mpeg4_description(file, track, 1, esd);
116 		} else {
117 			/*move to bps*/
118 			gf_isom_update_bitrate(file, track, 1, (u32) bitrate, (u32) max_rate, db_size);
119 		}
120 		if (esd) gf_odf_desc_del((GF_Descriptor *)esd);
121 	}
122 #endif
123 }
124 
125 GF_EXPORT
gf_media_update_bitrate(GF_ISOFile * file,u32 track)126 void gf_media_update_bitrate(GF_ISOFile *file, u32 track)
127 {
128 	gf_media_update_bitrate_ex(file, track, GF_FALSE);
129 
130 }
gf_media_get_video_timing(Double fps,u32 * timescale,u32 * dts_inc)131 void gf_media_get_video_timing(Double fps, u32 *timescale, u32 *dts_inc)
132 {
133 	u32 fps_1000 = (u32) (fps*1000 + 0.5);
134 	/*handle all drop-frame formats*/
135 	if (fps_1000==29970) {
136 		*timescale = 30000;
137 		*dts_inc = 1001;
138 	}
139 	else if (fps_1000==23976) {
140 		*timescale = 24000;
141 		*dts_inc = 1001;
142 	}
143 	else if (fps_1000==59940) {
144 		*timescale = 60000;
145 		*dts_inc = 1001;
146 	} else {
147 		*timescale = fps_1000;
148 		*dts_inc = 1000;
149 	}
150 }
151 
152 
gf_import_afx_sc3dmc(GF_MediaImporter * import,Bool mult_desc_allowed)153 static GF_Err gf_import_afx_sc3dmc(GF_MediaImporter *import, Bool mult_desc_allowed)
154 {
155 	GF_Err e;
156 	Bool destroy_esd;
157 	u32 size, track, di, dsi_len;
158 	GF_ISOSample *samp;
159 	u32 codecid;
160 	char *dsi, *data;
161 
162 	if (import->flags & GF_IMPORT_PROBE_ONLY) {
163 		import->tk_info[0].track_num = 1;
164 		import->tk_info[0].stream_type = GF_STREAM_SCENE;
165 		import->tk_info[0].codecid = GF_CODECID_AFX;
166 		import->nb_tracks = 1;
167 		return GF_OK;
168 	}
169 
170 	e = gf_file_load_data(import->in_name, (u8 **) &data, &size);
171 	if (e) return gf_import_message(import, e, "Opening file %s failed", import->in_name);
172 
173 	if ((s32) size < 0) return GF_IO_ERR;
174 
175 	codecid = GF_CODECID_AFX;
176 
177 	dsi = (char *)gf_malloc(1);
178 	dsi_len = 1;
179 	dsi[0] = GPAC_AFX_SCALABLE_COMPLEXITY;
180 
181 	destroy_esd = GF_FALSE;
182 	if (!import->esd) {
183 		import->esd = gf_odf_desc_esd_new(0);
184 		destroy_esd = GF_TRUE;
185 	}
186 	/*update stream type/oti*/
187 	if (!import->esd->decoderConfig) import->esd->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG);
188 	if (!import->esd->slConfig) import->esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
189 	import->esd->decoderConfig->streamType = GF_STREAM_SCENE;
190 	import->esd->decoderConfig->objectTypeIndication = codecid;
191 	import->esd->decoderConfig->bufferSizeDB = size;
192 	import->esd->decoderConfig->avgBitrate = 8*size;
193 	import->esd->decoderConfig->maxBitrate = 8*size;
194 	import->esd->slConfig->timestampResolution = 1000;
195 
196 	if (!import->esd->decoderConfig->decoderSpecificInfo) import->esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
197 	if (import->esd->decoderConfig->decoderSpecificInfo->data) gf_free(import->esd->decoderConfig->decoderSpecificInfo->data);
198 	import->esd->decoderConfig->decoderSpecificInfo->data = dsi;
199 	import->esd->decoderConfig->decoderSpecificInfo->dataLength = dsi_len;
200 
201 
202 	track = 0;
203 	if (mult_desc_allowed)
204 		track = gf_isom_get_track_by_id(import->dest, import->esd->ESID);
205 	if (!track)
206 		track = gf_isom_new_track(import->dest, import->esd->ESID, GF_ISOM_MEDIA_SCENE, 1000);
207 	if (!track) {
208 		e = gf_isom_last_error(import->dest);
209 		goto exit;
210 	}
211 	gf_isom_set_track_enabled(import->dest, track, GF_TRUE);
212 	if (!import->esd->ESID) import->esd->ESID = gf_isom_get_track_id(import->dest, track);
213 	import->final_trackID = import->esd->ESID;
214 
215 	if (import->source_magic)
216 		gf_isom_set_track_magic(import->dest, track, import->source_magic);
217 
218 	e = gf_isom_new_mpeg4_description(import->dest, track, import->esd, (import->flags & GF_IMPORT_USE_DATAREF) ? import->in_name : NULL, NULL, &di);
219 	if (e) goto exit;
220 	//gf_isom_set_visual_info(import->dest, track, di, w, h);
221 	samp = gf_isom_sample_new();
222 	samp->IsRAP = RAP;
223 	samp->dataLength = size;
224 	if (import->initial_time_offset) samp->DTS = (u64) (import->initial_time_offset*1000);
225 
226 	gf_import_message(import, GF_OK, "%s import %s", "SC3DMC", import->in_name);
227 
228 	/*we must start a track from DTS = 0*/
229 	if (!gf_isom_get_sample_count(import->dest, track) && samp->DTS) {
230 		/*todo - we could add an edit list*/
231 		samp->DTS=0;
232 	}
233 
234 	gf_set_progress("Importing SC3DMC", 0, 1);
235 	if (import->flags & GF_IMPORT_USE_DATAREF) {
236 		e = gf_isom_add_sample_reference(import->dest, track, di, samp, (u64) 0);
237 	} else {
238 		samp->data = data;
239 		e = gf_isom_add_sample(import->dest, track, di, samp);
240 		samp->data = NULL;
241 	}
242 	gf_set_progress("Importing SC3DMC", 1, 1);
243 
244 	gf_isom_sample_del(&samp);
245 
246 exit:
247 	gf_free(data);
248 	if (import->esd && destroy_esd) {
249 		gf_odf_desc_del((GF_Descriptor *) import->esd);
250 		import->esd = NULL;
251 	}
252 	return e;
253 }
254 
gf_import_isomedia_track(GF_MediaImporter * import)255 static GF_Err gf_import_isomedia_track(GF_MediaImporter *import)
256 {
257 	GF_Err e;
258 	u64 offset, sampDTS, duration, dts_offset;
259 	Bool is_nalu_video=GF_FALSE, has_seig;
260 	u32 track, di, trackID, track_in, i, num_samples, mtype, w, h, sr, sbr_sr, ch, mstype, cur_extract_mode, cdur, bps;
261 	s32 trans_x, trans_y;
262 	s16 layer;
263 	char *lang;
264 	const char *orig_name = gf_url_get_resource_name(gf_isom_get_filename(import->orig));
265 	Bool sbr, ps;
266 	GF_ISOSample *samp;
267 	GF_ESD *origin_esd;
268 	GF_InitialObjectDescriptor *iod;
269 	Bool is_cenc;
270 	GF_ISOTrackCloneFlags clone_flags;
271 	sampDTS = 0;
272 	if (import->flags & GF_IMPORT_PROBE_ONLY) {
273 		for (i=0; i<gf_isom_get_track_count(import->orig); i++) {
274 			import->tk_info[i].track_num = gf_isom_get_track_id(import->orig, i+1);
275 			mtype = gf_isom_get_media_type(import->orig, i+1);
276 			switch (mtype) {
277 			case GF_ISOM_MEDIA_VISUAL:
278 				import->tk_info[i].stream_type = GF_STREAM_VISUAL;
279 				break;
280 			case GF_ISOM_MEDIA_AUDIO:
281 				import->tk_info[i].stream_type = GF_STREAM_AUDIO;
282 				break;
283 			case GF_ISOM_MEDIA_TEXT:
284 				import->tk_info[i].stream_type = GF_STREAM_TEXT;
285 				break;
286 			case GF_ISOM_MEDIA_SCENE:
287 				import->tk_info[i].stream_type = GF_STREAM_SCENE;
288 				break;
289 			default:
290 				import->tk_info[i].stream_type = mtype;
291 				break;
292 			}
293 			if (import->tk_info[i].stream_type == GF_STREAM_VISUAL) {
294 				gf_isom_get_visual_info(import->orig, i+1, 1, &import->tk_info[i].video_info.width, &import->tk_info[i].video_info.height);
295 			} else if (import->tk_info[i].stream_type == GF_STREAM_AUDIO) {
296 				gf_isom_get_audio_info(import->orig, i+1, 1, &import->tk_info[i].audio_info.sample_rate, &import->tk_info[i].audio_info.nb_channels, NULL);
297 			}
298 			lang = NULL;
299 			gf_isom_get_media_language(import->orig, i+1, &lang);
300 			if (lang) {
301 				import->tk_info[i].lang = GF_4CC(' ', lang[0], lang[1], lang[2]);
302 				gf_free(lang);
303 				lang = NULL;
304 			}
305 			gf_media_get_rfc_6381_codec_name(import->orig, i+1, import->tk_info[i].szCodecProfile, GF_FALSE, GF_FALSE);
306 
307 			import->nb_tracks ++;
308 		}
309 		return GF_OK;
310 	}
311 
312 	trackID = import->trackID;
313 	if (!trackID) {
314 		if (gf_isom_get_track_count(import->orig) != 1) return gf_import_message(import, GF_BAD_PARAM, "Several tracks in MP4 - please indicate track to import");
315 		trackID = gf_isom_get_track_id(import->orig, 1);
316 	}
317 	track_in = gf_isom_get_track_by_id(import->orig, trackID);
318 	if (!track_in) return gf_import_message(import, GF_URL_ERROR, "Cannot find track ID %d in file", trackID);
319 
320 	origin_esd = gf_isom_get_esd(import->orig, track_in, 1);
321 
322 	if (import->esd && origin_esd) {
323 		origin_esd->OCRESID = import->esd->OCRESID;
324 		/*there may be other things to import...*/
325 	}
326 	ps = GF_FALSE;
327 	sbr = GF_FALSE;
328 	sbr_sr = 0;
329 	w = h = 0;
330 	cur_extract_mode = gf_isom_get_nalu_extract_mode(import->orig, track_in);
331 	iod = (GF_InitialObjectDescriptor *) gf_isom_get_root_od(import->orig);
332 	if (iod && (iod->tag != GF_ODF_IOD_TAG)) {
333 		gf_odf_desc_del((GF_Descriptor *) iod);
334 		iod = NULL;
335 	}
336 	mtype = gf_isom_get_media_type(import->orig, track_in);
337 	if (mtype==GF_ISOM_MEDIA_VISUAL) {
338 		u8 PL = iod ? iod->visual_profileAndLevel : 0xFE;
339 		gf_isom_get_visual_info(import->orig, track_in, 1, &w, &h);
340 #ifndef GPAC_DISABLE_AV_PARSERS
341 		/*for MPEG-4 visual, always check size (don't trust input file)*/
342 		if (origin_esd && (origin_esd->decoderConfig->objectTypeIndication==GF_CODECID_MPEG4_PART2)) {
343 			GF_M4VDecSpecInfo dsi;
344 			gf_m4v_get_config(origin_esd->decoderConfig->decoderSpecificInfo->data, origin_esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi);
345 			w = dsi.width;
346 			h = dsi.height;
347 			PL = dsi.VideoPL;
348 		}
349 #endif
350 		gf_isom_set_pl_indication(import->dest, GF_ISOM_PL_VISUAL, PL);
351 	}
352 	else if (mtype==GF_ISOM_MEDIA_AUDIO) {
353 		u8 PL = iod ? iod->audio_profileAndLevel : 0xFE;
354 		bps = 16;
355 		sr = ch = sbr_sr = 0;
356 		sbr = GF_FALSE;
357 		ps = GF_FALSE;
358 		gf_isom_get_audio_info(import->orig, track_in, 1, &sr, &ch, &bps);
359 #ifndef GPAC_DISABLE_AV_PARSERS
360 		if (origin_esd && origin_esd->decoderConfig && (origin_esd->decoderConfig->objectTypeIndication==GF_CODECID_AAC_MPEG4)) {
361 			if (origin_esd->decoderConfig->decoderSpecificInfo) {
362 				GF_M4ADecSpecInfo dsi;
363 				gf_m4a_get_config(origin_esd->decoderConfig->decoderSpecificInfo->data, origin_esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi);
364 				sr = dsi.base_sr;
365 				if (dsi.has_sbr) sbr_sr = dsi.sbr_sr;
366 				ch = dsi.nb_chan;
367 				PL = dsi.audioPL;
368 				sbr = dsi.has_sbr ? ((dsi.base_object_type==GF_M4A_AAC_SBR || dsi.base_object_type==GF_M4A_AAC_PS) ? 2 : 1) : GF_FALSE;
369 				ps = dsi.has_ps;
370 			} else {
371 				GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("Missing DecoderSpecificInfo in MPEG-4 AAC stream\n"));
372 			}
373 		}
374 #endif
375 		gf_isom_set_pl_indication(import->dest, GF_ISOM_PL_AUDIO, PL);
376 	}
377 	else if (mtype==GF_ISOM_MEDIA_SUBPIC) {
378 		w = h = 0;
379 		trans_x = trans_y = 0;
380 		layer = 0;
381 		if (origin_esd && origin_esd->decoderConfig->objectTypeIndication == GF_CODECID_SUBPIC) {
382 			gf_isom_get_track_layout_info(import->orig, track_in, &w, &h, &trans_x, &trans_y, &layer);
383 		}
384 	}
385 
386 	gf_odf_desc_del((GF_Descriptor *) iod);
387 	if ( ! gf_isom_get_track_count(import->dest)) {
388 		u32 timescale = gf_isom_get_timescale(import->orig);
389 		gf_isom_set_timescale(import->dest, timescale);
390 	}
391 	clone_flags = GF_ISOM_CLONE_TRACK_NO_QT;
392 	if (import->asemode == GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_QTFF) {
393 		clone_flags = 0;
394 	} else {
395 		const char *dst = gf_isom_get_filename(import->dest);
396 		if (dst && strstr(dst, ".mov"))
397 			clone_flags = 0;
398 	}
399 
400 	if (import->flags & GF_IMPORT_USE_DATAREF) clone_flags |= GF_ISOM_CLONE_TRACK_KEEP_DREF;
401 	e = gf_isom_clone_track(import->orig, track_in, import->dest, clone_flags, &track);
402 	if (e) goto exit;
403 
404 	di = 1;
405 
406 	if (import->esd && import->esd->ESID) {
407 		e = gf_isom_set_track_id(import->dest, track, import->esd->ESID);
408 		if (e) goto exit;
409 	}
410 
411 	import->final_trackID = gf_isom_get_track_id(import->dest, track);
412 	if (import->esd && import->esd->dependsOnESID) {
413 		gf_isom_set_track_reference(import->dest, track, GF_ISOM_REF_DECODE, import->esd->dependsOnESID);
414 	}
415 
416 	if (import->trackID && !(import->flags & GF_IMPORT_KEEP_REFS)) {
417 		gf_isom_remove_track_references(import->dest, track);
418 	}
419 
420 	if (import->source_magic)
421 		gf_isom_set_track_magic(import->dest, track, import->source_magic);
422 
423 	mstype = gf_isom_get_media_subtype(import->orig, track_in, di);
424 	switch (mtype) {
425 	case GF_ISOM_MEDIA_VISUAL:
426 		gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - Video (size %d x %d)", orig_name, trackID, w, h);
427 		break;
428     case GF_ISOM_MEDIA_AUXV:
429         gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - Auxiliary Video (size %d x %d)", orig_name, trackID, w, h);
430         break;
431     case GF_ISOM_MEDIA_PICT:
432         gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - Picture sequence (size %d x %d)", orig_name, trackID, w, h);
433         break;
434 	case GF_ISOM_MEDIA_AUDIO:
435 	{
436 		if (ps) {
437 			gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - HE-AACv2 (SR %d - SBR-SR %d - %d channels)", orig_name, trackID, sr, sbr_sr, ch);
438 		} else if (sbr) {
439 			gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - HE-AAC (SR %d - SBR-SR %d - %d channels)", orig_name, trackID, sr, sbr_sr, ch);
440 		} else {
441 			gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - Audio (SR %d - %d channels)", orig_name, trackID, sr, ch);
442 		}
443 		if (import->asemode != GF_IMPORT_AUDIO_SAMPLE_ENTRY_NOT_SET) {
444 			gf_isom_get_audio_info(import->orig, track_in, 1, &sr, &ch, &bps);
445 			gf_isom_set_audio_info(import->dest, track, 1, sr, ch, bps, import->asemode);
446 		}
447 	}
448 	break;
449 	case GF_ISOM_MEDIA_SUBPIC:
450 		gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - VobSub (size %d x %d)", orig_name, trackID, w, h);
451 		break;
452 	default:
453 	{
454 		char szT[GF_4CC_MSIZE];
455 		mstype = gf_isom_get_mpeg4_subtype(import->orig, track_in, di);
456 		if (!mstype) mstype = gf_isom_get_media_subtype(import->orig, track_in, di);
457 		strcpy(szT, gf_4cc_to_str(mtype));
458 		gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - media type \"%s:%s\"", orig_name, trackID, szT, gf_4cc_to_str(mstype));
459 	}
460 	break;
461 	}
462 
463 	//this may happen with fragmented files
464 	dts_offset = 0;
465 	samp = gf_isom_get_sample_info(import->orig, track_in, 1, &di, &offset);
466 	if (samp) {
467 		dts_offset = samp->DTS;
468 		gf_isom_sample_del(&samp);
469 	}
470 
471 	is_cenc = gf_isom_is_cenc_media(import->orig, track_in, 0);
472 	if (gf_isom_is_media_encrypted(import->orig, track_in, 0)) {
473 		gf_isom_get_original_format_type(import->orig, track_in, 0, &mstype);
474 	}
475 	has_seig = GF_FALSE;
476 	if (is_cenc && gf_isom_has_cenc_sample_group(import->orig, track_in)) {
477 		has_seig = GF_TRUE;
478 	}
479 
480 	cdur = gf_isom_get_constant_sample_duration(import->orig, track_in);
481 	gf_isom_enable_raw_pack(import->orig, track_in, 2048);
482 
483 	duration = 0;
484 	if ((import->duration.num>0) && import->duration.den) {
485 		duration = (u64) (((Double)import->duration.num * gf_isom_get_media_timescale(import->orig, track_in)) / import->duration.den);
486 	}
487 	gf_isom_set_nalu_extract_mode(import->orig, track_in, GF_ISOM_NALU_EXTRACT_INSPECT);
488 
489 	if (import->xps_inband) {
490 		if (is_cenc ) {
491 			GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[ISOM import] CENC media detected - cannot switch parameter set storage mode\n"));
492 		} else if (import->flags & GF_IMPORT_USE_DATAREF) {
493 			GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[ISOM import] Cannot switch parameter set storage mode when using data reference\n"));
494 		} else {
495 			switch (mstype) {
496 			case GF_ISOM_SUBTYPE_AVC_H264:
497 				gf_isom_set_nalu_extract_mode(import->orig, track_in, GF_ISOM_NALU_EXTRACT_INSPECT | GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG);
498 				gf_isom_avc_set_inband_config(import->dest, track, 1, (import->xps_inband==2) ? GF_TRUE : GF_FALSE);
499 				break;
500 			case GF_ISOM_SUBTYPE_HVC1:
501 				gf_isom_set_nalu_extract_mode(import->orig, track_in, GF_ISOM_NALU_EXTRACT_INSPECT | GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG);
502 				gf_isom_hevc_set_inband_config(import->dest, track, 1, (import->xps_inband==2) ? GF_TRUE : GF_FALSE);
503 				break;
504 			}
505 		}
506 	}
507 	switch (mstype) {
508 	case GF_ISOM_SUBTYPE_AVC_H264:
509 	case GF_ISOM_SUBTYPE_SVC_H264:
510 	case GF_ISOM_SUBTYPE_MVC_H264:
511 	case GF_ISOM_SUBTYPE_AVC2_H264:
512 	case GF_ISOM_SUBTYPE_AVC3_H264:
513 	case GF_ISOM_SUBTYPE_AVC4_H264:
514 	case GF_ISOM_SUBTYPE_HEV1:
515 	case GF_ISOM_SUBTYPE_HVC1:
516 	case GF_ISOM_SUBTYPE_LHE1:
517 	case GF_ISOM_SUBTYPE_LHV1:
518 	case GF_ISOM_SUBTYPE_HVT1:
519 		is_nalu_video = GF_TRUE;
520 		break;
521 	}
522 	num_samples = gf_isom_get_sample_count(import->orig, track_in);
523 
524 	if (is_cenc) {
525 		u32 container_type;
526 		e = gf_isom_cenc_get_sample_aux_info(import->orig, track_in, 0, 1, NULL, &container_type);
527 		if (e)
528 			goto exit;
529 		e = gf_isom_cenc_allocate_storage(import->dest, track, container_type, 0, 0, NULL);
530 		if (e) goto exit;
531 		e = gf_isom_clone_pssh(import->dest, import->orig, GF_FALSE);
532 		if (e) goto exit;
533 	}
534 	for (i=0; i<num_samples; i++) {
535 		if (import->flags & GF_IMPORT_USE_DATAREF) {
536 			samp = gf_isom_get_sample_info(import->orig, track_in, i+1, &di, &offset);
537 			if (!samp) {
538 				e = gf_isom_last_error(import->orig);
539 				goto exit;
540 			}
541 			samp->DTS -= dts_offset;
542 			e = gf_isom_add_sample_reference(import->dest, track, di, samp, offset);
543 		} else {
544 			samp = gf_isom_get_sample(import->orig, track_in, i+1, &di);
545 			if (!samp) {
546 				/*couldn't get the sample, but still move on*/
547 				goto exit;
548 			}
549 			samp->DTS -= dts_offset;
550 
551 			/*if packed samples (raw) and import duration is set, adjust the number of samples to add*/
552 			if (samp->nb_pack && duration && (samp->DTS + samp->nb_pack*cdur > duration) ) {
553 				u32 nb_samp = (u32) ( (duration - samp->DTS) / cdur);
554 				u32 csize = samp->dataLength / samp->nb_pack;
555 				if (!nb_samp) {
556 					gf_isom_sample_del(&samp);
557 					break;
558 				}
559 				samp->dataLength = csize*nb_samp;
560 				samp->nb_pack = nb_samp;
561 				duration = samp->DTS-1;
562 			}
563 
564 			/*if not first sample and same DTS as previous sample, force DTS++*/
565 			if (i && (samp->DTS<=sampDTS)) {
566 				if (i+1 < num_samples) {
567 					GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[ISOM import] 0-duration sample detected at DTS %u - adjusting\n", samp->DTS));
568 				}
569 				samp->DTS = sampDTS + 1;
570 			}
571 			e = gf_isom_add_sample(import->dest, track, di, samp);
572 		}
573 		sampDTS = samp->DTS;
574 		if (samp->nb_pack)
575 			i+= samp->nb_pack-1;
576 		gf_isom_sample_del(&samp);
577 
578 		gf_isom_copy_sample_info(import->dest, track, import->orig, track_in, i+1);
579 
580 		if (e)
581 			goto exit;
582 		if (is_cenc) {
583 			GF_CENCSampleAuxInfo *sai;
584 			u32 container_type, len, j;
585 			Bool Is_Encrypted;
586 			u8 IV_size;
587 			bin128 KID;
588 			u8 crypt_byte_block, skip_byte_block;
589 			u8 constant_IV_size;
590 			bin128 constant_IV;
591 			GF_BitStream *bs;
592 			u8 *buffer;
593 
594 			sai = NULL;
595 			e = gf_isom_cenc_get_sample_aux_info(import->orig, track_in, i+1, di, &sai, &container_type);
596 			if (e)
597 				goto exit;
598 
599 			e = gf_isom_get_sample_cenc_info(import->orig, track_in, i+1, &Is_Encrypted, &IV_size, &KID, &crypt_byte_block, &skip_byte_block, &constant_IV_size, &constant_IV);
600 			if (e) goto exit;
601 
602 			if (Is_Encrypted) {
603 				bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
604 				gf_bs_write_data(bs, (const char *)sai->IV, IV_size);
605 				if (sai->subsample_count) {
606 					gf_bs_write_u16(bs, sai->subsample_count);
607 					for (j = 0; j < sai->subsample_count; j++) {
608 						gf_bs_write_u16(bs, sai->subsamples[j].bytes_clear_data);
609 						gf_bs_write_u32(bs, sai->subsamples[j].bytes_encrypted_data);
610 					}
611 				}
612 				gf_isom_cenc_samp_aux_info_del(sai);
613 				gf_bs_get_content(bs, &buffer, &len);
614 				gf_bs_del(bs);
615 				e = gf_isom_track_cenc_add_sample_info(import->dest, track, container_type, IV_size, buffer, len, is_nalu_video, NULL, GF_FALSE);
616 				gf_free(buffer);
617 			} else {
618 				e = gf_isom_track_cenc_add_sample_info(import->dest, track, container_type, IV_size, NULL, 0, is_nalu_video, NULL, GF_FALSE);
619 			}
620 			if (e) goto exit;
621 
622 			if (has_seig) {
623 				e = gf_isom_set_sample_cenc_group(import->dest, track, i+1, Is_Encrypted, IV_size, KID, crypt_byte_block, skip_byte_block, constant_IV_size, constant_IV);
624 				if (e) goto exit;
625 			}
626 		}
627 
628 		gf_set_progress("Importing ISO File", i+1, num_samples);
629 		if (duration && (sampDTS > duration) ) break;
630 	}
631 
632 	//adjust last sample duration
633 	if (i==num_samples) {
634 		u32 dur = gf_isom_get_sample_duration(import->orig, track_in, num_samples);
635 		gf_isom_set_last_sample_duration(import->dest, track, dur);
636 	} else {
637 		s64 mediaOffset;
638 		if (gf_isom_get_edit_list_type(import->orig, track_in, &mediaOffset)) {
639 			GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[ISOBMF Import] Multiple edits found in source media, import may be broken\n"));
640 		}
641 		gf_isom_update_edit_list_duration(import->dest, track);
642 		gf_isom_update_duration(import->dest);
643 	}
644 
645 	if (gf_isom_has_time_offset(import->orig, track_in)==2) {
646 		e = gf_isom_set_composition_offset_mode(import->dest, track, GF_TRUE);
647 		if (e)
648 			goto exit;
649 	}
650 
651 
652 	if (import->esd) {
653 		if (!import->esd->slConfig) {
654 			import->esd->slConfig = origin_esd ? origin_esd->slConfig : NULL;
655 			if (origin_esd) origin_esd->slConfig = NULL;
656 		}
657 		if (!import->esd->decoderConfig) {
658 			import->esd->decoderConfig = origin_esd ? origin_esd->decoderConfig : NULL;
659 			if (origin_esd) origin_esd->decoderConfig = NULL;
660 		}
661 	}
662 	gf_media_update_bitrate_ex(import->dest, track, GF_TRUE);
663 	if (mtype == GF_ISOM_MEDIA_VISUAL) {
664 		if (import->is_alpha) {
665 			e = gf_isom_set_image_sequence_alpha(import->dest, track, di, GF_FALSE);
666 			if (e) goto exit;
667 		}
668 	}
669 
670 exit:
671 	if (origin_esd) gf_odf_desc_del((GF_Descriptor *) origin_esd);
672 	gf_isom_set_nalu_extract_mode(import->orig, track_in, cur_extract_mode);
673 	return e;
674 }
675 
gf_import_isomedia(GF_MediaImporter * import)676 static GF_Err gf_import_isomedia(GF_MediaImporter *import)
677 {
678 	u32 nb_tracks, i;
679 	if (import->trackID)
680 		return gf_import_isomedia_track(import);
681 
682 	if (!import->orig) return GF_BAD_PARAM;
683 
684 	nb_tracks = gf_isom_get_track_count(import->orig);
685 	for (i=0; i<nb_tracks; i++) {
686 		import->trackID = gf_isom_get_track_id(import->orig, i+1);
687 		if (import->trackID) {
688 			GF_Err e = gf_import_isomedia_track(import);
689 			import->trackID = 0;
690 			if (e) return e;
691 		}
692 	}
693 	return GF_OK;
694 }
695 
696 GF_EXPORT
gf_media_nal_rewrite_samples(GF_ISOFile * file,u32 track,u32 new_size)697 GF_Err gf_media_nal_rewrite_samples(GF_ISOFile *file, u32 track, u32 new_size)
698 {
699 	u32 i, count, di, remain, msize;
700 	char *buffer;
701 
702 	msize = 4096;
703 	buffer = (char*)gf_malloc(sizeof(char)*msize);
704 	count = gf_isom_get_sample_count(file, track);
705 	for (i=0; i<count; i++) {
706 		GF_ISOSample *samp = gf_isom_get_sample(file, track, i+1, &di);
707 		GF_BitStream *oldbs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ);
708 		GF_BitStream *newbs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
709 		u32 prev_size = 8*gf_isom_get_nalu_length_field(file, track, di);
710 		if (!prev_size) return GF_NON_COMPLIANT_BITSTREAM;
711 
712 		remain = samp->dataLength;
713 		while (remain) {
714 			u32 size = gf_bs_read_int(oldbs, prev_size);
715 			gf_bs_write_int(newbs, size, new_size);
716 			remain -= prev_size/8;
717 			if (size>msize) {
718 				msize = size;
719 				buffer = (char*)gf_realloc(buffer, sizeof(char)*msize);
720 			}
721 			gf_bs_read_data(oldbs, buffer, size);
722 			gf_bs_write_data(newbs, buffer, size);
723 			remain -= size;
724 		}
725 		gf_bs_del(oldbs);
726 		gf_free(samp->data);
727 		samp->data = NULL;
728 		samp->dataLength = 0;
729 		gf_bs_get_content(newbs, &samp->data, &samp->dataLength);
730 		gf_bs_del(newbs);
731 		gf_isom_update_sample(file, track, i+1, samp, GF_TRUE);
732 		gf_isom_sample_del(&samp);
733 	}
734 	gf_free(buffer);
735 	return GF_OK;
736 }
737 
738 GF_EXPORT
gf_media_import_chapters_file(GF_MediaImporter * import)739 GF_Err gf_media_import_chapters_file(GF_MediaImporter *import)
740 {
741 	s32 read=0;
742 	GF_Err e;
743 	u32 state, offset;
744 	u32 cur_chap;
745 	u64 ts;
746 	u32 i, h, m, s, ms, fr, fps;
747 	char line[1024];
748 	char szTitle[1024];
749 	FILE *f = gf_fopen(import->in_name, "rt");
750 	if (!f) return GF_URL_ERROR;
751 
752 	read = (s32) gf_fread(line, 4, f);
753 	if (read < 0) {
754 		e = GF_IO_ERR;
755 		goto err_exit;
756 	}
757 	if (read < 4) {
758 		e = GF_URL_ERROR;
759 		goto err_exit;
760 	}
761 
762 	if ((line[0]==(char)(0xFF)) && (line[1]==(char)(0xFE))) {
763 		if (!line[2] && !line[3]) {
764 			e = GF_NOT_SUPPORTED;
765 			goto err_exit;
766 		}
767 		offset = 2;
768 	} else if ((line[0]==(char)(0xFE)) && (line[1]==(char)(0xFF))) {
769 		if (!line[2] && !line[3]) {
770 			e = GF_NOT_SUPPORTED;
771 			goto err_exit;
772 		}
773 		offset = 2;
774 	} else if ((line[0]==(char)(0xEF)) && (line[1]==(char)(0xBB)) && (line[2]==(char)(0xBF))) {
775 		/*we handle UTF8 as asci*/
776 		offset = 3;
777 	} else {
778 		offset = 0;
779 	}
780 	gf_fseek(f, offset, SEEK_SET);
781 
782 	if (import->flags & GF_IMPORT_PROBE_ONLY) {
783 		Bool is_chap_or_sub = GF_FALSE;
784 		import->nb_tracks = 0;
785 		while (!is_chap_or_sub && (gf_fgets(line, 1024, f) != NULL)) {
786 			char *sep;
787 			strlwr(line);
788 
789 			if (strstr(line, "addchapter(")) is_chap_or_sub = GF_TRUE;
790 			else if (strstr(line, "-->")) is_chap_or_sub = GF_TRUE;
791 			else if ((sep = strstr(line, "chapter")) != NULL) {
792 				sep+=7;
793 				if (!strncmp(sep+1, "name", 4)) is_chap_or_sub = GF_TRUE;
794 				else if (!strncmp(sep+2, "name", 4)) is_chap_or_sub = GF_TRUE;
795 				else if (!strncmp(sep+3, "name", 4)) is_chap_or_sub = GF_TRUE;
796 				else if (strstr(line, "Zoom") || strstr(line, "zoom")) is_chap_or_sub = GF_TRUE;
797 			}
798 		}
799 		gf_fclose(f);
800 		if (is_chap_or_sub) {
801 			import->nb_tracks = 1;
802 			import->tk_info[0].stream_type = GF_STREAM_TEXT;
803 			import->tk_info[0].is_chapter = GF_TRUE;
804 			return GF_OK;
805 		}
806 		return GF_NOT_SUPPORTED;
807 	}
808 
809 	e = gf_isom_remove_chapter(import->dest, 0, 0);
810 	if (e) goto err_exit;
811 
812 	if (!import->video_fps.num || !import->video_fps.den ) {
813 		/*try to figure out the frame rate*/
814 		for (i=0; i<gf_isom_get_track_count(import->dest); i++) {
815 			GF_ISOSample *samp;
816 			u32 timescale, inc;
817             u32 mtype = gf_isom_get_media_type(import->dest, i+1);
818 			if (!gf_isom_is_video_handler_type(mtype)) continue;
819 			if (gf_isom_get_sample_count(import->dest, i+1) < 20) continue;
820 			samp = gf_isom_get_sample_info(import->dest, 1, 2, NULL, NULL);
821 			inc = (u32) samp->DTS;
822 			if (!inc) inc=1;
823 			timescale = gf_isom_get_media_timescale(import->dest, i+1);
824 			import->video_fps.num = timescale;
825 			import->video_fps.den = inc;
826 			gf_isom_sample_del(&samp);
827 			GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[Chapter import] Guessed video frame rate %u/%u\n", timescale, inc));
828 			break;
829 		}
830 		if (!import->video_fps.num || !import->video_fps.den) {
831 			import->video_fps.num = 25;
832 			import->video_fps.den = 1;
833 		}
834 	}
835 
836 	cur_chap = 0;
837 	ts = 0;
838 	state = 0;
839 	while (gf_fgets(line, 1024, f) != NULL) {
840 		char *title = NULL;
841 		u32 off = 0;
842 		char *sL;
843 		while (1) {
844 			u32 len = (u32) strlen(line);
845 			if (!len) break;
846 			switch (line[len-1]) {
847 			case '\n':
848 			case '\t':
849 			case '\r':
850 			case ' ':
851 				line[len-1] = 0;
852 				continue;
853 			}
854 			break;
855 		}
856 
857 		while (line[off]==' ') off++;
858 		if (!strlen(line+off)) continue;
859 		sL = line+off;
860 
861 		szTitle[0] = 0;
862 		/*ZoomPlayer chapters*/
863 		if (!strnicmp(sL, "AddChapter(", 11)) {
864 			u32 nb_fr;
865 			sscanf(sL, "AddChapter(%u,%1023s)", &nb_fr, szTitle);
866 			ts = nb_fr;
867 			ts *= 1000;
868 			ts = (u64) (((s64) ts )  *import->video_fps.den / import->video_fps.num);
869 			sL = strchr(sL, ',');
870 			strcpy(szTitle, sL+1);
871 			sL = strrchr(szTitle, ')');
872 			if (sL) sL[0] = 0;
873 		} else if (!strnicmp(sL, "AddChapterBySecond(", 19)) {
874 			u32 nb_s;
875 			sscanf(sL, "AddChapterBySecond(%u,%1023s)", &nb_s, szTitle);
876 			ts = nb_s;
877 			ts *= 1000;
878 			sL = strchr(sL, ',');
879 			strcpy(szTitle, sL+1);
880 			sL = strrchr(szTitle, ')');
881 			if (sL) sL[0] = 0;
882 		} else if (!strnicmp(sL, "AddChapterByTime(", 17)) {
883 			sscanf(sL, "AddChapterByTime(%u,%u,%u,%1023s)", &h, &m, &s, szTitle);
884 			ts = 3600*h + 60*m + s;
885 			ts *= 1000;
886 			sL = strchr(sL, ',');
887 			if (sL) sL = strchr(sL+1, ',');
888 			if (sL) sL = strchr(sL+1, ',');
889 			if (sL) strcpy(szTitle, sL+1);
890 			sL = strrchr(szTitle, ')');
891 			if (sL) sL[0] = 0;
892 		}
893 		/*regular or SMPTE time codes*/
894 		else if ((strlen(sL)>=8) && (sL[2]==':') && (sL[5]==':')) {
895 			title = NULL;
896 			if (strlen(sL)==8) {
897 				sscanf(sL, "%02u:%02u:%02u", &h, &m, &s);
898 				ts = (h*3600 + m*60+s)*1000;
899 			}
900 			else {
901 				char szTS[20], *tok;
902 				strncpy(szTS, sL, 19);
903 				szTS[19]=0;
904 				tok = strrchr(szTS, ' ');
905 				if (tok) {
906 					title = strchr(sL, ' ') + 1;
907 					while (title[0]==' ') title++;
908 					if (strlen(title)) strcpy(szTitle, title);
909 					tok[0] = 0;
910 				}
911 				ts = 0;
912 				h = m = s = ms = 0;
913 
914 				if (sscanf(szTS, "%u:%u:%u;%u/%u", &h, &m, &s, &fr, &fps)==5) {
915 					ts = (h*3600 + m*60+s)*1000 + 1000*fr/fps;
916 				} else if (sscanf(szTS, "%u:%u:%u;%u", &h, &m, &s, &fr)==4) {
917 					ts = (h*3600 + m*60+s);
918 					ts = (s64) (((import->video_fps.num*((s64)ts) + import->video_fps.den*fr) * 1000 ) / import->video_fps.num ) ;
919 				} else if (sscanf(szTS, "%u:%u:%u.%u", &h, &m, &s, &ms) == 4) {
920 					//microseconds used
921 					if (ms>=1000) ms /= 1000;
922 					ts = (h*3600 + m*60+s)*1000+ms;
923 				} else if (sscanf(szTS, "%u:%u:%u.%u", &h, &m, &s, &ms) == 4) {
924 					//microseconds used
925 					if (ms>=1000) ms /= 1000;
926 					ts = (h*3600 + m*60+s)*1000+ms;
927 				} else if (sscanf(szTS, "%u:%u:%u:%u", &h, &m, &s, &ms) == 4) {
928 					//microseconds used
929 					if (ms>=1000) ms /= 1000;
930 					ts = (h*3600 + m*60+s)*1000+ms;
931 				} else if (sscanf(szTS, "%u:%u:%u", &h, &m, &s) == 3) {
932 					ts = (h*3600 + m*60+s) * 1000;
933 				}
934 			}
935 		}
936 		/*CHAPTERX= and CHAPTERXNAME=*/
937 		else if (!strnicmp(sL, "CHAPTER", 7)) {
938 			u32 idx;
939 			char szTemp[20], *str;
940 			strncpy(szTemp, sL, 19);
941 			szTemp[19] = 0;
942 			str = strrchr(szTemp, '=');
943 			if (!str) continue;
944 			str[0] = 0;
945 			strlwr(szTemp);
946 			idx = cur_chap;
947 			str = strchr(sL, '=');
948 			str++;
949 			if (strstr(szTemp, "name")) {
950 				sscanf(szTemp, "chapter%uname", &idx);
951 				strcpy(szTitle, str);
952 				if (idx!=cur_chap) {
953 					cur_chap=idx;
954 					state = 0;
955 				}
956 				state++;
957 			} else {
958 				sscanf(szTemp, "chapter%u", &idx);
959 				if (idx!=cur_chap) {
960 					cur_chap=idx;
961 					state = 0;
962 				}
963 				state++;
964 
965 				ts = 0;
966 				h = m = s = ms = 0;
967 				if (sscanf(str, "%u:%u:%u.%u", &h, &m, &s, &ms) == 4) {
968 					//microseconds used
969 					if (ms>=1000) ms/=1000;
970 					ts = (h*3600 + m*60+s)*1000+ms;
971 				} else if (sscanf(str, "%u:%u:%u:%u", &h, &m, &s, &ms) == 4) {
972 					//microseconds used
973 					if (ms>=1000) ms/=1000;
974 					ts = (h*3600 + m*60+s)*1000+ms;
975 				} else if (sscanf(str, "%u:%u:%u", &h, &m, &s) == 3) {
976 					ts = (h*3600 + m*60+s) * 1000;
977 				}
978 			}
979 			if (state==2) {
980 				e = gf_isom_add_chapter(import->dest, 0, ts, szTitle);
981 				if (e) goto err_exit;
982 				state = 0;
983 			}
984 			continue;
985 		}
986 		else continue;
987 
988 		if (strlen(szTitle)) {
989 			e = gf_isom_add_chapter(import->dest, 0, ts, szTitle);
990 		} else {
991 			e = gf_isom_add_chapter(import->dest, 0, ts, NULL);
992 		}
993 		if (e) goto err_exit;
994 	}
995 
996 err_exit:
997 	gf_fclose(f);
998 	return e;
999 }
1000 
1001 GF_EXPORT
gf_media_import_chapters(GF_ISOFile * file,char * chap_file,GF_Fraction import_fps,Bool use_qt)1002 GF_Err gf_media_import_chapters(GF_ISOFile *file, char *chap_file, GF_Fraction import_fps, Bool use_qt)
1003 {
1004 	GF_Err e;
1005 	u32 i;
1006 	GF_MediaImporter import;
1007 	//remove all chapter info
1008 	gf_isom_remove_chapter(file, 0, 0);
1009 
1010 restart_check:
1011 	//remove all chapter tracks
1012 	for (i=0; i<gf_isom_get_track_count(file); i++) {
1013 		if (gf_isom_get_reference_count(file, i+1, GF_ISOM_REF_CHAP)) {
1014 			u32 chap_track=0;
1015 			gf_isom_get_reference(file, i+1, GF_ISOM_REF_CHAP, 1, &chap_track);
1016 			if (chap_track) {
1017 				gf_isom_remove_track(file, chap_track);
1018 				goto restart_check;
1019 			}
1020 		}
1021 	}
1022 
1023 	memset(&import, 0, sizeof(GF_MediaImporter));
1024 	import.dest = file;
1025 	import.in_name = chap_file;
1026 	import.video_fps = import_fps;
1027 	import.streamFormat = "CHAP";
1028 	e = gf_media_import(&import);
1029 	if (e) return e;
1030 
1031 	if (!import.final_trackID) return GF_OK;
1032 	if (use_qt) {
1033 		u32 chap_track = gf_isom_get_track_by_id(file, import.final_trackID);
1034 		u32 nb_sdesc = gf_isom_get_sample_description_count(file, chap_track);
1035 		for (i=0; i<nb_sdesc; i++) {
1036 			gf_isom_set_media_subtype(file, chap_track, i+1, GF_ISOM_SUBTYPE_TEXT);
1037 		}
1038 	}
1039 	//imported chapter is a track, set reference
1040 	for (i=0; i<gf_isom_get_track_count(file); i++) {
1041 		u32 mtype = gf_isom_get_media_type(file, i+1);
1042 		switch (mtype) {
1043 		case GF_ISOM_MEDIA_VISUAL:
1044 		case GF_ISOM_MEDIA_AUXV:
1045 		case GF_ISOM_MEDIA_PICT:
1046 		case GF_ISOM_MEDIA_AUDIO:
1047 			gf_isom_set_track_reference(file, i+1, GF_ISOM_REF_CHAP, import.final_trackID);
1048 			break;
1049 		}
1050 	}
1051 	return GF_OK;
1052 }
1053 
on_import_setup_failure(GF_Filter * f,void * on_setup_error_udta,GF_Err e)1054 static void on_import_setup_failure(GF_Filter *f, void *on_setup_error_udta, GF_Err e)
1055 {
1056 	GF_MediaImporter *importer = (GF_MediaImporter *)on_setup_error_udta;
1057 	if (importer)
1058 		importer->last_error = e;
1059 }
1060 
1061 GF_EXPORT
gf_media_import(GF_MediaImporter * importer)1062 GF_Err gf_media_import(GF_MediaImporter *importer)
1063 {
1064 	GF_Err e;
1065 	u32 i, count;
1066 	GF_FilterSession *fsess=NULL;
1067 	char *args = NULL;
1068 	char szSubArg[1024];
1069 	char szFilterID[20];
1070 	Bool source_id_set = GF_FALSE;
1071 	GF_Filter *isobmff_mux, *source;
1072 	GF_Filter *filter_orig;
1073 	char *ext;
1074 	char *fmt = "";
1075 
1076 	if (!importer || (!importer->dest && (importer->flags!=GF_IMPORT_PROBE_ONLY)) || (!importer->in_name && !importer->orig) ) return GF_BAD_PARAM;
1077 
1078 	if (importer->orig) return gf_import_isomedia(importer);
1079 
1080 	if (importer->force_ext) {
1081 		ext = importer->force_ext;
1082 	} else {
1083 		ext = gf_file_ext_start(importer->in_name);
1084 		if (!ext) ext = "";
1085 	}
1086 
1087 	if (importer->streamFormat) fmt = importer->streamFormat;
1088 
1089 	/*if isobmf and probing or no filter, direct copy*/
1090 	if (gf_isom_probe_file(importer->in_name)) {
1091 		u64 magic = 1;
1092 		magic <<= 32;
1093 		magic |= (importer->source_magic & 0xFFFFFFFFUL);
1094 		importer->source_magic = magic;
1095 		if ((!importer->filter_chain && !importer->filter_dst_opts && !importer->run_in_session)
1096 			|| (importer->flags & GF_IMPORT_PROBE_ONLY)
1097 		) {
1098 			importer->orig = gf_isom_open(importer->in_name, GF_ISOM_OPEN_READ, NULL);
1099 			if (importer->orig) {
1100 				e = gf_import_isomedia(importer);
1101 				gf_isom_delete(importer->orig);
1102 				importer->orig = NULL;
1103 				return e;
1104 			}
1105 		}
1106 	}
1107 
1108 	/*SC3DMC*/
1109 	if (!strnicmp(ext, ".s3d", 4) || !stricmp(fmt, "SC3DMC") )
1110 		return gf_import_afx_sc3dmc(importer, GF_TRUE);
1111 	/* chapter */
1112 	else if (!strnicmp(ext, ".txt", 4) || !strnicmp(ext, ".chap", 5) || !stricmp(fmt, "CHAP") )
1113 		return gf_media_import_chapters_file(importer);
1114 
1115 #ifdef FILTER_FIXME
1116 	#error "importer TO CHECK: SAF, TS"
1117 #endif
1118 
1119 	e = GF_OK;
1120 	importer->last_error = GF_OK;
1121 
1122 	if (importer->flags & GF_IMPORT_PROBE_ONLY) {
1123 		GF_Filter *prober, *src_filter;
1124 
1125 		fsess = gf_fs_new_defaults(0);
1126 		if (!fsess) {
1127 			return gf_import_message(importer, GF_BAD_PARAM, "[Importer] Cannot load filter session for import");
1128 		}
1129 		prober = gf_fs_load_filter(fsess, "probe", &e);
1130 		src_filter = gf_fs_load_source(fsess, importer->in_name, "index=0", NULL, &e);
1131 		if (e) {
1132 			gf_fs_run(fsess);
1133 			gf_fs_del(fsess);
1134 			return gf_import_message(importer, e, "[Importer] Cannot load filter for input file \"%s\"", importer->in_name);
1135 		}
1136 #ifdef GPAC_ENABLE_COVERAGE
1137 		if (gf_sys_is_cov_mode()) {
1138 			on_import_setup_failure(NULL, NULL, GF_OK);
1139 		}
1140 #endif
1141 
1142 		gf_filter_set_setup_failure_callback(prober, src_filter, on_import_setup_failure, importer);
1143 		gf_fs_run(fsess);
1144 
1145 		if (importer->last_error) {
1146 			gf_fs_del(fsess);
1147 			return gf_import_message(importer, importer->last_error, "[Importer] Error probing %s", importer->in_name);
1148 		}
1149 
1150 		importer->nb_tracks = 0;
1151 		count = gf_filter_get_ipid_count(prober);
1152 		for (i=0; i<count; i++) {
1153 			const GF_PropertyValue *p;
1154 			struct __track_import_info *tki = &importer->tk_info[importer->nb_tracks];
1155 			GF_FilterPid *pid = gf_filter_get_ipid(prober, i);
1156 
1157 			p = gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
1158 			tki->stream_type = p ? p->value.uint : GF_STREAM_UNKNOWN;
1159 			p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
1160 			tki->codecid = p ? p->value.uint : GF_CODECID_NONE;
1161 			p = gf_filter_pid_get_property(pid, GF_PROP_PID_LANGUAGE);
1162 			if (p && p->value.string) tki->lang = GF_4CC(p->value.string[0], p->value.string[1], p->value.string[2], ' ');
1163 			p = gf_filter_pid_get_property(pid, GF_PROP_PID_ID);
1164 			tki->track_num = p ? p->value.uint : 1;
1165 			p = gf_filter_pid_get_property(pid, GF_PROP_PID_ESID);
1166 			if (p) tki->mpeg4_es_id = p->value.uint;
1167 			p = gf_filter_pid_get_property(pid, GF_PROP_PID_SERVICE_ID);
1168 			if (p) tki->prog_num = p->value.uint;
1169 
1170 			p = gf_filter_pid_get_property(pid, GF_PROP_PID_DURATION);
1171 			if (p) {
1172 				Double d = (Double) p->value.lfrac.num;
1173 				d*=1000;
1174 				if (p->value.lfrac.den) d /= p->value.lfrac.den;
1175 				if (d > importer->probe_duration) importer->probe_duration = (u64) d;
1176 			}
1177 
1178 			p = gf_filter_pid_get_property(pid, GF_PROP_PID_WIDTH);
1179 			if (p) {
1180 				tki->video_info.width = p->value.uint;
1181 				p = gf_filter_pid_get_property(pid, GF_PROP_PID_HEIGHT);
1182 				if (p) tki->video_info.height = p->value.uint;
1183 				p = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
1184 				if (p) {
1185 					tki->video_info.FPS = p->value.frac.num;
1186 					if (p->value.frac.den) tki->video_info.FPS /= p->value.frac.den;
1187 				}
1188 				p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAR);
1189 				if (p) tki->video_info.par = (p->value.frac.num << 16) | p->value.frac.den;
1190 			}
1191 			p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLE_RATE);
1192 			if (p) {
1193 				tki->audio_info.sample_rate = p->value.uint;
1194 				p = gf_filter_pid_get_property(pid, GF_PROP_PID_NUM_CHANNELS);
1195 				if (p) tki->audio_info.nb_channels = p->value.uint;
1196 				p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLES_PER_FRAME);
1197 				if (p) tki->audio_info.samples_per_frame = p->value.uint;
1198 			}
1199 /*			p = gf_filter_pid_get_property(pid, GF_PROP_PID_CAN_DATAREF);
1200 			if (p) importer->flags |= GF_IMPORT_USE_DATAREF;
1201 */
1202 			p = gf_filter_pid_get_property(pid, GF_PROP_PID_SUBTYPE);
1203 			if (p) tki->media_subtype = p->value.uint;
1204 
1205 			importer->nb_tracks++;
1206 		}
1207 		gf_fs_del(fsess);
1208 		return GF_OK;
1209 	}
1210 
1211 	if (importer->run_in_session) {
1212 		fsess = importer->run_in_session;
1213 	} else {
1214 		fsess = gf_fs_new_defaults(0);
1215 		if (!fsess) {
1216 			return gf_import_message(importer, GF_BAD_PARAM, "[Importer] Cannot load filter session for import");
1217 		}
1218 	}
1219 
1220 	filter_orig=NULL;
1221 
1222 	if (importer->run_in_session) {
1223 		sprintf(szFilterID, "%d", (u32) ( (importer->source_magic & 0xFFFFFFFFUL) ) );
1224 	} else {
1225 		strcpy(szFilterID, "1");
1226 	}
1227 
1228 	if (!importer->run_in_session) {
1229 		//mux args
1230 		e = gf_dynstrcat(&args, "mp4mx:importer", ":");
1231 		sprintf(szSubArg, "file=%p", importer->dest);
1232 		e |= gf_dynstrcat(&args, szSubArg, ":");
1233 	}
1234 
1235 	if (importer->trackID) {
1236 		sprintf(szSubArg, "SID=%s#PID=%d", szFilterID, importer->trackID);
1237 		e |= gf_dynstrcat(&args, szSubArg, ":");
1238 	}
1239 	if (importer->filter_dst_opts)
1240 		e |= gf_dynstrcat(&args, importer->filter_dst_opts, ":");
1241 
1242 	if (importer->flags & GF_IMPORT_FORCE_MPEG4)
1243 		e |= gf_dynstrcat(&args, "m4sys", ":");
1244 	if (importer->flags & GF_IMPORT_USE_DATAREF)
1245 		e |= gf_dynstrcat(&args, "dref", ":");
1246 	if (importer->flags & GF_IMPORT_NO_EDIT_LIST)
1247 		e |= gf_dynstrcat(&args, "noedit", ":");
1248 	if (importer->flags & GF_IMPORT_FORCE_PACKED)
1249 		e |= gf_dynstrcat(&args, "pack_nal", ":");
1250 	if (importer->xps_inband==1)
1251 		e |= gf_dynstrcat(&args, "xps_inband=all", ":");
1252 	else if (importer->xps_inband==2)
1253 		e |= gf_dynstrcat(&args, "xps_inband=both", ":");
1254 	if (importer->esd && importer->esd->ESID) {
1255 		sprintf(szSubArg, "trackid=%d", importer->esd->ESID);
1256 		e |= gf_dynstrcat(&args, szSubArg, ":");
1257 	}
1258 
1259 	if (importer->duration.den) {
1260 		sprintf(szSubArg, "idur=%d/%d", importer->duration.num, importer->duration.den);
1261 		e |= gf_dynstrcat(&args, szSubArg, ":");
1262 	}
1263 	if (importer->frames_per_sample) {
1264 		sprintf(szSubArg, "pack3gp=%d", importer->frames_per_sample);
1265 		e |= gf_dynstrcat(&args, szSubArg, ":");
1266 	}
1267 	if (importer->asemode==GF_IMPORT_AUDIO_SAMPLE_ENTRY_v0_2) { e |= gf_dynstrcat(&args, "ase=v0s", ":"); }
1268 	else if (importer->asemode==GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_MPEG) { e |= gf_dynstrcat(&args, "ase=v1", ":"); }
1269 	else if (importer->asemode==GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_QTFF) { e |= gf_dynstrcat(&args, "ase=v1qt", ":"); }
1270 
1271 	if (e) {
1272 		gf_fs_del(fsess);
1273 		gf_free(args);
1274 		return gf_import_message(importer, e, "[Importer] Cannot load ISOBMFF muxer arguments");
1275 	}
1276 
1277 	if (!importer->run_in_session) {
1278 		isobmff_mux = gf_fs_load_filter(fsess, args, &e);
1279 		gf_free(args);
1280 		args = NULL;
1281 
1282 		if (!isobmff_mux) {
1283 			gf_fs_del(fsess);
1284 			gf_free(args);
1285 			return gf_import_message(importer, e, "[Importer] Cannot load ISOBMFF muxer");
1286 		}
1287 	} else {
1288 		importer->update_mux_args = args;
1289 		args = NULL;
1290 		isobmff_mux = NULL;
1291 	}
1292 
1293 	//filter chain
1294 	if (importer->filter_chain) {
1295 		GF_Filter *prev_filter=NULL;
1296 		char *fargs = (char *) importer->filter_chain;
1297 		while (fargs) {
1298 			GF_Filter *f;
1299 			char *sep = strstr(fargs, "@@");
1300 			if (sep) sep[0] = 0;
1301 			f = gf_fs_load_filter(fsess, fargs, &e);
1302 			if (!f) {
1303 				if (!importer->run_in_session)
1304 					gf_fs_del(fsess);
1305 				return gf_import_message(importer, e, "[Importer] Cannot load filter %s", fargs);
1306 			}
1307 			if (prev_filter) {
1308 				gf_filter_set_source(f, prev_filter, NULL);
1309 			}
1310 			prev_filter = f;
1311 			if (!filter_orig) filter_orig = f;
1312 			if (!sep) break;
1313 			sep[0] = '@';
1314 			fargs = sep+2;
1315 		}
1316 		if (prev_filter) {
1317 			const char *prev_id;
1318 			if (importer->trackID) {
1319 				if (gf_filter_get_id(prev_filter)) {
1320 					if (!importer->run_in_session)
1321 						gf_fs_del(fsess);
1322 					return gf_import_message(importer, GF_FILTER_NOT_FOUND, "[Importer] last filter in chain cannot use filter ID (%s)", fargs);
1323 				}
1324 				gf_filter_assign_id(prev_filter, szFilterID);
1325 				source_id_set=GF_TRUE;
1326 			}
1327 			prev_id = gf_filter_get_id(prev_filter);
1328 			if (!prev_id) {
1329 				gf_filter_assign_id(prev_filter, NULL);
1330 				prev_id = gf_filter_get_id(prev_filter);
1331 			}
1332 			if (importer->run_in_session) {
1333 				gf_dynstrcat(&importer->update_mux_args, ":SID=", NULL);
1334 				gf_dynstrcat(&importer->update_mux_args, prev_id, NULL);
1335 			} else {
1336 				assert(isobmff_mux);
1337 				gf_filter_set_source(isobmff_mux, prev_filter, NULL);
1338 			}
1339 		}
1340 	}
1341 
1342 	//source args
1343 	e = gf_dynstrcat(&args, "importer:index=0", ":");
1344 	if (importer->trackID && !source_id_set) {
1345 		sprintf(szSubArg, "FID=%s", szFilterID);
1346 		e |= gf_dynstrcat(&args, szSubArg, ":");
1347 	}
1348 	if (importer->filter_src_opts) e |= gf_dynstrcat(&args, importer->filter_src_opts, ":");
1349 
1350 	if (importer->flags & GF_IMPORT_SBR_IMPLICIT) e |= gf_dynstrcat(&args, "sbr=imp", ":");
1351 	else if (importer->flags & GF_IMPORT_SBR_EXPLICIT) e |= gf_dynstrcat(&args, "sbr=exp", ":");
1352 	if (importer->flags & GF_IMPORT_PS_IMPLICIT) e |= gf_dynstrcat(&args, "ps=imp", ":");
1353 	else if (importer->flags & GF_IMPORT_PS_EXPLICIT) e |= gf_dynstrcat(&args, "ps=exp", ":");
1354 	if (importer->flags & GF_IMPORT_OVSBR) e |= gf_dynstrcat(&args, "ovsbr", ":");
1355 	//avoids message at end of import
1356 	if (importer->flags & GF_IMPORT_FORCE_PACKED) e |= gf_dynstrcat(&args, "nal_length=0", ":");
1357 	if (importer->flags & GF_IMPORT_SET_SUBSAMPLES) e |= gf_dynstrcat(&args, "subsamples", ":");
1358 	if (importer->flags & GF_IMPORT_NO_SEI) e |= gf_dynstrcat(&args, "nosei", ":");
1359 	if (importer->flags & GF_IMPORT_SVC_NONE) e |= gf_dynstrcat(&args, "nosvc", ":");
1360 	if (importer->flags & GF_IMPORT_SAMPLE_DEPS) e |= gf_dynstrcat(&args, "deps", ":");
1361 	if (importer->flags & GF_IMPORT_FORCE_MPEG4) e |= gf_dynstrcat(&args, "mpeg4", ":");
1362 	if (importer->keep_audelim) e |= gf_dynstrcat(&args, "audelim", ":");
1363 	if (importer->video_fps.num && importer->video_fps.den) {
1364 		sprintf(szSubArg, "fps=%d/%d", importer->video_fps.num, importer->video_fps.den);
1365 		e |= gf_dynstrcat(&args, szSubArg, ":");
1366 	}
1367 	if (importer->is_alpha) e |= gf_dynstrcat(&args, "#Alpha", ":");
1368 
1369 	if (importer->streamFormat && !strcmp(importer->streamFormat, "VTT")) e |= gf_dynstrcat(&args, "webvtt", ":");
1370 
1371 	if (importer->source_magic) {
1372 		sprintf(szSubArg, "#SrcMagic="LLU, importer->source_magic);
1373 		e |= gf_dynstrcat(&args, szSubArg, ":");
1374 	}
1375 	if (importer->track_index) {
1376 		sprintf(szSubArg, "#TrackIndex=%d", importer->track_index);
1377 		e |= gf_dynstrcat(&args, szSubArg, ":");
1378 	}
1379 
1380 	if (e) {
1381 		if (!importer->run_in_session)
1382 			gf_fs_del(fsess);
1383 		gf_free(args);
1384 		return gf_import_message(importer, e, "[Importer] Cannot load arguments for input %s", importer->in_name);
1385 	}
1386 
1387 	source = gf_fs_load_source(fsess, importer->in_name, args, NULL, &e);
1388 	gf_free(args);
1389 	args = NULL;
1390 
1391 	if (e) {
1392 		if (!importer->run_in_session)
1393 			gf_fs_del(fsess);
1394 		return gf_import_message(importer, e, "[Importer] Cannot load filter for input file \"%s\"", importer->in_name);
1395 	}
1396 
1397 	if (filter_orig)
1398 		gf_filter_set_source(filter_orig, source, NULL);
1399 
1400 	//source is setup, we run in an external session, nothing left to do
1401 	if (importer->run_in_session)
1402 		return GF_OK;
1403 
1404 	gf_fs_run(fsess);
1405 
1406 	if (!importer->last_error) importer->last_error = gf_fs_get_last_connect_error(fsess);
1407 	if (!importer->last_error) importer->last_error = gf_fs_get_last_process_error(fsess);
1408 
1409 	if (importer->last_error) {
1410 		if (!importer->run_in_session)
1411 			gf_fs_del(fsess);
1412 		return gf_import_message(importer, importer->last_error, "[Importer] Error probing %s", importer->in_name);
1413 	}
1414 
1415 	importer->final_trackID = gf_isom_get_last_created_track_id(importer->dest);
1416 
1417 	if (importer->esd && importer->final_trackID) {
1418 		u32 tk_num = gf_isom_get_track_by_id(importer->dest, importer->final_trackID);
1419 		GF_ESD *esd = gf_isom_get_esd(importer->dest, tk_num, 1);
1420 		if (esd && !importer->esd->decoderConfig) {
1421 			importer->esd->decoderConfig = esd->decoderConfig;
1422 			esd->decoderConfig = NULL;
1423 		}
1424 		if (esd && !importer->esd->slConfig) {
1425 			importer->esd->slConfig = esd->slConfig;
1426 			esd->slConfig = NULL;
1427 		}
1428 		if (esd) {
1429 			gf_odf_desc_del((GF_Descriptor *) esd);
1430 		}
1431 
1432 		if (!importer->esd->ESID) {
1433 			importer->esd->ESID = importer->final_trackID;
1434 		}
1435 	}
1436 
1437 	if (importer->print_stats_graph & 1) gf_fs_print_stats(fsess);
1438 	if (importer->print_stats_graph & 2) gf_fs_print_connections(fsess);
1439 	gf_fs_del(fsess);
1440 	if (!importer->final_trackID) {
1441 		return gf_import_message(importer, GF_NOT_SUPPORTED, "[Importer] No valid track to import in input file \"%s\"", importer->in_name);
1442 	}
1443 	return GF_OK;
1444 }
1445 
1446 #endif /*GPAC_DISABLE_MEDIA_IMPORT*/
1447