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