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