1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2000-2017
6 * All rights reserved
7 *
8 * This file is part of GPAC / Scene Compositor 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
27 #include <gpac/constants.h>
28 #include <gpac/internal/compositor_dev.h>
29
30 #ifndef GPAC_DISABLE_VRML
31
32 /*render : setup media sensor and update timing in case of inline scenes*/
RenderMediaSensor(GF_Node * node,void * rs,Bool is_destroy)33 void RenderMediaSensor(GF_Node *node, void *rs, Bool is_destroy)
34 {
35 GF_TraverseState *tr_state = (GF_TraverseState *)rs;
36 GF_Clock *ck;
37 Bool do_update_clock = 1;
38 MediaSensorStack *st = (MediaSensorStack *)gf_node_get_private(node);
39
40 if (is_destroy) {
41 /*unlink from OD*/
42 if (st->stream && st->stream->odm)
43 gf_list_del_item(st->stream->odm->ms_stack, st);
44
45 gf_list_del(st->seg);
46 gf_free(st);
47 return;
48 }
49 //we need to disable culling otherwise we may never be called back again ...
50 tr_state->disable_cull = 1;
51
52 if (!st->is_init) {
53 if (!st->stream) {
54 st->stream = gf_mo_register(node, &st->sensor->url, 0, 0);
55 if (!st->stream) return;
56 }
57 if (!st->stream->odm) return;
58
59 gf_list_add(st->stream->odm->ms_stack, st);
60 gf_odm_init_segments(st->stream->odm, st->seg, &st->sensor->url);
61 st->is_init = 1;
62 st->active_seg = 0;
63 }
64 //st->stream may be NULL when destroying the ODM
65 if (!st->stream || !st->stream->odm) return;
66
67 /*media sensor bound to natural media (audio, video) is updated when fetching the stream
68 data for rendering.*/
69
70 ck = NULL;
71 /*check inline scenes - if the scene is set to restart DON'T MODIFY SENSOR: since we need a 2 render
72 passes to restart inline, scene is considered as not running*/
73 if (st->stream->odm->subscene && !st->stream->odm->subscene->needs_restart) {
74 if (! st->stream->odm->subscene->is_dynamic_scene) ck = st->stream->odm->subscene->root_od->ck;
75 /*dynamic scene*/
76 else ck = st->stream->odm->ck;
77
78 if (st->stream->odm->subscene->is_dynamic_scene) do_update_clock = 0;
79 }
80 /*check anim or OCR streams*/
81 else if (st->stream->odm->type==GF_STREAM_SCENE) ck = st->stream->odm->ck;
82 /*check OCR streams*/
83 else if (st->stream->odm->ck) ck = st->stream->odm->ck;
84
85 if (ck && ck->clock_init ) {
86 if (do_update_clock)
87 st->stream->odm->media_current_time = gf_clock_media_time(ck);
88 mediasensor_update_timing(st->stream->odm, GF_FALSE);
89 }
90 //if main addon is VoD , fire a timeshift update
91 else if (st->stream->odm->subscene && st->stream->odm->subscene->sys_clock_at_main_activation) {
92 GF_Event evt;
93 memset(&evt, 0, sizeof(evt));
94 evt.type = GF_EVENT_TIMESHIFT_UPDATE;
95 gf_sc_send_event(st->stream->odm->parentscene->compositor, &evt);
96 }
97 }
98
InitMediaSensor(GF_Scene * scene,GF_Node * node)99 void InitMediaSensor(GF_Scene *scene, GF_Node *node)
100 {
101 MediaSensorStack *st;
102 GF_SAFEALLOC(st, MediaSensorStack);
103 if (!st) {
104 GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Failed to allocate media sensor stack\n"));
105 return;
106 }
107
108 st->parent = scene;
109 st->sensor = (M_MediaSensor *)node;
110 st->seg = gf_list_new();
111 gf_node_set_callback_function(node, RenderMediaSensor);
112 gf_node_set_private(node, st);
113
114 }
115
116 /*only URL can be changed, so reset and get new URL*/
MS_Modified(GF_Node * node)117 void MS_Modified(GF_Node *node)
118 {
119 MediaSensorStack *st = (MediaSensorStack *)gf_node_get_private(node);
120 if (!st) return;
121
122 while (gf_list_count(st->seg)) gf_list_rem(st->seg, 0);
123
124 if (st->stream) {
125 /*unlink from OD*/
126 if (st->stream->odm && st->stream->odm->ms_stack)
127 gf_list_del_item(st->stream->odm->ms_stack, st);
128
129 gf_mo_unregister(node, st->stream);
130 if (st->sensor->isActive) {
131 st->sensor->isActive = 0;
132 gf_node_event_out((GF_Node *) st->sensor, 4/*"isActive"*/);
133 }
134 }
135 st->stream = NULL;
136 st->is_init = 0;
137 gf_sc_invalidate(st->parent->compositor, NULL);
138 }
139
mediasensor_update_timing(GF_ObjectManager * odm,Bool is_eos)140 void mediasensor_update_timing(GF_ObjectManager *odm, Bool is_eos)
141 {
142 GF_Segment *desc;
143 u32 i, count, j, ms_count;
144 Double time;
145 ms_count = gf_list_count(odm->ms_stack);
146 if (!ms_count) return;
147
148 time = odm->media_current_time / 1000.0;
149 //dirty hack to get timing of frame when very late (openhevc debug)
150 if (odm->subscene && odm->ck && odm->ck->last_ts_rendered)
151 time = odm->ck->last_ts_rendered / 1000.0;
152
153 for (j=0; j<ms_count; j++) {
154 MediaSensorStack *media_sens = (MediaSensorStack *)gf_list_get(odm->ms_stack, j);
155 if (!media_sens->is_init) continue;
156 count = gf_list_count(media_sens->seg);
157
158 /*full object controled*/
159 if (!media_sens->active_seg && !count) {
160 /*check for end of scene (MediaSensor on inline)*/
161 if (odm->subscene && odm->subscene->duration) {
162 GF_Clock *ck = gf_odm_get_media_clock(odm);
163 if (ck->has_seen_eos && (1000*time>=(Double) (s64)odm->subscene->duration)) {
164 if (media_sens->sensor->isActive) {
165 /*force notification of time (ntify the scene duration rather than the current clock*/
166 media_sens->sensor->mediaCurrentTime = (Double) odm->subscene->duration;
167 media_sens->sensor->mediaCurrentTime /= 1000;
168 gf_node_event_out((GF_Node *) media_sens->sensor, 1/*"mediaCurrentTime"*/);
169 media_sens->sensor->isActive = 0;
170 gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/);
171
172 GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[ODM%d] Deactivating media sensor\n", odm->ID));
173 }
174 continue;
175 }
176 }
177
178 if (!is_eos && !media_sens->sensor->isActive) {
179 media_sens->sensor->isActive = 1;
180 gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/);
181
182 gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/);
183 if (odm->subscene) {
184 media_sens->sensor->mediaDuration = (Double) (s64)odm->subscene->duration;
185 } else {
186 media_sens->sensor->mediaDuration = (Double) (s64)odm->duration;
187 }
188 if (media_sens->sensor->mediaDuration)
189 media_sens->sensor->mediaDuration /= 1000;
190 else
191 media_sens->sensor->mediaDuration = -FIX_ONE;
192
193 gf_node_event_out((GF_Node *) media_sens->sensor, 3/*"mediaDuration"*/);
194 }
195
196 if (is_eos && media_sens->sensor->isActive) {
197 if (media_sens->sensor->mediaDuration>=0) {
198 media_sens->sensor->mediaCurrentTime = media_sens->sensor->mediaDuration;
199 } else {
200 media_sens->sensor->mediaCurrentTime = time;
201 }
202 gf_node_event_out((GF_Node *) media_sens->sensor, 1/*"mediaCurrentTime"*/);
203 media_sens->sensor->isActive = 0;
204 gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/);
205 } else {
206 if (media_sens->sensor->isActive && (media_sens->sensor->mediaCurrentTime != time)) {
207 media_sens->sensor->mediaCurrentTime = time;
208 gf_node_event_out((GF_Node *) media_sens->sensor, 1/*"mediaCurrentTime"*/);
209 }
210 }
211 continue;
212 }
213
214 /*locate segment*/
215 for (i=media_sens->active_seg; i<count; i++) {
216 desc = (GF_Segment*)gf_list_get(media_sens->seg, i);
217 /*not controled*/
218 if (desc->startTime > time) {
219 if (media_sens->sensor->isActive) {
220 media_sens->sensor->isActive = 0;
221 gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/);
222
223 GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[ODM%d] Deactivating media sensor at time %g - segment %s\n", odm->ID, time, desc->SegmentName));
224 }
225 continue;
226 }
227 if (desc->startTime + desc->Duration < time) continue;
228 if (desc->startTime + desc->Duration == time) {
229 continue;
230 }
231 /*segment switch, force activation (isActive TRUE send at each seg)*/
232 if (media_sens->active_seg != i) {
233 media_sens->active_seg = i;
234 media_sens->sensor->isActive = 0;
235 }
236
237 if (!media_sens->sensor->isActive) {
238
239 GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[ODM%d] Activating media sensor time %g - segment %s\n", odm->ID, time, desc->SegmentName));
240
241 media_sens->sensor->isActive = 1;
242 gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/);
243 /*set info*/
244 gf_sg_vrml_mf_reset(& media_sens->sensor->info, GF_SG_VRML_MFSTRING);
245 gf_sg_vrml_mf_alloc(& media_sens->sensor->info, GF_SG_VRML_MFSTRING, 1);
246 media_sens->sensor->info.vals[0] = desc->SegmentName ? gf_strdup(desc->SegmentName) : NULL;
247 gf_node_event_out((GF_Node *) media_sens->sensor, 5/*"info"*/);
248 /*set duration*/
249 media_sens->sensor->mediaDuration = desc->Duration;
250 gf_node_event_out((GF_Node *) media_sens->sensor, 3/*"mediaDuration"*/);
251 /*set seg start time*/
252 media_sens->sensor->streamObjectStartTime = desc->startTime;
253 gf_node_event_out((GF_Node *) media_sens->sensor, 2/*"streamObjectStartTime"*/);
254
255 }
256
257 /*set media time - relative to segment start time*/
258 time -= desc->startTime;
259 if (media_sens->sensor->mediaCurrentTime != time) {
260 media_sens->sensor->mediaCurrentTime = time;
261 gf_node_event_out((GF_Node *) media_sens->sensor, 1/*"mediaCurrentTime"*/);
262 }
263 break;
264 }
265 if (i==count) {
266 /*we're after last segment, deactivate*/
267 if (media_sens->sensor->isActive) {
268 media_sens->sensor->isActive = 0;
269 gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/);
270 media_sens->active_seg = count;
271 GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[ODM%d] Deactivating media sensor at time %g: no more segments\n", odm->ID, time));
272 }
273 }
274 }
275 }
276
MS_Stop(MediaSensorStack * st)277 void MS_Stop(MediaSensorStack *st)
278 {
279 if (st->sensor->isActive) {
280 st->sensor->isActive = 0;
281 gf_node_event_out((GF_Node *) st->sensor, 4/*"isActive"*/);
282
283 GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[ODM%d] Deactivating media sensor\n", st->stream->odm->ID));
284 }
285 st->active_seg = 0;
286 }
287
288 #endif /*GPAC_DISABLE_VRML*/
289