blob: 039ad3e1e5079803d4abb5c70a12291bf11de85d [file] [edit]
/*
* GPAC - Multimedia Framework C SDK
*
* Authors: Jean Le Feuvre
* Copyright (c) Telecom ParisTech 2000-2023
* All rights reserved
*
* This file is part of GPAC / BIFS codec sub-project
*
* GPAC is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* GPAC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <gpac/internal/bifs_dev.h>
#ifndef GPAC_DISABLE_BIFS
/*private stack for conditional*/
typedef struct
{
/*BIFS decoder*/
GF_BifsDecoder *codec;
/*BIFS config of original stream carrying the conditional*/
BIFSStreamInfo *info;
} ConditionalStack;
void Conditional_PreDestroy(GF_Node *n, void *eff, Bool is_destroy)
{
if (is_destroy) {
ConditionalStack *priv = (ConditionalStack*)gf_node_get_private(n);
if (priv->codec)
gf_list_del_item(priv->codec->conditional_nodes, &priv->codec);
if (priv) gf_free(priv);
}
}
void Conditional_BufferReplaced(GF_BifsDecoder *codec, GF_Node *n)
{
ConditionalStack *priv = (ConditionalStack*)gf_node_get_private(n);
if (!priv || (gf_node_get_tag(n) != TAG_MPEG4_Conditional)) return;
priv->info = codec->info;
}
static void Conditional_execute(M_Conditional *node)
{
char *buffer;
u32 len;
GF_BitStream *bs;
GF_BifsDecoder *codec;
GF_Proto *prevproto;
GF_SceneGraph *prev_graph;
ConditionalStack *priv = (ConditionalStack*)gf_node_get_private((GF_Node*)node);
if (!priv || !priv->codec) return;
/*set the codec working graph to the node one (to handle conditional in protos)*/
prev_graph = priv->codec->current_graph;
priv->codec->current_graph = gf_node_get_graph((GF_Node*)node);
if (!priv->codec->current_graph) return;
priv->codec->info = priv->info;
prevproto = priv->codec->pCurrentProto;
priv->codec->pCurrentProto = NULL;
if (priv->codec->current_graph->pOwningProto) priv->codec->pCurrentProto = priv->codec->current_graph->pOwningProto->proto_interface;
/*set isActive - to clarify in the specs*/
node->isActive = 1;
gf_node_event_out((GF_Node *)node, 3/*"isActive"*/);
if (!node->buffer.bufferSize) return;
/*we may replace ourselves*/
buffer = (char*)node->buffer.buffer;
len = node->buffer.bufferSize;
node->buffer.buffer = NULL;
node->buffer.bufferSize = 0;
bs = gf_bs_new(buffer, len, GF_BITSTREAM_READ);
codec = priv->codec;
codec->cts_offset = gf_node_get_scene_time((GF_Node*)node);
/*a conditional may destroy/replace itself - to prevent that, protect node by a register/unregister ...*/
gf_node_register((GF_Node*)node, NULL);
#ifdef GF_SELF_REPLACE_ENABLE
/*and a conditional may destroy the entire scene!*/
cur_graph->graph_has_been_reset = 0;
#endif
gf_bifs_dec_command(codec, bs);
gf_bs_del(bs);
#ifdef GF_SELF_REPLACE_ENABLE
if (cur_graph->graph_has_been_reset) {
return;
}
#endif
if (node->buffer.buffer) {
gf_free(buffer);
} else {
node->buffer.buffer = (u8*)buffer;
node->buffer.bufferSize = len;
}
//set isActive - to clarify in the specs
// node->isActive = 0;
gf_node_unregister((GF_Node*)node, NULL);
codec->cts_offset = 0;
codec->pCurrentProto = prevproto;
codec->current_graph = prev_graph;
}
void Conditional_OnActivate(GF_Node *n, GF_Route *route)
{
M_Conditional *node = (M_Conditional *)n;
if (! node->activate) return;
Conditional_execute(node);
}
void Conditional_OnReverseActivate(GF_Node *n, GF_Route *route)
{
M_Conditional *node = (M_Conditional *)n;
if (node->reverseActivate) return;
Conditional_execute(node);
}
void SetupConditional(GF_BifsDecoder *codec, GF_Node *node)
{
ConditionalStack *priv;
if (gf_node_get_tag(node) != TAG_MPEG4_Conditional) return;
priv = (ConditionalStack*)gf_malloc(sizeof(ConditionalStack));
/*needed when initializing extern protos*/
if (!codec->info) codec->info = (BIFSStreamInfo*)gf_list_get(codec->streamInfo, 0);
if (!codec->info) return;
priv->info = codec->info;
priv->codec = codec;
codec->has_conditionnals = GF_TRUE;
gf_list_add(codec->conditional_nodes, &priv->codec);
gf_node_set_callback_function(node, Conditional_PreDestroy);
gf_node_set_private(node, priv);
((M_Conditional *)node)->on_activate = Conditional_OnActivate;
((M_Conditional *)node)->on_reverseActivate = Conditional_OnReverseActivate;
}
#endif /*GPAC_DISABLE_BIFS*/
/*this is ugly but we have no choice, we need to clone the conditional stack because of externProto*/
void BIFS_SetupConditionalClone(GF_Node *node, GF_Node *orig)
{
#ifndef GPAC_DISABLE_BIFS
M_Conditional *ptr;
ConditionalStack *priv_orig, *priv;
priv_orig = (ConditionalStack*)gf_node_get_private(orig);
/*looks we're not in BIFS*/
if (!priv_orig) {
#else
{
#endif
#ifndef GPAC_DISABLE_VRML
u32 i;
GF_Command *ori_com;
M_Conditional *c_orig, *c_dest;
c_orig = (M_Conditional *)orig;
c_dest = (M_Conditional *)node;
gf_node_init(node);
/*and clone all commands*/
i=0;
while ((ori_com = (GF_Command*)gf_list_enum(c_orig->buffer.commandList, &i))) {
GF_Command *dest_com = gf_sg_vrml_command_clone(ori_com, gf_node_get_graph(node), GF_TRUE);
if (dest_com) gf_list_add(c_dest->buffer.commandList, dest_com);
}
#endif
return;
}
#ifndef GPAC_DISABLE_BIFS
priv = (ConditionalStack*)gf_malloc(sizeof(ConditionalStack));
priv->codec = priv_orig->codec;
if (priv->codec)
gf_list_add(priv->codec->conditional_nodes, &priv->codec);
priv->info = priv_orig->info;
gf_node_set_callback_function(node, Conditional_PreDestroy);
gf_node_set_private(node, priv);
ptr = (M_Conditional *)node;
ptr->on_activate = Conditional_OnActivate;
ptr->on_reverseActivate = Conditional_OnReverseActivate;
#endif
}