Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2012
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / Scene Management 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/scene_manager.h>
27 : #include <gpac/constants.h>
28 : #include <gpac/bifs.h>
29 : #ifndef GPAC_DISABLE_LASER
30 : #include <gpac/laser.h>
31 : #endif
32 :
33 :
34 :
35 : #if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_LOADER_ISOM)
36 :
37 57 : static void UpdateODCommand(GF_ISOFile *mp4, GF_ODCom *com)
38 : {
39 : u32 i, j;
40 : const char *szName;
41 : char szPath[2048];
42 :
43 57 : szName = gf_isom_get_filename(mp4);
44 57 : if (com->tag == GF_ODF_OD_UPDATE_TAG) {
45 : GF_ObjectDescriptor *od;
46 : GF_ODUpdate *odU = (GF_ODUpdate *)com;
47 29 : i=0;
48 112 : while ((od = (GF_ObjectDescriptor *)gf_list_enum(odU->objectDescriptors, &i))) {
49 : GF_ESD *esd;
50 54 : j=0;
51 161 : while ((esd = (GF_ESD *)gf_list_enum(od->ESDescriptors, &j))) {
52 : //can happen when dumping with keep-ods
53 53 : if (esd->tag!=GF_ODF_ESD_TAG) {
54 1 : continue;
55 : }
56 52 : if (esd->URLString) continue;
57 :
58 52 : switch (esd->decoderConfig->streamType) {
59 0 : case GF_STREAM_OD:
60 0 : continue;
61 :
62 0 : case GF_STREAM_SCENE:
63 0 : if ((esd->decoderConfig->objectTypeIndication != GF_CODECID_AFX) &&
64 : (esd->decoderConfig->objectTypeIndication != GF_CODECID_SYNTHESIZED_TEXTURE)
65 : ) {
66 0 : continue;
67 : }
68 : break;
69 : /*dump the OCR track duration in case the OCR is used by media controls & co*/
70 0 : case GF_STREAM_OCR:
71 : {
72 : u32 track;
73 : Double dur;
74 0 : GF_MuxInfo *mi = (GF_MuxInfo *) gf_odf_desc_new(GF_ODF_MUXINFO_TAG);
75 0 : gf_list_add(esd->extensionDescriptors, mi);
76 0 : track = gf_isom_get_track_by_id(mp4, esd->ESID);
77 0 : dur = (Double) (s64) gf_isom_get_track_duration(mp4, track);
78 0 : dur /= gf_isom_get_timescale(mp4);
79 0 : mi->duration = (u32) (dur * 1000);
80 0 : continue;;
81 : }
82 : break;
83 : default:
84 : break;
85 : }
86 :
87 52 : GF_MuxInfo *mi = (GF_MuxInfo *) gf_odf_desc_new(GF_ODF_MUXINFO_TAG);
88 52 : gf_list_add(esd->extensionDescriptors, mi);
89 52 : sprintf(szPath, "%s#%d", szName, esd->ESID);
90 52 : mi->file_name = gf_strdup(szPath);
91 52 : mi->streamFormat = gf_strdup("MP4");
92 : }
93 : }
94 33 : return;
95 : }
96 28 : if (com->tag == GF_ODF_ESD_UPDATE_TAG) {
97 : GF_ESD *esd;
98 : GF_ESDUpdate *esdU = (GF_ESDUpdate *)com;
99 4 : i=0;
100 12 : while ((esd = (GF_ESD *)gf_list_enum(esdU->ESDescriptors, &i))) {
101 : Bool import = 1;
102 4 : if (esd->URLString) continue;
103 4 : switch (esd->decoderConfig->streamType) {
104 : case GF_STREAM_OD:
105 : import = 0;
106 : break;
107 0 : case GF_STREAM_SCENE:
108 0 : if ((esd->decoderConfig->objectTypeIndication != GF_CODECID_AFX) &&
109 : (esd->decoderConfig->objectTypeIndication != GF_CODECID_SYNTHESIZED_TEXTURE)
110 : ) {
111 : import = 0;
112 : }
113 : break;
114 : /*dump the OCR track duration in case the OCR is used by media controls & co*/
115 0 : case GF_STREAM_OCR:
116 : {
117 : u32 track;
118 : Double dur;
119 0 : GF_MuxInfo *mi = (GF_MuxInfo *) gf_odf_desc_new(GF_ODF_MUXINFO_TAG);
120 0 : gf_list_add(esd->extensionDescriptors, mi);
121 0 : track = gf_isom_get_track_by_id(mp4, esd->ESID);
122 0 : dur = (Double) (s64) gf_isom_get_track_duration(mp4, track);
123 0 : dur /= gf_isom_get_timescale(mp4);
124 0 : mi->duration = (u32) (dur * 1000);
125 : import = 0;
126 : }
127 : break;
128 : default:
129 : break;
130 : }
131 : if (import) {
132 4 : GF_MuxInfo *mi = (GF_MuxInfo *) gf_odf_desc_new(GF_ODF_MUXINFO_TAG);
133 4 : gf_list_add(esd->extensionDescriptors, mi);
134 4 : sprintf(szPath, "%s#%d", szName, esd->ESID);
135 4 : mi->file_name = gf_strdup(szPath);
136 4 : mi->streamFormat = gf_strdup("MP4");
137 : }
138 : }
139 : return;
140 : }
141 : }
142 :
143 18 : static void mp4_report(GF_SceneLoader *load, GF_Err e, char *format, ...)
144 : {
145 : #ifndef GPAC_DISABLE_LOG
146 18 : if (format && gf_log_tool_level_on(GF_LOG_PARSER, e ? GF_LOG_ERROR : GF_LOG_WARNING)) {
147 : char szMsg[1024];
148 : va_list args;
149 0 : va_start(args, format);
150 : vsnprintf(szMsg, 1024, format, args);
151 0 : va_end(args);
152 0 : GF_LOG((u32) (e ? GF_LOG_ERROR : GF_LOG_WARNING), GF_LOG_PARSER, ("[MP4 Loading] %s\n", szMsg) );
153 : }
154 : #endif
155 18 : }
156 :
157 18 : static GF_Err gf_sm_load_run_isom(GF_SceneLoader *load)
158 : {
159 : GF_Err e;
160 : FILE *logs;
161 : u32 i, j, di, nbBifs, nbLaser, nb_samp, samp_done, init_offset;
162 : GF_StreamContext *sc;
163 : GF_ESD *esd;
164 : GF_ODCodec *od_dec;
165 : #ifndef GPAC_DISABLE_BIFS
166 : GF_BifsDecoder *bifs_dec;
167 : #endif
168 : #ifndef GPAC_DISABLE_LASER
169 : GF_LASeRCodec *lsr_dec;
170 : #endif
171 :
172 18 : if (!load || !load->isom) return GF_BAD_PARAM;
173 :
174 : nbBifs = nbLaser = 0;
175 : e = GF_OK;
176 : #ifndef GPAC_DISABLE_BIFS
177 18 : bifs_dec = gf_bifs_decoder_new(load->scene_graph, 1);
178 : #endif
179 18 : od_dec = gf_odf_codec_new();
180 : logs = NULL;
181 : #ifndef GPAC_DISABLE_LASER
182 18 : lsr_dec = gf_laser_decoder_new(load->scene_graph);
183 : #endif
184 : esd = NULL;
185 : /*load each stream*/
186 : nb_samp = 0;
187 120 : for (i=0; i<gf_isom_get_track_count(load->isom); i++) {
188 84 : u32 type = gf_isom_get_media_type(load->isom, i+1);
189 84 : u32 subtype = gf_isom_get_mpeg4_subtype(load->isom, i+1, 1);
190 84 : switch (type) {
191 51 : case GF_ISOM_MEDIA_SCENE:
192 : case GF_ISOM_MEDIA_OD:
193 51 : nb_samp += gf_isom_get_sample_count(load->isom, i+1);
194 51 : break;
195 33 : default:
196 33 : if (subtype==GF_ISOM_SUBTYPE_MP4S) {
197 0 : nb_samp += gf_isom_get_sample_count(load->isom, i+1);
198 : }
199 : break;
200 : }
201 : }
202 : samp_done = 1;
203 18 : gf_isom_text_set_streaming_mode(load->isom, 1);
204 :
205 120 : for (i=0; i<gf_isom_get_track_count(load->isom); i++) {
206 84 : u32 type = gf_isom_get_media_type(load->isom, i+1);
207 84 : u32 subtype = gf_isom_get_mpeg4_subtype(load->isom, i+1, 1);
208 84 : switch (type) {
209 : case GF_ISOM_MEDIA_SCENE:
210 : case GF_ISOM_MEDIA_OD:
211 : break;
212 33 : default:
213 33 : if (subtype!=GF_ISOM_SUBTYPE_MP4S)
214 33 : continue;
215 : break;
216 : }
217 51 : esd = gf_isom_get_esd(load->isom, i+1, 1);
218 51 : if (!esd || !esd->decoderConfig) continue;
219 51 : if (esd->decoderConfig->objectTypeIndication==GF_CODECID_TEXT_MPEG4)
220 0 : continue;
221 :
222 51 : if ((esd->decoderConfig->objectTypeIndication == GF_CODECID_AFX) ||
223 : (esd->decoderConfig->objectTypeIndication == GF_CODECID_SYNTHESIZED_TEXTURE)
224 : ) {
225 0 : nb_samp += gf_isom_get_sample_count(load->isom, i+1);
226 0 : continue;
227 : }
228 51 : sc = gf_sm_stream_new(load->ctx, esd->ESID, esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication);
229 51 : sc->streamType = esd->decoderConfig->streamType;
230 51 : sc->ESID = esd->ESID;
231 51 : sc->codec_id = esd->decoderConfig->objectTypeIndication;
232 51 : sc->timeScale = gf_isom_get_media_timescale(load->isom, i+1);
233 :
234 : /*we still need to reconfig the BIFS*/
235 51 : if (esd->decoderConfig->streamType==GF_STREAM_SCENE) {
236 : #ifndef GPAC_DISABLE_BIFS
237 : /*BIFS*/
238 18 : if (esd->decoderConfig->objectTypeIndication<=2) {
239 16 : if (!esd->dependsOnESID && nbBifs && !i)
240 0 : mp4_report(load, GF_OK, "several scene namespaces used or improper scene dependencies in file - import may be incorrect");
241 16 : if (!esd->decoderConfig->decoderSpecificInfo) {
242 : /* Hack for T-DMB non compliant streams */
243 0 : e = gf_bifs_decoder_configure_stream(bifs_dec, esd->ESID, NULL, 0, esd->decoderConfig->objectTypeIndication);
244 : } else {
245 16 : e = gf_bifs_decoder_configure_stream(bifs_dec, esd->ESID, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, esd->decoderConfig->objectTypeIndication);
246 : }
247 16 : if (e) goto exit;
248 16 : nbBifs++;
249 : }
250 : #endif
251 :
252 : #ifndef GPAC_DISABLE_LASER
253 : /*LASER*/
254 18 : if (esd->decoderConfig->objectTypeIndication==0x09) {
255 2 : if (!esd->dependsOnESID && nbBifs && !i)
256 0 : mp4_report(load, GF_OK, "several scene namespaces used or improper scene dependencies in file - import may be incorrect");
257 2 : e = gf_laser_decoder_configure_stream(lsr_dec, esd->ESID, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength);
258 2 : if (e) goto exit;
259 : nbLaser++;
260 : }
261 : #endif
262 : }
263 :
264 : init_offset = 0;
265 : /*dump all AUs*/
266 349 : for (j=0; j<gf_isom_get_sample_count(load->isom, i+1); j++) {
267 : GF_AUContext *au;
268 247 : GF_ISOSample *samp = gf_isom_get_sample(load->isom, i+1, j+1, &di);
269 247 : if (!samp) {
270 0 : mp4_report(load, gf_isom_last_error(load->isom), "Unable to fetch sample %d from track ID %d - aborting track import", j+1, gf_isom_get_track_id(load->isom, i+1));
271 0 : break;
272 : }
273 : /*check if track has initial offset*/
274 247 : if (!j && gf_isom_get_edits_count(load->isom, i+1)) {
275 : u64 EditTime, dur, mtime;
276 : GF_ISOEditType mode;
277 0 : gf_isom_get_edit(load->isom, i+1, 1, &EditTime, &dur, &mtime, &mode);
278 0 : if (mode==GF_ISOM_EDIT_EMPTY) {
279 0 : init_offset = (u32) (dur * sc->timeScale / gf_isom_get_timescale(load->isom) );
280 : }
281 : }
282 247 : samp->DTS += init_offset;
283 :
284 247 : au = gf_sm_stream_au_new(sc, samp->DTS, ((Double)(s64) samp->DTS) / sc->timeScale, (samp->IsRAP==RAP) ? 1 : 0);
285 :
286 247 : if (esd->decoderConfig->streamType==GF_STREAM_SCENE) {
287 : #ifndef GPAC_DISABLE_BIFS
288 190 : if (esd->decoderConfig->objectTypeIndication<=2)
289 184 : e = gf_bifs_decode_command_list(bifs_dec, esd->ESID, samp->data, samp->dataLength, au->commands);
290 : #endif
291 : #ifndef GPAC_DISABLE_LASER
292 190 : if (esd->decoderConfig->objectTypeIndication==0x09)
293 6 : e = gf_laser_decode_command_list(lsr_dec, esd->ESID, samp->data, samp->dataLength, au->commands);
294 : #endif
295 : } else {
296 57 : e = gf_odf_codec_set_au(od_dec, samp->data, samp->dataLength);
297 57 : if (!e) e = gf_odf_codec_decode(od_dec);
298 57 : if (!e) {
299 57 : while (1) {
300 114 : GF_ODCom *odc = gf_odf_codec_get_com(od_dec);
301 114 : if (!odc) break;
302 : /*update ESDs if any*/
303 57 : UpdateODCommand(load->isom, odc);
304 57 : gf_list_add(au->commands, odc);
305 : }
306 : }
307 : }
308 247 : gf_isom_sample_del(&samp);
309 247 : if (e) {
310 0 : mp4_report(load, gf_isom_last_error(load->isom), "decoding sample %d from track ID %d failed", j+1, gf_isom_get_track_id(load->isom, i+1));
311 0 : goto exit;
312 : }
313 :
314 247 : samp_done++;
315 247 : gf_set_progress("MP4 Loading", samp_done, nb_samp);
316 : }
317 51 : gf_odf_desc_del((GF_Descriptor *) esd);
318 : esd = NULL;
319 : }
320 18 : gf_isom_text_set_streaming_mode(load->isom, 0);
321 :
322 18 : exit:
323 : #ifndef GPAC_DISABLE_BIFS
324 18 : gf_bifs_decoder_del(bifs_dec);
325 : #endif
326 18 : gf_odf_codec_del(od_dec);
327 : #ifndef GPAC_DISABLE_LASER
328 18 : gf_laser_decoder_del(lsr_dec);
329 : #endif
330 18 : if (esd) gf_odf_desc_del((GF_Descriptor *) esd);
331 : if (logs) gf_fclose(logs);
332 : return e;
333 : }
334 :
335 18 : static void gf_sm_load_done_isom(GF_SceneLoader *load)
336 : {
337 : /*nothing to do the file is not ours*/
338 18 : }
339 :
340 0 : static GF_Err gf_sm_isom_suspend(GF_SceneLoader *loader, Bool suspend)
341 : {
342 0 : return GF_OK;
343 : }
344 :
345 18 : GF_Err gf_sm_load_init_isom(GF_SceneLoader *load)
346 : {
347 : u32 i;
348 : GF_BIFSConfig *bc;
349 : GF_ESD *esd;
350 : GF_Err e;
351 : char *scene_msg = "MPEG-4 BIFS Scene Parsing";
352 18 : if (!load->isom) return GF_BAD_PARAM;
353 :
354 : /*load IOD*/
355 18 : load->ctx->root_od = (GF_ObjectDescriptor *) gf_isom_get_root_od(load->isom);
356 18 : if (!load->ctx->root_od) {
357 0 : e = gf_isom_last_error(load->isom);
358 0 : if (e) return e;
359 : }
360 : else {
361 18 : switch (load->ctx->root_od->tag) {
362 : case GF_ODF_OD_TAG:
363 : case GF_ODF_IOD_TAG:
364 : case GF_ODF_ISOM_OD_TAG:
365 : case GF_ODF_ISOM_IOD_TAG:
366 : break;
367 0 : default:
368 0 : gf_odf_desc_del((GF_Descriptor *) load->ctx->root_od);
369 0 : load->ctx->root_od = NULL;
370 0 : break;
371 : }
372 : }
373 :
374 : esd = NULL;
375 :
376 : /*get root scene stream*/
377 20 : for (i=0; i<gf_isom_get_track_count(load->isom); i++) {
378 20 : u32 type = gf_isom_get_media_type(load->isom, i+1);
379 20 : if (type != GF_ISOM_MEDIA_SCENE) continue;
380 18 : if (! gf_isom_is_track_in_root_od(load->isom, i+1) ) continue;
381 18 : esd = gf_isom_get_esd(load->isom, i+1, 1);
382 :
383 18 : if (esd && esd->URLString) {
384 0 : gf_odf_desc_del((GF_Descriptor *)esd);
385 : esd = NULL;
386 0 : continue;
387 : }
388 :
389 : /*make sure we load the root BIFS stream first*/
390 18 : if (esd && esd->dependsOnESID && (esd->dependsOnESID!=esd->ESID) ) {
391 0 : u32 track = gf_isom_get_track_by_id(load->isom, esd->dependsOnESID);
392 0 : if (gf_isom_get_media_type(load->isom, track) != GF_ISOM_MEDIA_OD) {
393 0 : gf_odf_desc_del((GF_Descriptor *)esd);
394 : esd = NULL;
395 0 : continue;
396 : }
397 : }
398 18 : if (esd && esd->decoderConfig && esd->decoderConfig->objectTypeIndication==0x09) scene_msg = "MPEG-4 LASeR Scene Parsing";
399 : break;
400 : }
401 18 : if (!esd) return GF_OK;
402 :
403 18 : GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("%s\n", scene_msg));
404 :
405 : /*BIFS: update size & pixel metrics info*/
406 18 : if (esd->decoderConfig) {
407 18 : if (esd->decoderConfig->objectTypeIndication<=2) {
408 16 : bc = gf_odf_get_bifs_config(esd->decoderConfig->decoderSpecificInfo, esd->decoderConfig->objectTypeIndication);
409 16 : if (!bc->elementaryMasks && bc->pixelWidth && bc->pixelHeight) {
410 16 : load->ctx->scene_width = bc->pixelWidth;
411 16 : load->ctx->scene_height = bc->pixelHeight;
412 16 : load->ctx->is_pixel_metrics = bc->pixelMetrics;
413 : }
414 16 : gf_odf_desc_del((GF_Descriptor *) bc);
415 : /*note we don't load the first BIFS AU to avoid storing the BIFS decoder, needed to properly handle quantization*/
416 : }
417 : /*LASeR*/
418 2 : else if (esd->decoderConfig->objectTypeIndication==0x09) {
419 2 : load->ctx->is_pixel_metrics = 1;
420 : }
421 : }
422 18 : gf_odf_desc_del((GF_Descriptor *) esd);
423 : esd = NULL;
424 :
425 : #ifdef GPAC_ENABLE_COVERAGE
426 18 : if (gf_sys_is_cov_mode()) {
427 18 : mp4_report(load, GF_OK, NULL);
428 : gf_sm_isom_suspend(load, GF_TRUE);
429 : gf_sm_isom_suspend(load, GF_FALSE);
430 : }
431 : #endif
432 :
433 18 : load->process = gf_sm_load_run_isom;
434 18 : load->done = gf_sm_load_done_isom;
435 18 : load->suspend = gf_sm_isom_suspend;
436 18 : return GF_OK;
437 : }
438 :
439 : #endif /*GPAC_DISABLE_ISOM && GPAC_DISABLE_LOADER_ISOM*/
|