blob: 1fe70d9ee331809b7ba81fc4433df5b8c31e7b9f [file] [edit]
/*
* 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*/