Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2018
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 : #include "texturing.h"
27 : #include <gpac/options.h>
28 :
29 : #include "nodes_stacks.h"
30 :
31 3830 : static void update_texture_void(GF_TextureHandler *txh)
32 : {
33 3830 : }
34 :
35 : GF_EXPORT
36 1400 : void gf_sc_texture_setup(GF_TextureHandler *txh, GF_Compositor *compositor, GF_Node *owner)
37 : {
38 : memset(txh, 0, sizeof(GF_TextureHandler));
39 1400 : txh->owner = owner;
40 1400 : txh->compositor = compositor;
41 : /*insert texture in reverse order, so that textures in sub documents/scenes are updated before parent ones*/
42 1400 : if (gf_list_find(compositor->textures, txh)<0) {
43 1400 : gf_list_insert(compositor->textures, txh, 0);
44 1400 : compositor->texture_inserted = GF_TRUE;
45 : }
46 1400 : if (!txh->update_texture_fcnt) txh->update_texture_fcnt = update_texture_void;
47 1400 : }
48 :
49 :
50 : GF_EXPORT
51 1927 : void gf_sc_texture_destroy(GF_TextureHandler *txh)
52 : {
53 1927 : GF_Compositor *compositor = txh->compositor;
54 1927 : Bool lock = gf_mx_try_lock(compositor->mx);
55 :
56 1927 : gf_sc_texture_release(txh);
57 1927 : if (txh->is_open) gf_sc_texture_stop(txh);
58 1927 : gf_list_del_item(txh->compositor->textures, txh);
59 :
60 1927 : if (lock) gf_mx_v(compositor->mx);
61 1927 : }
62 :
63 : GF_EXPORT
64 232 : Bool gf_sc_texture_check_url_change(GF_TextureHandler *txh, MFURL *url)
65 : {
66 232 : if (!txh->stream) return url->count;
67 26 : return gf_mo_url_changed(txh->stream, url);
68 : }
69 :
70 : GF_EXPORT
71 558 : GF_Err gf_sc_texture_open(GF_TextureHandler *txh, MFURL *url, Bool lock_scene_timeline)
72 : {
73 558 : if (txh->is_open) return GF_BAD_PARAM;
74 :
75 : /*if existing texture in cache destroy it - we don't destroy it on stop to handle MovieTexture*/
76 409 : if (txh->tx_io) gf_sc_texture_release(txh);
77 :
78 : /*get media object*/
79 409 : txh->stream = gf_mo_register(txh->owner, url, lock_scene_timeline, 0);
80 : //consider the texture open to avoid repeatingly calling for open on bad URLs/OD
81 409 : txh->is_open = 1;
82 :
83 : /*bad/Empty URL*/
84 409 : if (!txh->stream) return GF_NOT_SUPPORTED;
85 :
86 392 : return GF_OK;
87 : }
88 :
89 : GF_EXPORT
90 408 : GF_Err gf_sc_texture_play_from_to(GF_TextureHandler *txh, MFURL *url, Double start_offset, Double end_offset, Bool can_loop, Bool lock_scene_timeline)
91 : {
92 408 : if (!txh->stream) {
93 : GF_Err e;
94 407 : if (!url) return GF_BAD_PARAM;
95 407 : e = gf_sc_texture_open(txh, url, lock_scene_timeline);
96 407 : if (e != GF_OK) return e;
97 : }
98 393 : txh->is_open = 1;
99 393 : txh->stream_finished = GF_FALSE;
100 : /*request play*/
101 393 : gf_mo_play(txh->stream, start_offset, end_offset, can_loop);
102 :
103 393 : txh->last_frame_time = (u32) (-1);
104 :
105 : //we need to rework the raw memory stuff to be transparent
106 : #ifdef FILTER_FIXME
107 : txh->raw_memory = GF_FALSE;
108 : #endif
109 : /*request play*/
110 393 : return GF_OK;
111 : }
112 :
113 : GF_EXPORT
114 188 : GF_Err gf_sc_texture_play(GF_TextureHandler *txh, MFURL *url)
115 : {
116 : Double offset = 0;
117 : Bool loop = 0;
118 :
119 188 : if (txh->compositor->play_state != GF_STATE_PLAYING) {
120 0 : offset = gf_node_get_scene_time(txh->owner);
121 : loop = /*gf_mo_get_loop(gf_mo_register(txh->owner, url, 0, 0), 0)*/ 1;
122 : }
123 :
124 188 : return gf_sc_texture_play_from_to(txh, url, offset, -1, loop, 0);
125 : }
126 :
127 :
128 : GF_EXPORT
129 2 : void gf_sc_texture_stop_no_unregister(GF_TextureHandler *txh)
130 : {
131 2 : if (!txh->is_open) return;
132 : /*release texture WITHOUT dropping frame*/
133 2 : if (txh->needs_release) {
134 0 : gf_mo_release_data(txh->stream, 0xFFFFFFFF, 1);
135 0 : txh->needs_release = 0;
136 0 : txh->frame_ifce = NULL;
137 : }
138 2 : gf_sc_invalidate(txh->compositor, NULL);
139 2 : gf_mo_stop(&txh->stream);
140 2 : txh->data = NULL;
141 2 : txh->frame_ifce = NULL;
142 :
143 2 : txh->is_open = 0;
144 : }
145 :
146 : GF_EXPORT
147 408 : void gf_sc_texture_stop(GF_TextureHandler *txh)
148 : {
149 408 : if (!txh->is_open) return;
150 : /*release texture WITHOUT dropping frame*/
151 408 : if (txh->needs_release) {
152 1 : gf_mo_release_data(txh->stream, 0xFFFFFFFF, -1);
153 1 : txh->needs_release = 0;
154 1 : txh->frame_ifce = NULL;
155 : }
156 408 : gf_sc_invalidate(txh->compositor, NULL);
157 408 : gf_mo_stop(&txh->stream);
158 408 : if (!txh->stream) {
159 76 : txh->data = NULL;
160 76 : txh->frame_ifce = NULL;
161 : }
162 408 : txh->is_open = 0;
163 :
164 : /*and deassociate object*/
165 408 : gf_mo_unregister(txh->owner, txh->stream);
166 408 : txh->stream = NULL;
167 : }
168 :
169 : GF_EXPORT
170 0 : void gf_sc_texture_restart(GF_TextureHandler *txh)
171 : {
172 0 : if (!txh->is_open) return;
173 0 : gf_sc_texture_release_stream(txh);
174 0 : txh->stream_finished = 0;
175 0 : gf_mo_restart(txh->stream);
176 : }
177 :
178 :
179 388 : static void setup_texture_object(GF_TextureHandler *txh, Bool private_media)
180 : {
181 388 : if (!txh->tx_io) {
182 388 : gf_sc_texture_allocate(txh);
183 388 : if (!txh->tx_io) return;
184 :
185 388 : gf_mo_get_visual_info(txh->stream, &txh->width, &txh->height, &txh->stride, &txh->pixel_ar, &txh->pixelformat, &txh->is_flipped);
186 388 : gf_sc_texture_configure_conversion(txh);
187 :
188 388 : gf_pixel_get_size_info(txh->pixelformat, txh->width, txh->height, NULL, NULL, NULL, &txh->nb_planes, NULL);
189 :
190 388 : if (private_media) {
191 0 : txh->transparent = 1;
192 0 : txh->pixelformat = GF_PIXEL_ARGB;
193 0 : txh->flags |= GF_SR_TEXTURE_PRIVATE_MEDIA;
194 : } else {
195 388 : txh->transparent = 0;
196 388 : switch (txh->pixelformat) {
197 112 : case GF_PIXEL_ALPHAGREY:
198 : case GF_PIXEL_GREYALPHA:
199 : case GF_PIXEL_ARGB:
200 : case GF_PIXEL_RGBA:
201 : case GF_PIXEL_YUVA:
202 : case GF_PIXEL_RGBDS:
203 112 : txh->transparent = 1;
204 112 : break;
205 : }
206 : }
207 : }
208 : }
209 :
210 :
211 : GF_EXPORT
212 65298 : void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync)
213 : {
214 : Bool needs_reload = 0;
215 : u32 size, ts, push_time;
216 : s32 ms_until_pres, ms_until_next;
217 :
218 65298 : if (!txh->stream) {
219 47512 : txh->data = NULL;
220 107800 : return;
221 : }
222 17786 : if (txh->stream->config_changed) {
223 42 : txh->data = NULL;
224 : }
225 :
226 : /*already refreshed*/
227 17786 : if ((txh->stream_finished && txh->tx_io) || txh->needs_refresh)
228 : return;
229 :
230 : /*should never happen!!*/
231 8498 : if (txh->needs_release) {
232 0 : gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0);
233 0 : txh->frame_ifce=NULL;
234 : }
235 :
236 : /*check init flag*/
237 8498 : if (txh->stream->config_changed) {
238 : needs_reload = 1;
239 20 : txh->data = NULL;
240 20 : if (txh->tx_io) {
241 0 : gf_sc_texture_release(txh);
242 : }
243 : }
244 : //if first frame use 20ms as upload time
245 8498 : push_time = txh->nb_frames ? txh->upload_time/txh->nb_frames : 20;
246 8498 : txh->data = gf_mo_fetch_data(txh->stream, disable_resync ? GF_MO_FETCH : GF_MO_FETCH_RESYNC, push_time, &txh->stream_finished, &ts, &size, &ms_until_pres, &ms_until_next, &txh->frame_ifce, NULL);
247 :
248 8498 : if (txh->stream->config_changed) {
249 : needs_reload = 1;
250 8277 : } else if (txh->data && size && txh->size && (size != txh->size)) {
251 : needs_reload = 1;
252 : }
253 :
254 8272 : if (needs_reload) {
255 : /*if we had a texture this means the object has changed - delete texture and resetup. Do not skip
256 : texture update as this may lead to an empty rendering pass (blank frame for this object), especially in DASH*/
257 226 : if (txh->tx_io) {
258 1 : gf_sc_texture_release(txh);
259 1 : txh->needs_refresh = 1;
260 : }
261 226 : txh->flags &= ~GF_SR_TEXTURE_DISABLE_BLIT;
262 :
263 : }
264 :
265 : /*if no frame or muted don't draw*/
266 8498 : if (!txh->data && !txh->frame_ifce) {
267 2822 : GF_LOG(txh->stream->connect_failure ? GF_LOG_DEBUG : GF_LOG_INFO, GF_LOG_COMPOSE, ("[Texture %p] No output frame available \n", txh));
268 :
269 2822 : if (txh->compositor->use_step_mode || !txh->compositor->player) {
270 2818 : if (!txh->stream->connect_failure && ((s32)txh->last_frame_time<0) ) {
271 2310 : if (!txh->probe_time_ms) txh->probe_time_ms = gf_sys_clock();
272 1935 : else if (gf_sys_clock() - txh->probe_time_ms > txh->compositor->timeout / 2) {
273 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Texture %p] No output frame in %d ms, considering stream not available\n", txh, txh->compositor->timeout / 2));
274 0 : txh->stream->connect_failure = GF_TRUE;
275 0 : gf_sc_texture_stop_no_unregister(txh);
276 : }
277 2310 : txh->compositor->ms_until_next_frame = -1;
278 : }
279 : }
280 : /*TODO - check if this is needed */
281 4 : else if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) {
282 : //txh->needs_refresh = 1;
283 0 : gf_sc_invalidate(txh->compositor, NULL);
284 : }
285 : return;
286 : }
287 :
288 5676 : if (txh->compositor->frame_delay > ms_until_pres)
289 445 : txh->compositor->frame_delay = ms_until_pres;
290 :
291 : /*if setup and same frame return*/
292 5676 : if (txh->tx_io && ((s32) txh->last_frame_time>=0) && (txh->stream_finished || (txh->last_frame_time==ts)) ) {
293 666 : gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0);
294 666 : txh->needs_release = 0;
295 666 : if (!txh->stream_finished) {
296 490 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Texture %p] Same frame fetched (TS %u)\n", txh, ts));
297 490 : if (txh->compositor->ms_until_next_frame > ms_until_next)
298 487 : txh->compositor->ms_until_next_frame = ms_until_next;
299 : }
300 : return;
301 : }
302 5010 : GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[Texture %p] Updated new frame at clock time %d (%d ms) time %u ms\n", txh, gf_clock_time(txh->stream->odm->ck), gf_sys_clock(), ts));
303 5010 : txh->stream_finished = 0;
304 5010 : txh->needs_release = 1;
305 5010 : txh->last_frame_time = ts;
306 5010 : txh->size = size;
307 5010 : if (gf_mo_is_muted(txh->stream)) return;
308 :
309 :
310 5010 : if (txh->nb_frames) {
311 4345 : s32 push_delay = txh->upload_time / txh->nb_frames;
312 4345 : if (push_delay > ms_until_pres) ms_until_pres = 0;
313 3909 : else ms_until_pres -= push_delay;
314 : }
315 :
316 5010 : if (txh->compositor->ms_until_next_frame > ms_until_next)
317 4696 : txh->compositor->ms_until_next_frame = ms_until_next;
318 :
319 5010 : if (!txh->tx_io) {
320 388 : setup_texture_object(txh, 0);
321 : }
322 :
323 :
324 :
325 : /*try to push texture on graphics but don't complain if failure*/
326 5010 : gf_sc_texture_set_data(txh);
327 :
328 5010 : txh->needs_refresh = 1;
329 5010 : gf_sc_invalidate(txh->compositor, NULL);
330 : }
331 :
332 : GF_EXPORT
333 75062 : void gf_sc_texture_release_stream(GF_TextureHandler *txh)
334 : {
335 75062 : txh->needs_refresh = 0;
336 75062 : if (txh->needs_release) {
337 : assert(txh->stream);
338 5009 : gf_mo_release_data(txh->stream, 0xFFFFFFFF, (txh->needs_release==2) ? 3 :0);
339 5009 : if (txh->needs_release==2) {
340 145 : txh->last_frame_time = -1;
341 : }
342 5009 : txh->needs_release = 0;
343 5009 : txh->frame_ifce = NULL;
344 :
345 : }
346 75062 : if (txh->stream) txh->stream->config_changed = GF_FALSE;
347 75062 : }
348 :
349 :
350 : GF_EXPORT
351 115122 : GF_TextureHandler *gf_sc_texture_get_handler(GF_Node *n)
352 : {
353 115122 : if (!n) return NULL;
354 70447 : switch (gf_node_get_tag(n)) {
355 : #ifndef GPAC_DISABLE_VRML
356 19730 : case TAG_MPEG4_ImageTexture:
357 : case TAG_MPEG4_CacheTexture:
358 19730 : return it_get_texture(n);
359 16423 : case TAG_MPEG4_MovieTexture:
360 16423 : return mt_get_texture(n);
361 746 : case TAG_MPEG4_PixelTexture:
362 746 : return pt_get_texture(n);
363 :
364 3307 : case TAG_MPEG4_CompositeTexture2D:
365 : case TAG_MPEG4_CompositeTexture3D:
366 3307 : return compositor_get_composite_texture(n);
367 27340 : case TAG_MPEG4_LinearGradient:
368 : case TAG_MPEG4_RadialGradient:
369 27340 : return compositor_mpeg4_get_gradient_texture(n);
370 :
371 0 : case TAG_MPEG4_MatteTexture:
372 : {
373 0 : GF_TextureHandler *hdl = gf_sc_texture_get_handler( ((M_MatteTexture*)n)->surfaceB );
374 0 : if (hdl) hdl->matteTexture = n;
375 : return hdl;
376 : }
377 : #endif /*GPAC_DISABLE_VRML*/
378 :
379 : #ifndef GPAC_DISABLE_X3D
380 0 : case TAG_X3D_ImageTexture:
381 0 : return it_get_texture(n);
382 0 : case TAG_X3D_MovieTexture:
383 0 : return mt_get_texture(n);
384 0 : case TAG_X3D_PixelTexture:
385 0 : return pt_get_texture(n);
386 : #endif
387 :
388 :
389 : #ifndef GPAC_DISABLE_SVG
390 210 : case TAG_SVG_linearGradient:
391 : case TAG_SVG_radialGradient:
392 210 : return compositor_svg_get_gradient_texture(n);
393 2389 : case TAG_SVG_image:
394 : case TAG_SVG_video:
395 2389 : return compositor_svg_get_image_texture(n);
396 : #endif
397 :
398 : #ifndef GPAC_DISABLE_VRML
399 302 : case TAG_ProtoNode:
400 302 : return gf_sc_hardcoded_proto_get_texture_handler(n);
401 : #endif
402 : default:
403 : return NULL;
404 : }
405 : }
|