LCOV - code coverage report
Current view: top level - compositor - mpeg4_textures.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 264 339 77.9 %
Date: 2021-04-29 23:48:07 Functions: 18 20 90.0 %

          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 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             : 
      28             : #include <gpac/network.h>
      29             : #include <gpac/nodes_mpeg4.h>
      30             : #include <gpac/nodes_x3d.h>
      31             : 
      32             : #ifndef GPAC_DISABLE_VRML
      33             : 
      34             : #ifdef __cplusplus
      35             : extern "C" {
      36             : #endif
      37             : 
      38             : /*for cache texture decode and hash*/
      39             : #include <gpac/avparse.h>
      40             : #include <gpac/crypt.h>
      41             : #include "nodes_stacks.h"
      42             : 
      43             : 
      44             : typedef struct
      45             : {
      46             :         GF_TextureHandler txh;
      47             : 
      48             :         GF_TimeNode time_handle;
      49             :         Bool fetch_first_frame, first_frame_fetched, is_x3d;
      50             :         Double start_time;
      51             : } MovieTextureStack;
      52             : 
      53         251 : static void movietexture_destroy(GF_Node *node, void *rs, Bool is_destroy)
      54             : {
      55         251 :         if (is_destroy) {
      56         251 :                 MovieTextureStack *st = (MovieTextureStack *) gf_node_get_private(node);
      57         251 :                 gf_sc_texture_destroy(&st->txh);
      58         251 :                 if (st->time_handle.is_registered) gf_sc_unregister_time_node(st->txh.compositor, &st->time_handle);
      59         251 :                 gf_free(st);
      60             :         }
      61         251 : }
      62             : static Fixed movietexture_get_speed(MovieTextureStack *stack, M_MovieTexture *mt)
      63             : {
      64        7812 :         return gf_mo_get_speed(stack->txh.stream, mt->speed);
      65             : }
      66             : static Bool movietexture_get_loop(MovieTextureStack *stack, M_MovieTexture *mt)
      67             : {
      68        2088 :         return gf_mo_get_loop(stack->txh.stream, mt->loop);
      69             : }
      70         223 : static void movietexture_activate(MovieTextureStack *stack, M_MovieTexture *mt, Double scene_time)
      71             : {
      72         223 :         mt->isActive = 1;
      73         223 :         gf_node_event_out((GF_Node*)mt, 8/*"isActive"*/);
      74         223 :         if (!stack->txh.is_open) {
      75         216 :                 scene_time -= mt->startTime;
      76         216 :                 gf_sc_texture_play_from_to(&stack->txh, &mt->url, scene_time, -1, gf_mo_get_loop(stack->txh.stream, mt->loop), 0);
      77           7 :         } else if (stack->first_frame_fetched) {
      78           1 :                 gf_mo_resume(stack->txh.stream);
      79             :         }
      80         223 :         gf_mo_set_speed(stack->txh.stream, mt->speed);
      81         223 : }
      82           1 : static void movietexture_deactivate(MovieTextureStack *stack, M_MovieTexture *mt)
      83             : {
      84           1 :         mt->isActive = 0;
      85           1 :         gf_node_event_out((GF_Node*)mt, 8/*"isActive"*/);
      86           1 :         stack->time_handle.needs_unregister = 1;
      87             : 
      88           1 :         if (stack->txh.is_open) {
      89           1 :                 gf_sc_texture_stop_no_unregister(&stack->txh);
      90             :         }
      91           1 : }
      92        8379 : static void movietexture_update(GF_TextureHandler *txh)
      93             : {
      94        8379 :         M_MovieTexture *txnode = (M_MovieTexture *) txh->owner;
      95        8379 :         MovieTextureStack *st = (MovieTextureStack *) gf_node_get_private(txh->owner);
      96             : 
      97             :         /*setup texture if needed*/
      98        8379 :         if (!txh->is_open) return;
      99        8347 :         if (!txnode->isActive && st->first_frame_fetched) return;
     100             : 
     101             :         /*when fetching the first frame disable resync*/
     102        8255 :         gf_sc_texture_update_frame(txh, 0);
     103             : 
     104        8255 :         if (txh->stream_finished) {
     105        4176 :                 if (movietexture_get_loop(st, txnode)) {
     106           0 :                         gf_sc_texture_restart(txh);
     107             :                 }
     108             :                 /*if active deactivate*/
     109        2088 :                 else if (txnode->isActive && (txnode->startTime<txnode->stopTime) && gf_mo_should_deactivate(st->txh.stream) ) {
     110           0 :                         movietexture_deactivate(st, txnode);
     111             :                 }
     112             :         }
     113             :         /*first frame is fetched*/
     114        8255 :         if (!st->first_frame_fetched && (txh->needs_refresh) ) {
     115         210 :                 st->first_frame_fetched = 1;
     116         210 :                 txnode->duration_changed = gf_mo_get_duration(txh->stream);
     117         210 :                 gf_node_event_out(txh->owner, 7/*"duration_changed"*/);
     118             :                 /*stop stream if needed*/
     119         210 :                 if (!txnode->isActive && txh->is_open) {
     120           1 :                         gf_mo_pause(txh->stream);
     121             :                         /*make sure the refresh flag is not cleared*/
     122           1 :                         txh->needs_refresh = 1;
     123           1 :                         gf_sc_invalidate(txh->compositor, NULL);
     124             :                 }
     125             :         }
     126        8255 :         if (txh->needs_refresh) {
     127             :                 /*mark all subtrees using this image as dirty*/
     128        4202 :                 gf_node_dirty_parents(txh->owner);
     129             :         }
     130             : }
     131             : 
     132        8348 : static void movietexture_update_time(GF_TimeNode *st)
     133             : {
     134             :         Double time;
     135        8348 :         M_MovieTexture *mt = (M_MovieTexture *)st->udta;
     136        8348 :         MovieTextureStack *stack = (MovieTextureStack *)gf_node_get_private(st->udta);
     137             : 
     138             :         /*not active, store start time and speed*/
     139        8348 :         if ( ! mt->isActive) {
     140         759 :                 stack->start_time = mt->startTime;
     141             :         }
     142        8348 :         time = gf_node_get_scene_time(st->udta);
     143             : 
     144       16160 :         if (time < stack->start_time ||
     145             :                 /*special case if we're getting active AFTER stoptime */
     146        8035 :                 (!mt->isActive && (mt->stopTime > stack->start_time) && (time>=mt->stopTime))
     147             : //              || (!stack->start_time && !stack->is_x3d && !mt->loop)
     148             :            ) {
     149             :                 /*opens stream only at first access to fetch first frame*/
     150         536 :                 if (stack->fetch_first_frame) {
     151           7 :                         stack->fetch_first_frame = 0;
     152           7 :                         if (!stack->txh.is_open)
     153           7 :                                 gf_sc_texture_play(&stack->txh, &mt->url);
     154             :                         else
     155           0 :                                 gf_mo_resume(stack->txh.stream);
     156             :                 }
     157             :                 return;
     158             :         }
     159             : 
     160       15624 :         if (movietexture_get_speed(stack, mt) && mt->isActive) {
     161             :                 /*if stoptime is reached (>startTime) deactivate*/
     162        7585 :                 if ((mt->stopTime > stack->start_time) && (time >= mt->stopTime) ) {
     163           1 :                         movietexture_deactivate(stack, mt);
     164           1 :                         return;
     165             :                 }
     166             :         }
     167             : 
     168             :         /*we're (about to be) active: VRML:
     169             :         "A time-dependent node is inactive until its startTime is reached. When time now becomes greater than or
     170             :         equal to startTime, an isActive TRUE event is generated and the time-dependent node becomes active      */
     171             : 
     172        7811 :         if (! mt->isActive) movietexture_activate(stack, mt, time);
     173        7811 :         stack->txh.stream_finished = GF_FALSE;
     174        7811 :         if (!mt->url.count)
     175        1919 :                 stack->txh.stream_finished = GF_TRUE;
     176             : }
     177             : 
     178         251 : void compositor_init_movietexture(GF_Compositor *compositor, GF_Node *node)
     179             : {
     180             :         MovieTextureStack *st;
     181         251 :         GF_SAFEALLOC(st, MovieTextureStack);
     182         251 :         if (!st) {
     183           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate movie texture stack\n"));
     184             :                 return;
     185             :         }
     186         251 :         gf_sc_texture_setup(&st->txh, compositor, node);
     187         251 :         st->txh.update_texture_fcnt = movietexture_update;
     188         251 :         st->time_handle.UpdateTimeNode = movietexture_update_time;
     189         251 :         st->time_handle.udta = node;
     190         251 :         st->fetch_first_frame = 1;
     191         251 :         st->txh.flags = 0;
     192         251 :         if (((M_MovieTexture*)node)->repeatS) st->txh.flags |= GF_SR_TEXTURE_REPEAT_S;
     193         251 :         if (((M_MovieTexture*)node)->repeatT) st->txh.flags |= GF_SR_TEXTURE_REPEAT_T;
     194             : 
     195             : #ifndef GPAC_DISABLE_X3D
     196         251 :         st->is_x3d = (gf_node_get_tag(node)==TAG_X3D_MovieTexture) ? 1 : 0;
     197             : #endif
     198             : 
     199         251 :         gf_node_set_private(node, st);
     200         251 :         gf_node_set_callback_function(node, movietexture_destroy);
     201             : 
     202         251 :         gf_sc_register_time_node(compositor, &st->time_handle);
     203             : }
     204             : 
     205       16423 : GF_TextureHandler *mt_get_texture(GF_Node *node)
     206             : {
     207       16423 :         MovieTextureStack *st = (MovieTextureStack *) gf_node_get_private(node);
     208       16423 :         return &st->txh;
     209             : }
     210             : 
     211         206 : void compositor_movietexture_modified(GF_Node *node)
     212             : {
     213             :         M_MovieTexture *mt = (M_MovieTexture *)node;
     214         206 :         MovieTextureStack *st = (MovieTextureStack *) gf_node_get_private(node);
     215         206 :         if (!st) return;
     216             : 
     217             :         /*if open and changed, stop and play*/
     218         206 :         if (gf_sc_texture_check_url_change(&st->txh, &mt->url)) {
     219         204 :                 if (st->txh.is_open) gf_sc_texture_stop(&st->txh);
     220         204 :                 if (mt->isActive) gf_sc_texture_play(&st->txh, &mt->url);
     221             :         }
     222             :         /*update state if we're active*/
     223           2 :         else if (mt->isActive) {
     224           1 :                 movietexture_update_time(&st->time_handle);
     225           1 :                 if (!mt->isActive) return;
     226             :         }
     227             :         /*reregister if needed*/
     228         205 :         st->time_handle.needs_unregister = 0;
     229         205 :         if (!st->time_handle.is_registered) gf_sc_register_time_node(st->txh.compositor, &st->time_handle);
     230             : }
     231             : 
     232         107 : static void imagetexture_destroy(GF_Node *node, void *rs, Bool is_destroy)
     233             : {
     234         107 :         if (is_destroy) {
     235         107 :                 GF_TextureHandler *txh = (GF_TextureHandler *) gf_node_get_private(node);
     236             : 
     237             :                 /*cleanup cache if needed*/
     238         107 :                 if (gf_node_get_tag(node)==TAG_MPEG4_CacheTexture) {
     239             :                         char section[64];
     240             :                         const char *opt, *file;
     241             :                         Bool delete_file = GF_TRUE;
     242             :                         M_CacheTexture *ct = (M_CacheTexture*)node;
     243             : 
     244             :                         sprintf(section, "@cache=%p", ct);
     245           8 :                         file = gf_opts_get_key(section, "cacheFile");
     246           8 :                         opt = gf_opts_get_key(section, "expireAfterNTP");
     247             : 
     248           8 :                         if (opt) {
     249             :                                 u32 sec, frac, exp;
     250           1 :                                 sscanf(opt, "%u", &exp);
     251           1 :                                 gf_net_get_ntp(&sec, &frac);
     252           1 :                                 if (!exp || (exp>sec)) delete_file=GF_FALSE;
     253             :                         }
     254             :                         if (delete_file) {
     255           7 :                                 if (file) gf_file_delete((char*)file);
     256           7 :                                 gf_opts_del_section(section);
     257             :                         }
     258             : 
     259           8 :                         if (txh->data) gf_free(txh->data);
     260           8 :                         txh->data = NULL;
     261             :                 }
     262         107 :                 gf_sc_texture_destroy(txh);
     263         107 :                 gf_free(txh);
     264             :         }
     265         107 : }
     266             : 
     267        7651 : static void imagetexture_update(GF_TextureHandler *txh)
     268             : {
     269        7651 :         if (gf_node_get_tag(txh->owner)!=TAG_MPEG4_CacheTexture) {
     270        7057 :                 MFURL url = ((M_ImageTexture *) txh->owner)->url;
     271             : 
     272             :                 /*setup texture if needed*/
     273        7057 :                 if (!txh->is_open && url.count) {
     274          92 :                         gf_sc_texture_play(txh, &url);
     275             :                 }
     276        7057 :                 gf_sc_texture_update_frame(txh, 0);
     277             : 
     278        7057 :                 if (
     279             :                     /*URL is present but not opened - redraw till fetch*/
     280             :                     /* (txh->stream && !txh->tx_io) && */
     281             :                     /*image has been updated*/
     282        7057 :                     txh->needs_refresh) {
     283             :                         /*mark all subtrees using this image as dirty*/
     284          99 :                         gf_node_dirty_parents(txh->owner);
     285          99 :                         gf_sc_invalidate(txh->compositor, NULL);
     286             :                 }
     287             :                 return;
     288             :         }
     289             :         /*cache texture case*/
     290             :         else {
     291         594 :                 M_CacheTexture *ct = (M_CacheTexture *) txh->owner;
     292             : 
     293             :                 /*decode cacheTexture data */
     294         594 :                 if ((ct->data || ct->image.buffer) && !txh->data) {
     295             : #ifndef GPAC_DISABLE_AV_PARSERS
     296             :                         u32 out_size;
     297             :                         GF_Err e;
     298             : 
     299             :                         /*BT/XMT playback: load to memory*/
     300           2 :                         if (ct->image.buffer) {
     301           2 :                                 char *par = (char *) gf_scene_get_service_url( gf_node_get_graph(txh->owner ) );
     302           2 :                                 char *src_url = gf_url_concatenate(par, ct->image.buffer);
     303             : 
     304           2 :                                 if (ct->data) gf_free(ct->data);
     305           2 :                                 ct->data = NULL;
     306           2 :                                 ct->data_len = 0;
     307             : 
     308           2 :                                 e = gf_file_load_data(src_url ? src_url : ct->image.buffer, &ct->data, &ct->data_len);
     309           2 :                                 if (e) {
     310           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to load CacheTexture data from file %s: %s\n", src_url ? src_url : ct->image.buffer, gf_error_to_string(e) ) );
     311             :                                 }
     312           2 :                                 if (ct->image.buffer) gf_free(ct->image.buffer);
     313           2 :                                 ct->image.buffer = NULL;
     314           2 :                                 if (src_url) gf_free(src_url);
     315             :                         }
     316             : 
     317             :                         /*BIFS decoded playback*/
     318           2 :                         switch (ct->objectTypeIndication) {
     319           2 :                         case GF_CODECID_JPEG:
     320           2 :                                 out_size = 0;
     321           2 :                                 e = gf_img_jpeg_dec(ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size, 3);
     322           2 :                                 if (e==GF_BUFFER_TOO_SMALL) {
     323             :                                         u32 BPP;
     324           2 :                                         txh->data = gf_malloc(sizeof(char) * out_size);
     325           2 :                                         if (txh->pixelformat==GF_PIXEL_GREYSCALE) BPP = 1;
     326             :                                         else BPP = 3;
     327             : 
     328           2 :                                         e = gf_img_jpeg_dec(ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size, BPP);
     329           2 :                                         if (e==GF_OK) {
     330           2 :                                                 gf_sc_texture_allocate(txh);
     331           2 :                                                 gf_sc_texture_set_data(txh);
     332           2 :                                                 txh->needs_refresh = 1;
     333           2 :                                                 txh->stride = out_size / txh->height;
     334             :                                         }
     335             :                                 }
     336             :                                 break;
     337           0 :                         case GF_CODECID_PNG:
     338           0 :                                 out_size = 0;
     339           0 :                                 e = gf_img_png_dec(ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size);
     340           0 :                                 if (e==GF_BUFFER_TOO_SMALL) {
     341           0 :                                         txh->data = gf_malloc(sizeof(char) * out_size);
     342           0 :                                         e = gf_img_png_dec(ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size);
     343           0 :                                         if (e==GF_OK) {
     344           0 :                                                 gf_sc_texture_allocate(txh);
     345           0 :                                                 gf_sc_texture_set_data(txh);
     346           0 :                                                 txh->needs_refresh = 1;
     347           0 :                                                 txh->stride = out_size / txh->height;
     348             :                                         }
     349             :                                 }
     350             :                                 break;
     351             :                         }
     352             : 
     353             : #endif // GPAC_DISABLE_AV_PARSERS
     354             : 
     355             :                         /*cacheURL is specified, store the image*/
     356           2 :                         if (ct->cacheURL.buffer) {
     357             :                                 u32 i;
     358             :                                 u8 hash[20];
     359             :                                 FILE *cached_texture;
     360             :                                 char szExtractName[GF_MAX_PATH], *opt, *src_url;
     361           1 :                                 opt = (char *) gf_opts_get_key("core", "cache");
     362           1 :                                 if (opt) {
     363             :                                         strcpy(szExtractName, opt);
     364             :                                 } else {
     365           0 :                                         strcpy(szExtractName, gf_get_default_cache_directory());
     366             :                                 }
     367             :                                 strcat(szExtractName, "/");
     368           1 :                                 src_url = (char *) gf_scene_get_service_url( gf_node_get_graph(txh->owner ) );
     369             : 
     370           1 :                                 gf_sha1_csum((u8 *)src_url, (u32) strlen(src_url), hash);
     371          21 :                                 for (i=0; i<20; i++) {
     372             :                                         char t[3];
     373          20 :                                         t[2] = 0;
     374          20 :                                         sprintf(t, "%02X", hash[i]);
     375             :                                         strcat(szExtractName, t);
     376             :                                 }
     377             :                                 strcat(szExtractName, "_");
     378             : 
     379           1 :                                 strcat(szExtractName, ct->cacheURL.buffer);
     380           1 :                                 cached_texture = gf_fopen(szExtractName, "wb");
     381           1 :                                 if (cached_texture) {
     382           1 :                                         gf_fwrite(ct->data, ct->data_len, cached_texture);
     383           1 :                                         gf_fclose(cached_texture);
     384             :                                 }
     385             : 
     386             :                                 /*and write cache info*/
     387           1 :                                 if (ct->expirationDate!=0) {
     388             :                                         char section[64];
     389             :                                         sprintf(section, "@cache=%p", ct);
     390           1 :                                         gf_opts_set_key(section, "serviceURL", src_url);
     391           1 :                                         gf_opts_set_key(section, "cacheFile", szExtractName);
     392           1 :                                         gf_opts_set_key(section, "cacheName", ct->cacheURL.buffer);
     393             : 
     394           1 :                                         if (ct->expirationDate>0) {
     395             :                                                 char exp[50];
     396             :                                                 u32 sec, frac;
     397           1 :                                                 gf_net_get_ntp(&sec, &frac);
     398           1 :                                                 sec += ct->expirationDate;
     399             :                                                 sprintf(exp, "%u", sec);
     400           1 :                                                 gf_opts_set_key(section, "expireAfterNTP", exp);
     401             :                                         } else {
     402           0 :                                                 gf_opts_set_key(section, "expireAfterNTP", "0");
     403             :                                         }
     404             :                                 }
     405             :                         }
     406             : 
     407             :                         /*done with image, destroy buffer*/
     408           2 :                         if (ct->data) gf_free(ct->data);
     409           2 :                         ct->data = NULL;
     410           2 :                         ct->data_len = 0;
     411             :                 }
     412             :         }
     413             : }
     414             : 
     415         107 : void compositor_init_imagetexture(GF_Compositor *compositor, GF_Node *node)
     416             : {
     417             :         GF_TextureHandler *txh;
     418         107 :         GF_SAFEALLOC(txh, GF_TextureHandler);
     419         107 :         if (!txh) {
     420           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate image texture stack\n"));
     421             :                 return;
     422             :         }
     423         107 :         gf_sc_texture_setup(txh, compositor, node);
     424         107 :         txh->update_texture_fcnt = imagetexture_update;
     425         107 :         gf_node_set_private(node, txh);
     426         107 :         gf_node_set_callback_function(node, imagetexture_destroy);
     427         107 :         txh->flags = 0;
     428             : 
     429         107 :         if (gf_node_get_tag(txh->owner)!=TAG_MPEG4_CacheTexture) {
     430          99 :                 if (((M_ImageTexture*)node)->repeatS) txh->flags |= GF_SR_TEXTURE_REPEAT_S;
     431          99 :                 if (((M_ImageTexture*)node)->repeatT) txh->flags |= GF_SR_TEXTURE_REPEAT_T;
     432             :         } else {
     433             :                 const char *url;
     434             :                 u32 i, count;
     435             :                 M_CacheTexture*ct = (M_CacheTexture*)node;
     436           8 :                 if (!ct->image.buffer) return;
     437             : 
     438           2 :                 if (ct->repeatS) txh->flags |= GF_SR_TEXTURE_REPEAT_S;
     439           2 :                 if (ct->repeatT) txh->flags |= GF_SR_TEXTURE_REPEAT_T;
     440             : 
     441             :                 /*locate existing cache*/
     442           2 :                 url = gf_scene_get_service_url( gf_node_get_graph(node) );
     443           2 :                 count = gf_opts_get_section_count();
     444          19 :                 for (i=0; i<count; i++) {
     445             :                         const char *opt;
     446          17 :                         const char *name = gf_opts_get_section_name(i);
     447          17 :                         if (strncmp(name, "@cache=", 7)) continue;
     448           0 :                         opt = gf_opts_get_key(name, "serviceURL");
     449           0 :                         if (!opt || stricmp(opt, url)) continue;
     450           0 :                         opt = gf_opts_get_key(name, "cacheName");
     451           0 :                         if (opt && ct->cacheURL.buffer && !stricmp(opt, ct->cacheURL.buffer)) {
     452           0 :                                 opt = gf_opts_get_key(name, "cacheFile");
     453           0 :                                 if (opt) gf_file_delete((char*)opt);
     454           0 :                                 gf_opts_del_section(name);
     455           0 :                                 break;
     456             :                         }
     457             :                 }
     458             : 
     459             :         }
     460             : }
     461             : 
     462       19730 : GF_TextureHandler *it_get_texture(GF_Node *node)
     463             : {
     464       19730 :         return gf_node_get_private(node);
     465             : }
     466          14 : void compositor_imagetexture_modified(GF_Node *node)
     467             : {
     468             :         MFURL url;
     469             :         SFURL sfurl;
     470          14 :         GF_TextureHandler *txh = (GF_TextureHandler *) gf_node_get_private(node);
     471          27 :         if (!txh) return;
     472             : 
     473          14 :         if (gf_node_get_tag(node)!=TAG_MPEG4_CacheTexture) {
     474          14 :                 url = ((M_ImageTexture *) node)->url;
     475             :         } else {
     476           0 :                 url.count = 1;
     477           0 :                 sfurl.OD_ID=GF_MEDIA_EXTERNAL_ID;
     478           0 :                 sfurl.url = ((M_CacheTexture *) node)->image.buffer;
     479           0 :                 url.vals = &sfurl;
     480             :         }
     481             : 
     482             :         /*if open and changed, stop and play*/
     483          14 :         if (txh->is_open) {
     484          13 :                 if (! gf_sc_texture_check_url_change(txh, &url)) return;
     485          13 :                 gf_sc_texture_stop(txh);
     486          13 :                 gf_sc_texture_play(txh, &url);
     487          13 :                 return;
     488             :         }
     489             :         /*if not open and changed play*/
     490           1 :         if (url.count)
     491           1 :                 gf_sc_texture_play(txh, &url);
     492             : }
     493             : 
     494             : 
     495             : 
     496             : typedef struct
     497             : {
     498             :         GF_TextureHandler txh;
     499             :         char *pixels;
     500             : } PixelTextureStack;
     501             : 
     502          10 : static void pixeltexture_destroy(GF_Node *node, void *rs, Bool is_destroy)
     503             : {
     504          10 :         if (is_destroy) {
     505          10 :                 PixelTextureStack *st = (PixelTextureStack *) gf_node_get_private(node);
     506          10 :                 if (st->pixels) gf_free(st->pixels);
     507          10 :                 gf_sc_texture_destroy(&st->txh);
     508          10 :                 gf_free(st);
     509             :         }
     510          10 : }
     511        1145 : static void pixeltexture_update(GF_TextureHandler *txh)
     512             : {
     513             :         u32 pix_format, stride, i;
     514        1145 :         M_PixelTexture *pt = (M_PixelTexture *) txh->owner;
     515        1145 :         PixelTextureStack *st = (PixelTextureStack *) gf_node_get_private(txh->owner);
     516             : 
     517        1145 :         if (!gf_node_dirty_get(txh->owner)) return;
     518          16 :         gf_node_dirty_clear(txh->owner, 0);
     519             : 
     520             : 
     521             :         /*pixel texture doesn not use any media object but has data in the content.
     522             :         However we still use the same texture object, just be careful not to use media funtcions*/
     523          16 :         txh->transparent = 0;
     524          16 :         stride = pt->image.width;
     525             :         /*num_components are as in VRML (1->4) not as in BIFS bitstream (0->3)*/
     526          16 :         switch (pt->image.numComponents) {
     527             :         case 1:
     528             :                 pix_format = GF_PIXEL_GREYSCALE;
     529             :                 break;
     530           1 :         case 2:
     531             :                 pix_format = GF_PIXEL_ALPHAGREY;
     532           1 :                 txh->transparent = 1;
     533           1 :                 stride *= 2;
     534           1 :                 break;
     535           1 :         case 3:
     536             :                 pix_format = GF_PIXEL_RGB;
     537             :                 txh->transparent = 0;
     538           1 :                 stride *= 3;
     539           1 :                 break;
     540           1 :         case 4:
     541             :                 pix_format = GF_PIXEL_RGBA;
     542           1 :                 txh->transparent = 1;
     543           1 :                 stride *= 4;
     544           1 :                 break;
     545             :         default:
     546             :                 return;
     547             :         }
     548             : 
     549          16 :         if (!txh->tx_io) {
     550          10 :                 gf_sc_texture_allocate(txh);
     551          10 :                 if (!txh->tx_io) return;
     552             :         }
     553             : 
     554          16 :         if (st->pixels) gf_free(st->pixels);
     555          16 :         st->pixels = (char*)gf_malloc(sizeof(char) * stride * pt->image.height);
     556             :         /*FIXME FOR OPENGL !!*/
     557             : #if 0
     558             :         for (i=0; i<pt->image.height; i++) {
     559             :                 memcpy(st->pixels + i * stride, pt->image.pixels + i * stride, stride);
     560             :         }
     561             : #else
     562             :         /*revert pixel ordering...*/
     563          80 :         for (i=0; i<pt->image.height; i++) {
     564          64 :                 memcpy(st->pixels + i * stride, pt->image.pixels + (pt->image.height - 1 - i) * stride, stride);
     565             :         }
     566             : #endif
     567             : 
     568          16 :         txh->width = pt->image.width;
     569          16 :         txh->height = pt->image.height;
     570          16 :         txh->stride = stride;
     571          16 :         txh->pixelformat = pix_format;
     572          16 :         txh->data = st->pixels;
     573             : 
     574          16 :         gf_sc_texture_set_data(txh);
     575             : }
     576             : 
     577          10 : void compositor_init_pixeltexture(GF_Compositor *compositor, GF_Node *node)
     578             : {
     579             :         PixelTextureStack *st;
     580          10 :         GF_SAFEALLOC(st, PixelTextureStack);
     581          10 :         if (!st) {
     582           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate pixel texture stack\n"));
     583             :                 return;
     584             :         }
     585          10 :         gf_sc_texture_setup(&st->txh, compositor, node);
     586          10 :         st->pixels = NULL;
     587          10 :         st->txh.update_texture_fcnt = pixeltexture_update;
     588             : 
     589          10 :         gf_node_set_private(node, st);
     590          10 :         gf_node_set_callback_function(node, pixeltexture_destroy);
     591          10 :         st->txh.flags = 0;
     592          10 :         if (((M_PixelTexture*)node)->repeatS) st->txh.flags |= GF_SR_TEXTURE_REPEAT_S;
     593          10 :         if (((M_PixelTexture*)node)->repeatT) st->txh.flags |= GF_SR_TEXTURE_REPEAT_T;
     594             : }
     595             : 
     596         746 : GF_TextureHandler *pt_get_texture(GF_Node *node)
     597             : {
     598         746 :         PixelTextureStack *st = (PixelTextureStack *) gf_node_get_private(node);
     599         746 :         return &st->txh;
     600             : }
     601             : 
     602           0 : static void matte_update(GF_TextureHandler *txh)
     603             : {
     604             :         /*nothing to do*/
     605           0 : }
     606             : 
     607           0 : void compositor_init_mattetexture(GF_Compositor *compositor, GF_Node *node)
     608             : {
     609             :         GF_TextureHandler *txh;
     610           0 :         GF_SAFEALLOC(txh, GF_TextureHandler);
     611           0 :         if (!txh) {
     612           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate matte texture stack\n"));
     613             :                 return;
     614             :         }
     615           0 :         gf_sc_texture_setup(txh, compositor, node);
     616           0 :         txh->flags = GF_SR_TEXTURE_MATTE;
     617           0 :         txh->update_texture_fcnt = matte_update;
     618           0 :         gf_node_set_private(node, txh);
     619           0 :         gf_node_set_callback_function(node, imagetexture_destroy);
     620             : }
     621             : 
     622           1 : void gf_sc_mo_destroyed(GF_Node *n)
     623             : {
     624           1 :         void *st = gf_node_get_private(n);
     625           1 :         if (!st) return;
     626             : 
     627           1 :         switch (gf_node_get_tag(n)) {
     628           0 :         case TAG_MPEG4_Background2D:
     629           0 :                 ((Background2DStack *)st)->txh.stream = NULL;
     630           0 :                 break;
     631           0 :         case TAG_MPEG4_Background:
     632             :         case TAG_X3D_Background:
     633             : #ifndef GPAC_DISABLE_3D
     634           0 :                 ((BackgroundStack *)st)->txh_back.stream = NULL;
     635           0 :                 ((BackgroundStack *)st)->txh_front.stream = NULL;
     636           0 :                 ((BackgroundStack *)st)->txh_left.stream = NULL;
     637           0 :                 ((BackgroundStack *)st)->txh_right.stream = NULL;
     638           0 :                 ((BackgroundStack *)st)->txh_top.stream = NULL;
     639           0 :                 ((BackgroundStack *)st)->txh_bottom.stream = NULL;
     640             : #endif
     641           0 :                 break;
     642           1 :         case TAG_MPEG4_ImageTexture:
     643             :         case TAG_X3D_ImageTexture:
     644           1 :                 ((GF_TextureHandler *)st)->stream = NULL;
     645           1 :                 break;
     646           0 :         case TAG_MPEG4_MovieTexture:
     647             :         case TAG_X3D_MovieTexture:
     648           0 :                 ((MovieTextureStack *)st)->txh.stream = NULL;
     649           0 :                 break;
     650           0 :         case TAG_MPEG4_MediaSensor:
     651           0 :                 ((MediaSensorStack *)st)->stream = NULL;
     652           0 :                 break;
     653           0 :         case TAG_MPEG4_MediaControl:
     654           0 :                 ((MediaControlStack *)st)->stream = NULL;
     655           0 :                 break;
     656           0 :         case TAG_MPEG4_AudioSource:
     657           0 :                 ((AudioSourceStack *)st)->input.stream = NULL;
     658           0 :                 break;
     659           0 :         case TAG_MPEG4_AudioClip:
     660             :         case TAG_X3D_AudioClip:
     661           0 :                 ((AudioClipStack *)st)->input.stream = NULL;
     662           0 :                 break;
     663             : #ifndef GPAC_DISABLE_SVG
     664           0 :         case TAG_SVG_video:
     665             :         case TAG_SVG_image:
     666           0 :                 ((SVG_video_stack *)st)->txh.stream = NULL;
     667           0 :                 break;
     668           0 :         case TAG_SVG_audio:
     669           0 :                 ((SVG_audio_stack *)st)->input.stream = NULL;
     670           0 :                 break;
     671             : #endif
     672             :         default:
     673             :                 break;
     674             :         }
     675             : }
     676             : 
     677             : #ifdef __cplusplus
     678             : }
     679             : #endif
     680             : #endif /*GPAC_DISABLE_VRML*/

Generated by: LCOV version 1.13