| /* | |
| * GPAC - Multimedia Framework C SDK | |
| * | |
| * Authors: Jean Le Feuvre | |
| * Copyright (c) Telecom ParisTech 2000-2022 | |
| * All rights reserved | |
| * | |
| * This file is part of GPAC / Scene Management sub-project | |
| * | |
| * GPAC is free software; you can redistribute it and/or modify | |
| * it under the terms of the GNU Lesser General Public License as published by | |
| * the Free Software Foundation; either version 2, or (at your option) | |
| * any later version. | |
| * | |
| * GPAC is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; see the file COPYING. If not, write to | |
| * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
| * | |
| */ | |
| #include <gpac/scene_manager.h> | |
| #include <gpac/internal/media_dev.h> | |
| #include <gpac/internal/isomedia_dev.h> | |
| #include <gpac/constants.h> | |
| #if !defined(GPAC_DISABLE_QTVR) | |
| #include <gpac/nodes_mpeg4.h> | |
| static GF_Err gf_qtvr_report(GF_SceneLoader *load, GF_Err e, char *format, ...) | |
| { | |
| #ifndef GPAC_DISABLE_LOG | |
| if (format && gf_log_tool_level_on(GF_LOG_PARSER, e ? GF_LOG_ERROR : GF_LOG_WARNING)) { | |
| char szMsg[1024]; | |
| va_list args; | |
| va_start(args, format); | |
| vsnprintf(szMsg, 1024, format, args); | |
| va_end(args); | |
| GF_LOG((u32) (e ? GF_LOG_ERROR : GF_LOG_WARNING), GF_LOG_PARSER, ("[QT Parsing] %s\n", szMsg) ); | |
| } | |
| #endif | |
| return e; | |
| } | |
| /*import cubic QTVR to mp4*/ | |
| GF_Err gf_sm_load_init_qt(GF_SceneLoader *load) | |
| { | |
| u32 i, di, w, h, tk, nb_samp; | |
| Bool has_qtvr; | |
| GF_ISOSample *samp; | |
| GF_ISOFile *src; | |
| GF_StreamContext *st; | |
| GF_AUContext *au; | |
| GF_Command *com; | |
| M_Background *back; | |
| M_NavigationInfo *ni; | |
| M_Group *gr; | |
| GF_ODUpdate *odU; | |
| GF_SceneGraph *sg; | |
| GF_Err e=GF_OK; | |
| if (!load->ctx) return GF_NOT_SUPPORTED; | |
| src = gf_isom_open(load->fileName, GF_ISOM_OPEN_READ, NULL); | |
| if (!src) return gf_qtvr_report(load, GF_URL_ERROR, "Opening file %s failed", load->fileName); | |
| w = h = tk = 0; | |
| nb_samp = 0; | |
| has_qtvr = 0; | |
| for (i=0; i<gf_isom_get_track_count(src); i++) { | |
| switch (gf_isom_get_media_type(src, i+1)) { | |
| case GF_ISOM_MEDIA_VISUAL: | |
| case GF_ISOM_MEDIA_AUXV: | |
| case GF_ISOM_MEDIA_PICT: | |
| if (gf_isom_get_media_subtype(src, i+1, 1) == GF_ISOM_BOX_TYPE_JPEG) { | |
| u32 aw, ah; | |
| gf_isom_get_visual_info(src, i+1, 1, &aw, &ah); | |
| if ((aw>w) || (ah>h)) { | |
| w = aw; | |
| h = ah; | |
| tk = i+1; | |
| nb_samp = gf_isom_get_sample_count(src, i+1); | |
| } | |
| } | |
| break; | |
| case GF_ISOM_MEDIA_QTVR: | |
| has_qtvr = 1; | |
| break; | |
| } | |
| } | |
| if (!has_qtvr) { | |
| gf_isom_delete(src); | |
| return gf_qtvr_report(load, GF_NOT_SUPPORTED, "QTVR not found - no conversion available for this QuickTime movie"); | |
| } | |
| if (!tk) { | |
| gf_isom_delete(src); | |
| return gf_qtvr_report(load, GF_NON_COMPLIANT_BITSTREAM, "No associated visual track with QTVR movie"); | |
| } | |
| if (nb_samp!=6) { | |
| gf_isom_delete(src); | |
| return gf_qtvr_report(load, GF_NOT_SUPPORTED, "Movie %s doesn't look a Cubic QTVR - sorry...", load->fileName); | |
| } | |
| GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("QT: Importing Cubic QTVR Movie")); | |
| //for coverage | |
| gf_qtvr_report(load, GF_OK, NULL); | |
| /*create scene*/ | |
| sg = load->ctx->scene_graph; | |
| gr = (M_Group *) gf_node_new(sg, TAG_MPEG4_Group); | |
| gf_node_register((GF_Node *)gr, NULL); | |
| st = gf_sm_stream_new(load->ctx, 1, GF_STREAM_SCENE, GF_CODECID_BIFS); | |
| au = gf_sm_stream_au_new(st, 0, 0, 1); | |
| com = gf_sg_command_new(load->ctx->scene_graph, GF_SG_SCENE_REPLACE); | |
| gf_list_add(au->commands, com); | |
| com->node = (GF_Node *)gr; | |
| back = (M_Background *) gf_node_new(sg, TAG_MPEG4_Background); | |
| gf_node_list_add_child( &gr->children, (GF_Node*)back); | |
| gf_node_register((GF_Node *)back, (GF_Node *)gr); | |
| gf_sg_vrml_mf_alloc(&back->leftUrl, GF_SG_VRML_MFURL, 1); | |
| back->leftUrl.vals[0].OD_ID = 2; | |
| gf_sg_vrml_mf_alloc(&back->frontUrl, GF_SG_VRML_MFURL, 1); | |
| back->frontUrl.vals[0].OD_ID = 3; | |
| gf_sg_vrml_mf_alloc(&back->rightUrl, GF_SG_VRML_MFURL, 1); | |
| back->rightUrl.vals[0].OD_ID = 4; | |
| gf_sg_vrml_mf_alloc(&back->backUrl, GF_SG_VRML_MFURL, 1); | |
| back->backUrl.vals[0].OD_ID = 5; | |
| gf_sg_vrml_mf_alloc(&back->topUrl, GF_SG_VRML_MFURL, 1); | |
| back->topUrl.vals[0].OD_ID = 6; | |
| gf_sg_vrml_mf_alloc(&back->bottomUrl, GF_SG_VRML_MFURL, 1); | |
| back->bottomUrl.vals[0].OD_ID = 7; | |
| ni = (M_NavigationInfo *) gf_node_new(sg, TAG_MPEG4_NavigationInfo); | |
| gf_node_list_add_child(&gr->children, (GF_Node*)ni); | |
| gf_node_register((GF_Node *)ni, (GF_Node *)gr); | |
| gf_sg_vrml_mf_reset(&ni->type, GF_SG_VRML_MFSTRING); | |
| gf_sg_vrml_mf_alloc(&ni->type, GF_SG_VRML_MFSTRING, 1); | |
| ni->type.vals[0] = gf_strdup("VR"); | |
| /*create ODs*/ | |
| st = gf_sm_stream_new(load->ctx, 2, GF_STREAM_OD, GF_CODECID_OD_V1); | |
| au = gf_sm_stream_au_new(st, 0, 0, 1); | |
| odU = (GF_ODUpdate*) gf_odf_com_new(GF_ODF_OD_UPDATE_TAG); | |
| gf_list_add(au->commands, odU); | |
| for (i=0; i<6; i++) { | |
| GF_ObjectDescriptor *od; | |
| GF_ESD *esd; | |
| GF_MuxInfo *mi; | |
| FILE *img; | |
| char szName[1024]; | |
| od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG); | |
| od->objectDescriptorID = 2+i; | |
| esd = gf_odf_desc_esd_new(2); | |
| esd->decoderConfig->streamType = GF_STREAM_VISUAL; | |
| esd->decoderConfig->objectTypeIndication = GF_CODECID_JPEG; | |
| esd->ESID = 3+i; | |
| /*extract image and remember it*/ | |
| mi = (GF_MuxInfo *) gf_odf_desc_new(GF_ODF_MUXINFO_TAG); | |
| gf_list_add(esd->extensionDescriptors, mi); | |
| mi->delete_file = 1; | |
| sprintf(szName, "%s_img%d.jpg", load->fileName, esd->ESID); | |
| mi->file_name = gf_strdup(szName); | |
| gf_list_add(od->ESDescriptors, esd); | |
| gf_list_add(odU->objectDescriptors, od); | |
| samp = gf_isom_get_sample(src, tk, i+1, &di); | |
| img = gf_fopen(mi->file_name, "wb"); | |
| if (gf_fwrite(samp->data, samp->dataLength, img)!=samp->dataLength) | |
| e = GF_IO_ERR; | |
| gf_fclose(img); | |
| gf_isom_sample_del(&samp); | |
| } | |
| gf_isom_delete(src); | |
| return e; | |
| } | |
| #endif /*GPAC_DISABLE_QTVR*/ |