Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2020
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/internal/media_dev.h>
28 : #include <gpac/internal/isomedia_dev.h>
29 : #include <gpac/constants.h>
30 :
31 : #if !defined(GPAC_DISABLE_QTVR)
32 :
33 : #include <gpac/nodes_mpeg4.h>
34 :
35 :
36 :
37 3 : static GF_Err gf_qtvr_report(GF_SceneLoader *load, GF_Err e, char *format, ...)
38 : {
39 : #ifndef GPAC_DISABLE_LOG
40 3 : if (format && gf_log_tool_level_on(GF_LOG_PARSER, e ? GF_LOG_ERROR : GF_LOG_WARNING)) {
41 : char szMsg[1024];
42 : va_list args;
43 0 : va_start(args, format);
44 : vsnprintf(szMsg, 1024, format, args);
45 0 : va_end(args);
46 0 : GF_LOG((u32) (e ? GF_LOG_ERROR : GF_LOG_WARNING), GF_LOG_PARSER, ("[QT Parsing] %s\n", szMsg) );
47 : }
48 : #endif
49 3 : return e;
50 : }
51 :
52 :
53 : /*import cubic QTVR to mp4*/
54 3 : GF_Err gf_sm_load_init_qt(GF_SceneLoader *load)
55 : {
56 : u32 i, di, w, h, tk, nb_samp;
57 : Bool has_qtvr;
58 : GF_ISOSample *samp;
59 : GF_ISOFile *src;
60 : GF_StreamContext *st;
61 : GF_AUContext *au;
62 : GF_Command *com;
63 : M_Background *back;
64 : M_NavigationInfo *ni;
65 : M_Group *gr;
66 : GF_ODUpdate *odU;
67 : GF_SceneGraph *sg;
68 :
69 3 : if (!load->ctx) return GF_NOT_SUPPORTED;
70 :
71 3 : src = gf_isom_open(load->fileName, GF_ISOM_OPEN_READ, NULL);
72 3 : if (!src) return gf_qtvr_report(load, GF_URL_ERROR, "Opening file %s failed", load->fileName);
73 :
74 : w = h = tk = 0;
75 : nb_samp = 0;
76 :
77 : has_qtvr = 0;
78 14 : for (i=0; i<gf_isom_get_track_count(src); i++) {
79 11 : switch (gf_isom_get_media_type(src, i+1)) {
80 5 : case GF_ISOM_MEDIA_VISUAL:
81 : case GF_ISOM_MEDIA_AUXV:
82 : case GF_ISOM_MEDIA_PICT:
83 5 : if (gf_isom_get_media_subtype(src, i+1, 1) == GF_ISOM_BOX_TYPE_JPEG) {
84 : u32 aw, ah;
85 5 : gf_isom_get_visual_info(src, i+1, 1, &aw, &ah);
86 5 : if ((aw>w) || (ah>h)) {
87 : w = aw;
88 4 : h = ah;
89 : tk = i+1;
90 4 : nb_samp = gf_isom_get_sample_count(src, i+1);
91 : }
92 : }
93 : break;
94 3 : case GF_ISOM_MEDIA_QTVR:
95 : has_qtvr = 1;
96 3 : break;
97 : }
98 : }
99 3 : if (!has_qtvr) {
100 0 : gf_isom_delete(src);
101 0 : return gf_qtvr_report(load, GF_NOT_SUPPORTED, "QTVR not found - no conversion available for this QuickTime movie");
102 : }
103 3 : if (!tk) {
104 0 : gf_isom_delete(src);
105 0 : return gf_qtvr_report(load, GF_NON_COMPLIANT_BITSTREAM, "No associated visual track with QTVR movie");
106 : }
107 3 : if (nb_samp!=6) {
108 0 : gf_isom_delete(src);
109 0 : return gf_qtvr_report(load, GF_NOT_SUPPORTED, "Movie %s doesn't look a Cubic QTVR - sorry...", load->fileName);
110 : }
111 :
112 3 : GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("QT: Importing Cubic QTVR Movie"));
113 : //for coverage
114 3 : gf_qtvr_report(load, GF_OK, NULL);
115 :
116 : /*create scene*/
117 3 : sg = load->ctx->scene_graph;
118 3 : gr = (M_Group *) gf_node_new(sg, TAG_MPEG4_Group);
119 3 : gf_node_register((GF_Node *)gr, NULL);
120 3 : st = gf_sm_stream_new(load->ctx, 1, GF_STREAM_SCENE, GF_CODECID_BIFS);
121 3 : au = gf_sm_stream_au_new(st, 0, 0, 1);
122 3 : com = gf_sg_command_new(load->ctx->scene_graph, GF_SG_SCENE_REPLACE);
123 3 : gf_list_add(au->commands, com);
124 3 : com->node = (GF_Node *)gr;
125 :
126 3 : back = (M_Background *) gf_node_new(sg, TAG_MPEG4_Background);
127 3 : gf_node_list_add_child( &gr->children, (GF_Node*)back);
128 3 : gf_node_register((GF_Node *)back, (GF_Node *)gr);
129 :
130 3 : gf_sg_vrml_mf_alloc(&back->leftUrl, GF_SG_VRML_MFURL, 1);
131 3 : back->leftUrl.vals[0].OD_ID = 2;
132 3 : gf_sg_vrml_mf_alloc(&back->frontUrl, GF_SG_VRML_MFURL, 1);
133 3 : back->frontUrl.vals[0].OD_ID = 3;
134 3 : gf_sg_vrml_mf_alloc(&back->rightUrl, GF_SG_VRML_MFURL, 1);
135 3 : back->rightUrl.vals[0].OD_ID = 4;
136 3 : gf_sg_vrml_mf_alloc(&back->backUrl, GF_SG_VRML_MFURL, 1);
137 3 : back->backUrl.vals[0].OD_ID = 5;
138 3 : gf_sg_vrml_mf_alloc(&back->topUrl, GF_SG_VRML_MFURL, 1);
139 3 : back->topUrl.vals[0].OD_ID = 6;
140 3 : gf_sg_vrml_mf_alloc(&back->bottomUrl, GF_SG_VRML_MFURL, 1);
141 3 : back->bottomUrl.vals[0].OD_ID = 7;
142 :
143 3 : ni = (M_NavigationInfo *) gf_node_new(sg, TAG_MPEG4_NavigationInfo);
144 3 : gf_node_list_add_child(&gr->children, (GF_Node*)ni);
145 3 : gf_node_register((GF_Node *)ni, (GF_Node *)gr);
146 3 : gf_sg_vrml_mf_reset(&ni->type, GF_SG_VRML_MFSTRING);
147 3 : gf_sg_vrml_mf_alloc(&ni->type, GF_SG_VRML_MFSTRING, 1);
148 3 : ni->type.vals[0] = gf_strdup("VR");
149 :
150 : /*create ODs*/
151 3 : st = gf_sm_stream_new(load->ctx, 2, GF_STREAM_OD, GF_CODECID_OD_V1);
152 3 : au = gf_sm_stream_au_new(st, 0, 0, 1);
153 3 : odU = (GF_ODUpdate*) gf_odf_com_new(GF_ODF_OD_UPDATE_TAG);
154 3 : gf_list_add(au->commands, odU);
155 24 : for (i=0; i<6; i++) {
156 : GF_ObjectDescriptor *od;
157 : GF_ESD *esd;
158 : GF_MuxInfo *mi;
159 : FILE *img;
160 : char szName[1024];
161 18 : od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
162 18 : od->objectDescriptorID = 2+i;
163 18 : esd = gf_odf_desc_esd_new(2);
164 18 : esd->decoderConfig->streamType = GF_STREAM_VISUAL;
165 18 : esd->decoderConfig->objectTypeIndication = GF_CODECID_JPEG;
166 18 : esd->ESID = 3+i;
167 : /*extract image and remember it*/
168 18 : mi = (GF_MuxInfo *) gf_odf_desc_new(GF_ODF_MUXINFO_TAG);
169 18 : gf_list_add(esd->extensionDescriptors, mi);
170 18 : mi->delete_file = 1;
171 18 : sprintf(szName, "%s_img%d.jpg", load->fileName, esd->ESID);
172 18 : mi->file_name = gf_strdup(szName);
173 :
174 18 : gf_list_add(od->ESDescriptors, esd);
175 18 : gf_list_add(odU->objectDescriptors, od);
176 :
177 18 : samp = gf_isom_get_sample(src, tk, i+1, &di);
178 18 : img = gf_fopen(mi->file_name, "wb");
179 18 : gf_fwrite(samp->data, samp->dataLength, img);
180 18 : gf_fclose(img);
181 18 : gf_isom_sample_del(&samp);
182 : }
183 3 : gf_isom_delete(src);
184 3 : return GF_OK;
185 : }
186 :
187 : #endif /*GPAC_DISABLE_QTVR*/
|