gimp-gap r770 - in trunk: . gap libgapvidutil
- From: wolfgangh svn gnome org
- To: svn-commits-list gnome org
- Subject: gimp-gap r770 - in trunk: . gap libgapvidutil
- Date: Thu, 31 Jul 2008 18:05:59 +0000 (UTC)
Author: wolfgangh
Date: Thu Jul 31 18:05:59 2008
New Revision: 770
URL: http://svn.gnome.org/viewvc/gimp-gap?rev=770&view=rev
Log:
new feature: filtermacro mapping to persitent drawable ids
Added:
trunk/gap/gap_drawable_vref_parasite.c
trunk/gap/gap_drawable_vref_parasite.h
trunk/gap/gap_fmac_context.c
trunk/gap/gap_fmac_context.h
trunk/gap/gap_frame_fetcher.c
trunk/gap/gap_frame_fetcher.h
Modified:
trunk/NEWS
trunk/gap/Makefile.am
trunk/gap/gap_filter_iterators.c
trunk/gap/gap_filter_pdb.c
trunk/gap/gap_filter_pdb.h
trunk/gap/gap_fmac_base.c
trunk/gap/gap_fmac_main.c
trunk/gap/gap_player_dialog.c
trunk/gap/gap_player_main.c
trunk/gap/gap_player_main.h
trunk/gap/gap_story_dialog.c
trunk/gap/gap_story_file.c
trunk/gap/gap_story_render_processor.c
trunk/gap/gap_story_render_types.h
trunk/gap/gap_story_vthumb.c
trunk/libgapvidutil/gap_gve_story.h
Modified: trunk/NEWS
==============================================================================
--- trunk/NEWS (original)
+++ trunk/NEWS Thu Jul 31 18:05:59 2008
@@ -1,3 +1,33 @@
+Here is a short overview whats new in GIMP-GAP-2.5.0:
+-----------------------------------------------------
+(compared to gimp-gap release 2.4.0)
+
+- Player supports extracting audio track when playing clips
+ that refere to a videofile that has one or more audiotrack(s)
+
+- Filtermacro processing now supports mapping to
+ persistent drawable id references.
+ This allows applying recorded filtermacros in another gimp session
+ in case the recorded last values buffer data contains references
+ to drawable ids.
+ such as the drawable for a bump map in the plug_in_bump_map,
+ or all the layers that were used to map on a quader in plug_in_map_object.
+
+ The persistent references can refer to anim frames (series of numbered
+ images), multilayer images, or videofiles.
+
+ Filtermacros can be applied with fixed or varying values
+ in Storyboard clips. For varying values 2 filtermacros
+ are required to provide from and to values. Iteration of
+ persistent drawable ids is supported in case both refer to the
+ same image, anim frame series or the same videofile.
+
+- viedo extract supports generating transparency via bluebox effect.
+
+- Modify Frames now supports creation of grayscale layer from
+ alpha channel, or layermask or mix of both
+
+
Here is a short overview whats new in GIMP-GAP-2.3.0:
-----------------------------------------------------
(compared to gimp-gap release 2.2.1)
Modified: trunk/gap/Makefile.am
==============================================================================
--- trunk/gap/Makefile.am (original)
+++ trunk/gap/Makefile.am Thu Jul 31 18:05:59 2008
@@ -70,8 +70,12 @@
libgapstory_a_SOURCES = $(BASE_SOURCES) \
+ gap_frame_fetcher.c \
+ gap_frame_fetcher.h \
gap_fmac_name.c \
gap_fmac_name.h \
+ gap_fmac_context.c \
+ gap_fmac_context.h \
gap_story_file.h \
gap_story_file.c \
gap_story_render_types.h \
@@ -158,6 +162,12 @@
gap_filter_main.c \
gap_filter_pdb.c \
gap_filter_pdb.h \
+ gap_drawable_vref_parasite.c \
+ gap_drawable_vref_parasite.h \
+ gap_fmac_context.c \
+ gap_fmac_context.h \
+ gap_frame_fetcher.c \
+ gap_frame_fetcher.h \
gap_lastvaldesc.c \
gap_lastvaldesc.h \
gap_libgimpgap.h
@@ -170,11 +180,17 @@
gap_filter_foreach.c \
gap_filter_iterators.c \
gap_filter_iterators.h \
+ gap_drawable_vref_parasite.c \
+ gap_drawable_vref_parasite.h \
gap_fmac_main.c \
gap_filter_pdb.c \
gap_filter_pdb.h \
+ gap_frame_fetcher.c \
+ gap_frame_fetcher.h \
gap_fmac_name.c \
gap_fmac_name.h \
+ gap_fmac_context.c \
+ gap_fmac_context.h \
gap_fmac_base.c \
gap_fmac_base.h \
gap_lastvaldesc.c \
@@ -185,11 +201,17 @@
gap_filter.h \
gap_filter_iterators.c \
gap_filter_iterators.h \
+ gap_drawable_vref_parasite.c \
+ gap_drawable_vref_parasite.h \
gap_fmac_varying_main.c \
gap_filter_pdb.c \
gap_filter_pdb.h \
+ gap_frame_fetcher.c \
+ gap_frame_fetcher.h \
gap_fmac_name.c \
gap_fmac_name.h \
+ gap_fmac_context.c \
+ gap_fmac_context.h \
gap_fmac_base.c \
gap_fmac_base.h \
gap_lastvaldesc.c \
@@ -239,6 +261,8 @@
gap_player_cache.h \
gap_audio_extract.c \
gap_audio_extract.h \
+ gap_drawable_vref_parasite.c \
+ gap_drawable_vref_parasite.h \
gap_libgapstory.h \
gap_libgimpgap.h
@@ -275,6 +299,8 @@
gap_player_dialog.h \
gap_player_cache.c \
gap_player_cache.h \
+ gap_drawable_vref_parasite.c \
+ gap_drawable_vref_parasite.h \
gap_libgapstory.h \
gap_libgimpgap.h
@@ -294,6 +320,8 @@
gap_player_dialog.h \
gap_player_cache.c \
gap_player_cache.h \
+ gap_drawable_vref_parasite.c \
+ gap_drawable_vref_parasite.h \
gap_libgapstory.h \
gap_libgimpgap.h
@@ -352,9 +380,9 @@
gap_plugins_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
gap_bluebox_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
-gap_filter_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
-gap_fmac_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
-gap_fmac_varying_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
+gap_filter_LDADD = $(GAPVIDEOAPI) $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
+gap_fmac_LDADD = $(GAPVIDEOAPI) $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
+gap_fmac_varying_LDADD = $(GAPVIDEOAPI) $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
gap_frontends_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
gap_morph_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
gap_name2layer_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
Added: trunk/gap/gap_drawable_vref_parasite.c
==============================================================================
--- (empty file)
+++ trunk/gap/gap_drawable_vref_parasite.c Thu Jul 31 18:05:59 2008
@@ -0,0 +1,210 @@
+/* gap_drawable_vref_parasite.c
+ *
+ * This module handles gap specific video reference drawable parasites.
+ * Such parasites are typically used to identify extracted video file frames
+ * for usage in filtermacro as persistent drawable_id references at recording time of filtermacros.
+ *
+ * The gap player does attach such vref drawable parasites (as temporary parasites)
+ * when extracting a videoframe at original size (by click on the preview)
+ *
+ * Copyright (C) 2008 Wolfgang Hofer <hof gimp org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "gap_drawable_vref_parasite.h"
+
+
+extern int gap_debug; /* ==0 ... dont print debug infos */
+
+/* ------------------------------------------
+ * gap_dvref_debug_print_GapDrawableVideoRef
+ * ------------------------------------------
+ */
+void
+gap_dvref_debug_print_GapDrawableVideoRef(GapDrawableVideoRef *dvref)
+{
+ if(gap_debug)
+ {
+ if(dvref == NULL)
+ {
+ printf("GapDrawableVideoRef: dvref:(null)\n");
+ return;
+ }
+ if(dvref->videofile == NULL)
+ {
+ printf("GapDrawableVideoRef: videofile:(null) frame:%d seltrack:%d (%s)\n"
+ ,dvref->para.framenr
+ ,dvref->para.seltrack
+ ,&dvref->para.preferred_decoder[0]
+ );
+ return;
+ }
+
+ printf("GapDrawableVideoRef: videofile:%s frame:%d seltrack:%d (%s)\n"
+ ,dvref->videofile
+ ,dvref->para.framenr
+ ,dvref->para.seltrack
+ ,&dvref->para.preferred_decoder[0]
+ );
+ }
+} /* end gap_dvref_debug_print_GapDrawableVideoRef */
+
+
+/* -------------------
+ * gap_dvref_free
+ * -------------------
+ */
+void
+gap_dvref_free(GapDrawableVideoRef **dvref_ptr)
+{
+ GapDrawableVideoRef *dvref;
+
+ dvref = *dvref_ptr;
+ if (dvref)
+ {
+ if(dvref->videofile)
+ {
+ g_free(dvref->videofile);
+ }
+ g_free(dvref);
+ }
+
+ *dvref_ptr = NULL;
+
+} /* end gap_dvref_free */
+
+/* ---------------------------------------------------
+ * gap_dvref_get_drawable_video_reference_via_parasite
+ * ---------------------------------------------------
+ * return Gap drawable video reference parasite if such a parasite is atached to the specified drawable_id
+ * oterwise return NULL;
+ */
+GapDrawableVideoRef *
+gap_dvref_get_drawable_video_reference_via_parasite(gint32 drawable_id)
+{
+ GapDrawableVideoRef *dvref;
+ GimpParasite *l_parasite;
+
+ dvref = NULL;
+
+ l_parasite = gimp_drawable_parasite_find(drawable_id, GAP_DRAWABLE_VIDEOFILE_PARASITE_NAME);
+ if(l_parasite)
+ {
+ if(gap_debug)
+ {
+ printf("gap_dvref_get_drawable_video_reference_via_parasite: size:%d data:%s\n"
+ ,l_parasite->size
+ ,(char *)l_parasite->data
+ );
+ }
+
+ dvref = g_new(GapDrawableVideoRef, 1);
+
+ dvref->videofile = g_malloc0(l_parasite->size +1);
+ memcpy(dvref->videofile, l_parasite->data, l_parasite->size);
+
+
+ gimp_parasite_free(l_parasite);
+
+
+ l_parasite = gimp_drawable_parasite_find(drawable_id, GAP_DRAWABLE_VIDEOPARAMS_PARASITE_NAME);
+ if(l_parasite)
+ {
+ memcpy(&dvref->para, l_parasite->data, sizeof(GapDrawableVideoParasite));
+ gimp_parasite_free(l_parasite);
+
+ if(gap_debug)
+ {
+ printf("gap_dvref_get_drawable_video_reference_via_parasite: dvref PARASITES OK\n");
+ gap_dvref_debug_print_GapDrawableVideoRef(dvref);
+ }
+ return (dvref);
+ }
+
+ }
+
+ if(gap_debug)
+ {
+ printf("gap_dvref_get_drawable_video_reference_via_parasite: NO dvref parasites found.\n");
+ }
+
+ return (NULL);
+} /* end gap_dvref_get_drawable_video_reference_via_parasite */
+
+
+
+/* --------------------------------------
+ * gap_dvref_assign_videoref_parasites
+ * --------------------------------------
+ * if gpp->drawable_vref contains vaild video reference
+ * then
+ * assign video reference parasites to the specified drawable_id (typically this is a layer.)
+ * (one parasite contains only the videfilename and has variable length,
+ * the other contains framenumber and other information that was used to fetch
+ * the frame from the videofile).
+ *
+ * the video reference is typically set on successful fetch
+ * from a video file. (and reset on all other types of frame fetches)
+ *
+ + TODO: query gimprc parameter that can configures using persitent drawable_videoref_parasites.
+ * (default shall be temporary parasites)
+ */
+void
+gap_dvref_assign_videoref_parasites(GapDrawableVideoRef *dvref, gint32 drawable_id)
+{
+ GimpParasite *l_parasite;
+
+ if(gap_debug)
+ {
+ printf("gap_assign_drawable_videoref_parasite: START\n");
+ gap_dvref_debug_print_GapDrawableVideoRef(dvref);
+ }
+
+ if(dvref->videofile == NULL)
+ {
+ /* no viedo reference available for the current frame */
+ return;
+ }
+
+
+ l_parasite = gimp_parasite_new(GAP_DRAWABLE_VIDEOFILE_PARASITE_NAME
+ ,0 /* GIMP_PARASITE_PERSISTENT 0 for non persistent */
+ ,1 + strlen(dvref->videofile)
+ ,dvref->videofile /* parasite data */
+ );
+ if(l_parasite)
+ {
+ gimp_drawable_parasite_attach(drawable_id, l_parasite);
+ gimp_parasite_free(l_parasite);
+ }
+
+ l_parasite = gimp_parasite_new(GAP_DRAWABLE_VIDEOPARAMS_PARASITE_NAME
+ ,0 /* GIMP_PARASITE_PERSISTENT */
+ ,sizeof(GapDrawableVideoParasite)
+ ,&dvref->para /* parasite data */
+ );
+ if(l_parasite)
+ {
+ gimp_drawable_parasite_attach(drawable_id, l_parasite);
+ gimp_parasite_free(l_parasite);
+ }
+
+} /* end gap_dvref_assign_videoref_parasites */
+
Added: trunk/gap/gap_drawable_vref_parasite.h
==============================================================================
--- (empty file)
+++ trunk/gap/gap_drawable_vref_parasite.h Thu Jul 31 18:05:59 2008
@@ -0,0 +1,57 @@
+/* gap_drawable_vref_parasite.h
+ *
+ * This module handles gap specific video reference drawable parasites.
+ * Such parasites are typically used to identify extracted video file frames
+ * for usage in filtermacro as persistent drawable_id references at recording time of filtermacros.
+ *
+ * The gap player does attach such vref drawable parasites (as temporary parasites)
+ * when extracting a videoframe at original size (by click on the preview)
+ *
+ * Copyright (C) 2008 Wolfgang Hofer <hof gimp org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GAP_DRAWABLE_VREF_PARASITE_H
+#define _GAP_DRAWABLE_VREF_PARASITE_H
+
+#include "libgimp/gimp.h"
+#include "libgimp/gimp.h"
+#include "gap_lib_common_defs.h"
+
+
+#define GAP_DRAWABLE_VIDEOFILE_PARASITE_NAME "gap-video-file"
+#define GAP_DRAWABLE_VIDEOPARAMS_PARASITE_NAME "gap-video-param"
+
+typedef struct GapDrawableVideoParasite {
+ char preferred_decoder[16];
+ gint32 framenr;
+ gint32 seltrack;
+} GapDrawableVideoParasite;
+
+typedef struct GapDrawableVideoRef { /* nickname: dvref */
+ char *videofile;
+ GapDrawableVideoParasite para;
+} GapDrawableVideoRef;
+
+
+GapDrawableVideoRef * gap_dvref_get_drawable_video_reference_via_parasite(gint32 drawable_id);
+void gap_dvref_assign_videoref_parasites(GapDrawableVideoRef *dvref, gint32 layer_id);
+
+void gap_dvref_free(GapDrawableVideoRef **dvref);
+void gap_dvref_debug_print_GapDrawableVideoRef(GapDrawableVideoRef *dvref);
+
+#endif
Modified: trunk/gap/gap_filter_iterators.c
==============================================================================
--- trunk/gap/gap_filter_iterators.c (original)
+++ trunk/gap/gap_filter_iterators.c Thu Jul 31 18:05:59 2008
@@ -94,7 +94,11 @@
#include "gap_filter.h"
#include "gap_filter_iterators.h"
#include "gap_dbbrowser_utils.h"
-
+#include "gap_fmac_context.h"
+#include "gap_frame_fetcher.h"
+#include "gap_drawable_vref_parasite.h"
+#include "gap_lib.h"
+#include "gap/gap_layer_copy.h"
static gchar *g_plugin_data_from = NULL;
@@ -178,6 +182,14 @@
gdouble mutation_dist;
} t_CML_PARAM;
+static void p_delta_drawable_simple(gint32 *val, gint32 val_from, gint32 val_to
+ , gint32 total_steps, gdouble current_step);
+
+static gint32 p_capture_image_name_and_assign_pesistent_id(GapFmacContext *fmacContext
+ , gint32 drawable_id);
+static gboolean p_iteration_by_pesistent_id(GapFmacContext *fmacContext
+ ,gint32 *val, gint32 val_from, gint32 val_to
+ , gint32 total_steps, gdouble current_step);
/* ----------------------------------------------------------------------
* iterator functions for basic datatypes
@@ -337,45 +349,479 @@
val->color[l_idx] = val_from->color[l_idx] + delta;
}
}
-static void p_delta_drawable(gint32 *val, gint32 val_from, gint32 val_to, gint32 total_steps, gdouble current_step)
+
+
+/* ---------------------------
+ * p_delta_drawable
+ * ---------------------------
+ * the drawable iterator checks for current filtermacro context.
+ * if there is such a context, iteration tries to fetch the relvant drawable
+ * via loading an image, or fetching a video frame.
+ * In this case, the drawables (gint32 val_from and val_to) are expected to refere
+ * to persistent Ids
+ * e.g. are >= GAP_FMCT_MIN_PERSISTENT_DRAWABLE_ID
+ * The image_ids of all fetched images are added to a list of last recent temp images
+ * this list has to be deleted at end of filtermacro processing. if the list contains
+ * more than NNNNN entries, the oldest entries are deleted at begin of a new fetch
+ * to make space for the next temporary image.
+ *
+ * if the record flag of the filtermacro context is set
+ * we do record identifying information about the the current drawable (*val)
+ * in the persistent_id_lookup_filename. The drawable id is therfore mapped into a persitent
+ * drawable_id that is unique in the persistent_id_lookup_file.
+ * (the 1st entry starts with GAP_FMCT_MIN_PERSISTENT_DRAWABLE_ID)
+ */
+void
+p_delta_drawable(gint32 *val, gint32 val_from, gint32 val_to, gint32 total_steps, gdouble current_step)
+{
+ gint sizeFmacContext;
+
+ if(gap_debug)
+ {
+ printf("p_delta_drawable: START *val drawable_id:%d (from:%d to:%d)\n"
+ ,(int)*val
+ ,(int)val_from
+ ,(int)val_to
+ );
+ }
+
+ sizeFmacContext = gimp_get_data_size(GAP_FMAC_CONTEXT_KEYWORD);
+
+ if(sizeFmacContext == sizeof(GapFmacContext))
+ {
+ GapFmacContext *fmacContext;
+ fmacContext = g_malloc0(sizeFmacContext);
+ if(fmacContext)
+ {
+ gimp_get_data(GAP_FMAC_CONTEXT_KEYWORD, fmacContext);
+
+ if(fmacContext->enabled == TRUE)
+ {
+ gboolean success;
+
+ gap_fmct_load_GapFmacContext(fmacContext);
+
+ /* check for record conditions */
+ if(fmacContext->recording_mode)
+ {
+ gint32 drawable_id;
+
+ drawable_id = *val;
+
+ /* calculate and assign the mapped persistent darawable_id */
+ *val = p_capture_image_name_and_assign_pesistent_id(fmacContext, drawable_id);
+
+ gap_fmct_free_GapFmacRefList(fmacContext);
+ g_free(fmacContext);
+ return;
+ }
+ success = p_iteration_by_pesistent_id(fmacContext, val, val_from, val_to, total_steps, current_step);
+ if (success)
+ {
+ gap_fmct_free_GapFmacRefList(fmacContext);
+ g_free(fmacContext);
+ return;
+ }
+ }
+ gap_fmct_free_GapFmacRefList(fmacContext);
+ g_free(fmacContext);
+ }
+
+ }
+
+ /* simple iteration of layers if in the same image (without context) */
+ p_delta_drawable_simple(val, val_from, val_to, total_steps, current_step);
+
+} /* end p_delta_drawable */
+
+
+/* ---------------------------
+ * p_delta_drawable_simple
+ * ---------------------------
+ * simple iteration for drawable id (in case val_from and val_to both refere to
+ * the same image (that is already opened in the current gimp session)
+ */
+static void
+p_delta_drawable_simple(gint32 *val, gint32 val_from, gint32 val_to, gint32 total_steps, gdouble current_step)
+{
+ gint l_nlayers;
+ gint32 *l_layers_list;
+ gint32 l_tmp_image_id;
+ gint l_idx, l_idx_from, l_idx_to;
+
+ if(gap_debug)
+ {
+ printf("p_delta_drawable_simple: START *val drawable_id:%d (from:%d to:%d)\n"
+ ,(int)*val
+ ,(int)val_from
+ ,(int)val_to
+ );
+ }
+ if((val_from < 0) || (val_to < 0))
+ {
+ return;
+ }
+
+ l_tmp_image_id = gimp_drawable_get_image(val_from);
+
+ /* check if from and to values are both valid drawables within the same image */
+ if ((l_tmp_image_id > 0)
+ && (l_tmp_image_id = gimp_drawable_get_image(val_to)))
+ {
+ l_idx_from = -1;
+ l_idx_to = -1;
+
+ /* check the layerstack index of from and to drawable */
+ l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers);
+ for (l_idx = l_nlayers -1; l_idx >= 0; l_idx--)
+ {
+ if( l_layers_list[l_idx] == val_from ) l_idx_from = l_idx;
+ if( l_layers_list[l_idx] == val_to ) l_idx_to = l_idx;
+
+ if((l_idx_from != -1) && (l_idx_to != -1))
+ {
+ /* OK found both index values, iterate the index (proceed to next layer) */
+ p_delta_gint(&l_idx, l_idx_from, l_idx_to, total_steps, current_step);
+ *val = l_layers_list[l_idx];
+ break;
+ }
+ }
+ g_free (l_layers_list);
+ }
+} /* end p_delta_drawable_simple */
+
+
+/* ------------------------------------
+ * p_drawable_is_alive
+ * ------------------------------------
+ * current implementation checks only for layers and layermasks.
+ * TODO check other drawable types such as channels ....
+ *
+ * return TRUE if OK (drawable is still valid)
+ * return FALSE if drawable is NOT valid
+ */
+gboolean
+p_drawable_is_alive(gint32 drawable_id)
{
+ gint32 *images;
+ gint nimages;
+ gint l_idi;
+ gboolean l_found;
+
+ if(drawable_id < 0)
+ {
+ return FALSE;
+ }
+
+ images = gimp_image_list(&nimages);
+ l_idi = nimages -1;
+ l_found = FALSE;
+ while((l_idi >= 0) && images)
+ {
gint l_nlayers;
gint32 *l_layers_list;
- gint32 l_tmp_image_id;
- gint l_idx, l_idx_from, l_idx_to;
- if((val_from < 0) || (val_to < 0))
+ l_layers_list = gimp_image_get_layers(images[l_idi], &l_nlayers);
+ if(l_layers_list != NULL)
{
- return;
+ gint l_idx;
+ l_idx = l_nlayers;
+ for(l_idx = 0; l_idx < l_nlayers; l_idx++)
+ {
+ gint32 l_layer_id;
+ gint32 l_layermask_id;
+
+ l_layer_id = l_layers_list[0];
+ if (l_layer_id == drawable_id)
+ {
+ l_found = TRUE;
+ break;
+ }
+ l_layermask_id = gimp_layer_get_mask(l_layer_id);
+ if (l_layermask_id == drawable_id)
+ {
+ l_found = TRUE;
+ break;
+ }
+ }
+ g_free (l_layers_list);
}
+
+ if (l_found == TRUE)
+ {
+ break;
+ }
+ l_idi--;
+ }
- l_tmp_image_id = gimp_drawable_get_image(val_from);
+ if(images) g_free(images);
+ if(l_found)
+ {
+ return TRUE; /* OK */
+ }
- /* check if from and to values are both valid drawables within the same image */
- if ((l_tmp_image_id > 0)
- && (l_tmp_image_id = gimp_drawable_get_image(val_to)))
+ if(gap_debug)
+ {
+ printf("p_drawable_is_alive: drawable_id %d is not VALID\n", (int)drawable_id);
+ }
+
+ return FALSE ; /* INVALID image id */
+} /* end p_drawable_is_alive */
+
+/* --------------------------------------------
+ * p_capture_image_name_and_assign_pesistent_id
+ * --------------------------------------------
+ * Capture the identifying information about the image, anim_frame or videofile name and layerstack index
+ * (or frameposition) of the specified drawable_id.
+ * Note: videofilename and framenumber can be fetched from layer parasite data.
+ * (plus additional information prefered_decoder and seltrack)
+ * parasite data shall be set when the player creates a snapshot of a video clip.
+ * (click in the preview)
+ * (Player option: enable videoname parasites.)
+ * assign a persistent id that is unique within a persistent_id_lookup_file.
+ * filtermacro context.
+ * returns the assigned persistent_drawable_id.
+ * (In case no assigned persisten_drawable_id could be created
+ * return the original drawable_id).
+ */
+static gint32
+p_capture_image_name_and_assign_pesistent_id(GapFmacContext *fmacContext, gint32 drawable_id)
+{
+ gint32 persistent_drawable_id;
+ gint32 image_id;
+ GapDrawableVideoRef *dvref;
+ GapLibAinfoType ainfo_type;
+ gint32 frame_nr;
+ gint32 stackposition;
+ gint32 track;
+ char *filename;
+
+
+ if(gap_debug)
+ {
+ printf("p_capture_image_name_and_assign_pesistent_id: START_REC orignal_drawable_id:%d\n"
+ ,drawable_id
+ );
+ }
+
+ if(p_drawable_is_alive(drawable_id) != TRUE)
+ {
+ /* drawable is no longer valid and can not be mapped.
+ * This may happen if the layer was removed or the refered image was close
+ * in the time since the plugin has stored the last values buffer
+ * and the time when filtermacro starts recording filtercalls.
+ */
+ return(drawable_id);
+ }
+
+ persistent_drawable_id = drawable_id;
+ filename = NULL;
+
+ dvref = gap_dvref_get_drawable_video_reference_via_parasite(drawable_id);
+ if (dvref != NULL)
+ {
+ if(gap_debug)
{
- l_idx_from = -1;
- l_idx_to = -1;
+ printf("p_capture_image_name_and_assign_pesistent_id: VIDEO ref found for orignal_drawable_id:%d\n"
+ ,drawable_id
+ );
+ }
+ ainfo_type = GAP_AINFO_MOVIE;
+ frame_nr = dvref->para.framenr; /* video frame number */
+ stackposition = -1; /* stackposition not relevant for video */
+ track = dvref->para.seltrack;
+ filename = g_strdup(dvref->videofile);
+
+ gap_dvref_free(&dvref);
+ }
+ else
+ {
+ GapAnimInfo *l_ainfo_ptr;
+
+ image_id = gimp_drawable_get_image(drawable_id);
+ filename = gimp_image_get_filename(image_id);
+ ainfo_type = GAP_AINFO_ANIMIMAGE;
+ stackposition = gap_layer_get_stackposition(image_id, drawable_id);
+ track = 1;
+ frame_nr = 1;
+
+ // here we could check gimp_image_is_dirty(image_id)
+ // to check for unsaved changes of the image.
+ // but the recording of a filtermacro can happen much later than
+ // the initial recording of the plugin's last values buffer.
+
+ l_ainfo_ptr = gap_lib_alloc_ainfo(image_id, GIMP_RUN_NONINTERACTIVE);
+ if(l_ainfo_ptr != NULL)
+ {
+ ainfo_type = l_ainfo_ptr->ainfo_type;
+ frame_nr = l_ainfo_ptr->frame_nr;
+ track = -1; /* video track (not relevant for frames and single images) */
+
+ gap_lib_free_ainfo(&l_ainfo_ptr);
+ }
+ }
+
+ if (filename != NULL)
+ {
+ persistent_drawable_id = gap_fmct_add_GapFmacRefEntry(ainfo_type
+ , frame_nr
+ , stackposition
+ , track
+ , drawable_id
+ , filename
+ , FALSE /* force_id NO (e.g generate unique id) */
+ , fmacContext
+ );
+ g_free(filename);
+ }
+
+
+ if(gap_debug)
+ {
+ printf("p_capture_image_name_and_assign_pesistent_id: orignal_drawable_id:%d mapped_drawable_id:%d\n"
+ ,drawable_id
+ ,persistent_drawable_id
+ );
+ }
+
+ return (persistent_drawable_id);
+} /* end p_capture_image_name_and_assign_pesistent_id */
- /* check the layerstack index of from and to drawable */
- l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers);
- for (l_idx = l_nlayers -1; l_idx >= 0; l_idx--)
- {
- if( l_layers_list[l_idx] == val_from ) l_idx_from = l_idx;
- if( l_layers_list[l_idx] == val_to ) l_idx_to = l_idx;
- if((l_idx_from != -1) && (l_idx_to != -1))
+/* -------------------------------------
+ * p_iteration_by_pesistent_id
+ * -------------------------------------
+ * fetch frame image by persistent id,
+ * assign drawable and calculate iteration between
+ * start_drawable_id
+ * end_drawable_id
+ * o) check if both start_drawable_id and end_drawable_id
+ * are found in the persistent_id_lookup
+ *
+ * o) if both refere to the same image filename and ainfo_type == GAP_AINFO_ANIMIMAGE
+ * then open this image (if not already opened)
+ * and calculate the drawable id according to current step
+ * by iterating layerstack numbers.
+ * o) if both refere to images, that are anim frames
+ * with the same basename and extension
+ * (for example:
+ * anim_000001.xcf
+ * anim_000009.xcf
+ * )
+ * then iterate by framenumber (in the example this will be between 1 and 9)
+ *
+ * o) filename references to videofiles are supported if ainfo_type == GAP_AINFO_MOVIE
+ *
+ * Note that each fetch of a persistent darawable (the fetched_layer_id) creates
+ * a temporary image in the frame fetcher (assotiated with fmacContext->ffetch_user_id)
+ * In this iterator we can not delete those temp. image(s) because they are required for
+ * processing in the corresponding filter plug-in.
+ * Therefore the master filtermacro processing has to do this clean up step after the
+ * filtercall has finished.
+ */
+static gboolean
+p_iteration_by_pesistent_id(GapFmacContext *fmacContext
+ ,gint32 *val, gint32 val_from, gint32 val_to, gint32 total_steps, gdouble current_step)
+{
+ GapFmacRefEntry *fmref_entry_from;
+
+ if(gap_debug)
+ {
+ printf("p_iteration_by_pesistent_id: START *val drawable_id:%d (from:%d to:%d)\n"
+ ,(int)*val
+ ,(int)val_from
+ ,(int)val_to
+ );
+ }
+
+ fmref_entry_from = gap_fmct_get_GapFmacRefEntry_by_persitent_id(fmacContext, val_from);
+ if (fmref_entry_from)
+ {
+ GapFmacRefEntry *fmref_entry_to;
+
+ fmref_entry_to = gap_fmct_get_GapFmacRefEntry_by_persitent_id(fmacContext, val_to);
+ if (fmref_entry_to)
+ {
+ if ((strcmp(fmref_entry_from->filename, fmref_entry_to->filename) == 0)
+ && (fmref_entry_from->track == fmref_entry_to->track)
+ && (fmref_entry_from->ainfo_type == fmref_entry_to->ainfo_type))
+ {
+ gint32 fetched_layer_id;
+
+ fetched_layer_id = -1;
+
+ // TODO: what to do if mtime has changed ? (maybe print warning if this occurs the 1st time ?)
+
+ if (fmref_entry_from->ainfo_type == GAP_AINFO_ANIMIMAGE)
+ {
+ /* iterate stackposition */
+ gint32 stackposition;
+
+ stackposition = fmref_entry_from->stackposition;
+ p_delta_gint32(&stackposition, fmref_entry_from->stackposition, fmref_entry_to->stackposition
+ ,total_steps, current_step);
+
+ fetched_layer_id = gap_frame_fetch_dup_image(fmacContext->ffetch_user_id
+ ,fmref_entry_from->filename /* full filename of the image */
+ ,stackposition /* pick layer by stackposition */
+ ,TRUE /* enable caching */
+ );
+ }
+ else
+ {
+ /* iterate frame_nr */
+ gint32 frame_nr;
+
+ frame_nr = fmref_entry_from->frame_nr;
+ p_delta_gint32(&frame_nr, fmref_entry_from->frame_nr, fmref_entry_to->frame_nr
+ ,total_steps, current_step);
+
+ if (fmref_entry_from->ainfo_type == GAP_AINFO_MOVIE)
{
- /* OK found both index values, iterate the index (proceed to next layer) */
- p_delta_gint(&l_idx, l_idx_from, l_idx_to, total_steps, current_step);
- *val = l_layers_list[l_idx];
- break;
+ fetched_layer_id = gap_frame_fetch_dup_video(fmacContext->ffetch_user_id
+ ,fmref_entry_from->filename /* full filename of a video */
+ ,frame_nr /* frame within the video (starting at 1) */
+ ,fmref_entry_from->track /* videotrack */
+ , NULL /* char *prefered_decoder*/
+ );
}
- }
- g_free (l_layers_list);
+ else
+ {
+ fetched_layer_id = gap_frame_fetch_dup_image(fmacContext->ffetch_user_id
+ ,fmref_entry_from->filename /* full filename of the image */
+ ,-1 /* 0 pick layer on top of stack, -1 merge visible layers */
+ ,TRUE /* enable caching */
+ );
+ }
+
+ }
+
+ *val = fetched_layer_id;
+ if(gap_debug)
+ {
+ printf("p_iteration_by_pesistent_id: SUCCESS drawable_id:%d (from:%d to:%d)\n"
+ ,(int)*val
+ ,(int)val_from
+ ,(int)val_to
+ );
+ }
+ return (TRUE);
+ }
}
-}
+ }
+
+ if(gap_debug)
+ {
+ printf("p_iteration_by_pesistent_id: FAILED *val drawable_id:%d (from:%d to:%d)\n"
+ ,(int)*val
+ ,(int)val_from
+ ,(int)val_to
+ );
+ }
+ return (FALSE);
+} /* end p_iteration_by_pesistent_id */
+
+
static void
p_delta_gintdrawable(gint *val, gint val_from, gint val_to, gint32 total_steps, gdouble current_step)
{
Modified: trunk/gap/gap_filter_pdb.c
==============================================================================
--- trunk/gap/gap_filter_pdb.c (original)
+++ trunk/gap/gap_filter_pdb.c Thu Jul 31 18:05:59 2008
@@ -478,7 +478,7 @@
* and there is no individual Iterator Procedure.
*/
char *
-gap_filt_pdb_get_iterator_proc(char *plugin_name, gint *count)
+gap_filt_pdb_get_iterator_proc(const char *plugin_name, gint *count)
{
char *l_plugin_iterator;
char *canonical_name;
Modified: trunk/gap/gap_filter_pdb.h
==============================================================================
--- trunk/gap/gap_filter_pdb.h (original)
+++ trunk/gap/gap_filter_pdb.h Thu Jul 31 18:05:59 2008
@@ -49,7 +49,7 @@
gint gap_filt_pdb_get_data(char *key);
void gap_filt_pdb_set_data(char *key, gint plugin_data_len);
gint gap_filt_pdb_procedure_available(char *proc_name, GapFiltPdbProcType ptype);
-char * gap_filt_pdb_get_iterator_proc(char *plugin_name, gint *count);
+char * gap_filt_pdb_get_iterator_proc(const char *plugin_name, gint *count);
int gap_filt_pdb_constraint_proc_sel1(gchar *proc_name, gint32 image_id);
int gap_filt_pdb_constraint_proc_sel2(gchar *proc_name, gint32 image_id);
Modified: trunk/gap/gap_fmac_base.c
==============================================================================
--- trunk/gap/gap_fmac_base.c (original)
+++ trunk/gap/gap_fmac_base.c Thu Jul 31 18:05:59 2008
@@ -53,6 +53,8 @@
#include "gap_filter_pdb.h"
#include "gap_fmac_name.h"
#include "gap_fmac_base.h"
+#include "gap_fmac_context.h"
+#include "gap_frame_fetcher.h"
@@ -61,6 +63,7 @@
typedef struct FMacElem {
char *filtername;
gboolean assigned_flag;
+ gboolean varying_flag;
char *buffer_from;
gint32 buffer_from_length;
char *buffer_to;
@@ -239,6 +242,12 @@
* init the assigned_flag with FALSE for all elements that are added to the list.
* Note that the order of elements in the list must match the order in the
* filtermacro file.
+ * Furthermore assign the matching iteratorname (a name of
+ * an iterator plug-in that can handle the filter specific parameter value mix
+ * for the iterable parameter values and/or can do the mapping of persistent drawable id's
+ * in the last values buffer.
+ * the varying_flag is initilized with FALSE.
+ *
* returns root elem of the list or NULL if load failed.
*/
static FMacElem *
@@ -280,6 +289,7 @@
if (fmacLine)
{
FMacElem *fmac_elem;
+ gint l_count;
/* create fmac_elem according to scanned fmac line */
fmac_elem = g_malloc0(sizeof(FMacElem));
@@ -287,9 +297,15 @@
fmac_elem->buffer_from = g_malloc0(fmacLine->paramlength);
fmac_elem->buffer_to = g_malloc0(fmacLine->paramlength);
fmac_elem->buffer_from_length = fmacLine->paramlength;
- fmac_elem->iteratorname = NULL;
fmac_elem->assigned_flag = FALSE;
+ fmac_elem->varying_flag = FALSE;
fmac_elem->next = NULL;
+ /* assign the matching Iterator PluginProcedure
+ * (if there is any)
+ */
+ fmac_elem->iteratorname =
+ gap_filt_pdb_get_iterator_proc(fmac_elem->filtername
+ , &l_count);
memcpy(fmac_elem->buffer_from , fmacLine->paramdata, fmacLine->paramlength);
memcpy(fmac_elem->buffer_to , fmacLine->paramdata, fmacLine->paramlength);
@@ -334,10 +350,11 @@
* read filters from the 2nd filtermacro file and merge
* in the buffer_to values by overwriting already initialized
* values where filtername matches and assigned_flag is not yet set.
- * Furthermore assign the matching iteratorname (a name of
- * an iterator plug-in that can handle the filter specific parameter value mix
- * for the iterable parameter values.
* Note that all non-matching entries are ignored.
+ *
+ * the varying_flag is set to TRUE for those lines that have a matching line
+ * in the 2nd filtermacro file AND have an iterator
+ * (that can do the plug-in specific mix of the parmetervakues)
*/
gboolean
p_merge_fmac_list(FMacElem *fmac_root, const char *filtermacro_file, GimpRunMode run_mode)
@@ -383,17 +400,14 @@
{
if (fmac_elem->buffer_from_length == fmacLine->paramlength)
{
- gint l_count;
/* overwrite param data */
memcpy(fmac_elem->buffer_to, fmacLine->paramdata, fmacLine->paramlength);
fmac_elem->assigned_flag = TRUE;
- /* assign the matching Iterator PluginProcedures
- * (if there is any)
- */
- fmac_elem->iteratorname =
- gap_filt_pdb_get_iterator_proc(fmac_elem->filtername
- , &l_count);
+ if(fmac_elem->iteratorname != NULL)
+ {
+ fmac_elem->varying_flag = TRUE;
+ }
}
else
@@ -496,11 +510,22 @@
if(gap_debug)
{
- printf("p_fmac_execute_single_filter: VARYING APPLY iteratorname:%s\n key_from:%s\n key_to:%s\n"
+ if(fmac_elem->varying_flag == TRUE)
+ {
+ printf("p_fmac_execute_single_filter: VARYING APPLY iteratorname:%s\n key_from:%s\n key_to:%s\n"
,fmac_elem->iteratorname
,l_key_from
,l_key_to
);
+ }
+ else
+ {
+ printf("p_fmac_execute_single_filter: MAPPING APPLY iteratorname:%s\n key_from:%s\n key_to:%s\n"
+ ,fmac_elem->iteratorname
+ ,l_key_from
+ ,l_key_to
+ );
+ }
}
/* the iterator call will set the last values buffer for the corresponding
@@ -535,7 +560,6 @@
gint l_exec_len;
gint l_ii;
- /* make backup of last values buffer (if available) */
l_exec_len = gimp_get_data_size(fmac_elem->filtername);
printf("p_fmac_execute_single_filter: EXEC image:%d, drawable:%d filtername:%s len:%d\n"
@@ -626,6 +650,17 @@
if (fmac_root)
{
FMacElem *fmac_elem;
+ GapFmacContext theFmacContext;
+ GapFmacContext *fmacContext;
+
+ fmacContext = &theFmacContext;
+
+ gap_fmct_setup_GapFmacContext(fmacContext
+ , FALSE /* no recording_mode (e.g. apply mode) */
+ , filtermacro_file1
+ );
+
+
if(filtermacro_file2 != NULL)
{
@@ -638,7 +673,15 @@
, current_step
, total_steps
);
+
+ /* intermediate cleanup of temporary image duplicates that may have been
+ * created while iterating persistent drawable ids (by iterator sub-procedur p_delta_drawable)
+ */
+ gap_frame_fetch_delete_list_of_duplicated_images(fmacContext->ffetch_user_id);
}
+
+ /* disable the sessionwide filtermacro context */
+ gap_fmct_disable_GapFmacContext();
//TODO p_free_fmac_list(fmac_root); /* free the filtermacro processing list */
}
Added: trunk/gap/gap_fmac_context.c
==============================================================================
--- (empty file)
+++ trunk/gap/gap_fmac_context.c Thu Jul 31 18:05:59 2008
@@ -0,0 +1,676 @@
+/* gap_fmac_context.c
+ *
+ *
+ * This module handles the filtermacro context.
+ * The filtermacro context is used for itration of "persistent drawable ids"
+ * for animated (or constant) filter apply.
+ * If gap controlled filterapply is done via a filtermacro
+ * the iteration is done within a filtermacro context.
+ * (e.g. while filtermacro is beeing recorded or is applied)
+ * the handled drawable ids are mapped with the help of a filtermacro reference file
+ * In this case the "persitent_drawable_id" is used to open the referenced
+ * image, frame or videoframe at apply time (this may happen in another gimp
+ * session than the recording of the filtermacro was done).
+ *
+ *
+ * Copyright (C) 2008 Wolfgang Hofer <hof gimp org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib/gstdio.h>
+
+/* GAP includes */
+#include "gap_fmac_context.h"
+#include "gap_frame_fetcher.h"
+#include "gap_file_util.h"
+#include "gap_val_file.h"
+
+
+extern int gap_debug; /* ==0 ... dont print debug infos */
+
+char * p_parse_string(char **scan_ptr);
+static void p_parse_and_add_GapFmacRefEntry(GapFmacContext *fmacContext, char *line_ptr);
+
+
+/* --------------------------------------------
+ * gap_fmct_set_derived_lookup_filename
+ * --------------------------------------------
+ * set persistent_id_lookup_filename = filename.fmref
+ */
+void
+gap_fmct_set_derived_lookup_filename(GapFmacContext *fmacContext, const char *filename)
+{
+ if ((fmacContext) && (filename))
+ {
+ g_snprintf(fmacContext->persistent_id_lookup_filename , sizeof(fmacContext->persistent_id_lookup_filename), "%s%s"
+ ,filename
+ ,GAP_FMREF_FILENAME_EXTENSION
+ );
+ }
+} /* end gap_fmct_set_derived_lookup_filename */
+
+
+/* --------------------------------------------
+ * gap_fmct_setup_GapFmacContext
+ * --------------------------------------------
+ * setup a filtermacro context for recording or playback mode.
+ * the context affects the behaviour of drawable_iteration in the whole gimp_session
+ * until the procedure gap_fmct_disable_GapFmacContext is called.
+ * This procedure registers a new frame fetcher resource user_id if playback (e.g NOT recording_mode)
+ * is used. The drawable_iteration will refere to this ffetch_user_id when fetching
+ * frames via mapped persistent drawable ids.
+ *
+ * The current implementation can NOT handle parallell processing of multiple filtermacros
+ * because there is only ONE context that will be overwritten in case of concurrent calls.
+ */
+void
+gap_fmct_setup_GapFmacContext(GapFmacContext *fmacContext, gboolean recording_mode, const char *filename)
+{
+ gap_fmct_set_derived_lookup_filename(fmacContext, filename);
+ fmacContext->recording_mode = recording_mode;
+ fmacContext->enabled = TRUE;
+ if (recording_mode)
+ {
+ fmacContext->ffetch_user_id = -1;
+ }
+ else
+ {
+ fmacContext->ffetch_user_id = gap_frame_fetch_register_user("gap_fmct_setup_GapFmacContext");
+ }
+ fmacContext->fmref_list = NULL;
+ gimp_set_data(GAP_FMAC_CONTEXT_KEYWORD, fmacContext, sizeof(GapFmacContext));
+} /* end gap_fmct_setup_GapFmacContext */
+
+
+/* --------------------------------------------
+ * gap_fmct_disable_GapFmacContext
+ * --------------------------------------------
+ * disable the gimp session wide global filtermacro context.
+ * (this also unregisters frame fetcher resource usage if
+ * there was a valid context in playback mode at calling time)
+ */
+void
+gap_fmct_disable_GapFmacContext(void)
+{
+ gint sizeFmacContext;
+
+ sizeFmacContext = gimp_get_data_size(GAP_FMAC_CONTEXT_KEYWORD);
+
+ if(sizeFmacContext == sizeof(GapFmacContext))
+ {
+ GapFmacContext *fmacContext;
+ fmacContext = g_malloc0(sizeFmacContext);
+
+ if(fmacContext)
+ {
+ gimp_get_data(GAP_FMAC_CONTEXT_KEYWORD, fmacContext);
+ fmacContext->enabled = FALSE;
+ fmacContext->fmref_list = NULL;
+ if(fmacContext->ffetch_user_id >= 0)
+ {
+ /* unregister (shall drop cached resources of the frame fetcher when last user unregisters) */
+ gap_frame_fetch_unregister_user(fmacContext->ffetch_user_id);
+ }
+ gimp_set_data(GAP_FMAC_CONTEXT_KEYWORD, fmacContext, sizeof(GapFmacContext));
+ g_free(fmacContext);
+ }
+ }
+} /* end gap_fmct_disable_GapFmacContext */
+
+
+/* --------------------------------------------
+ * gap_fmct_free_GapFmacRefList
+ * --------------------------------------------
+ * free all elements of the fmacContext->fmref_list.
+ */
+void
+gap_fmct_free_GapFmacRefList(GapFmacContext *fmacContext)
+{
+ GapFmacRefEntry *fmref_entry;
+ GapFmacRefEntry *fmref_next;
+
+ fmref_entry = fmacContext->fmref_list;
+ while(fmref_entry != NULL)
+ {
+ fmref_next = fmref_entry->next;
+ g_free(fmref_entry);
+ fmref_entry = fmref_next;
+ }
+ fmacContext->fmref_list = NULL;
+
+} /* end gap_fmct_free_GapFmacRefList */
+
+
+
+/* --------------------------
+ * p_parse_string_raw
+ * --------------------------
+ * return a pointer to the start of the next non-white space character
+ * in this line and advance the scan_ptr to the next white space
+ * or to one position after the ':' (that terminates key strings)
+ * NULL is returned if there is no (more) non-white space character
+ * left in the line rest (starting at *scan_ptr).
+ * the scan_ptr is rest to NULL when end of line \n or end of string \0
+ * is reached.
+ */
+char *
+p_parse_string_raw(char **scan_ptr)
+{
+ char *ptr;
+ char *result_ptr;
+
+ result_ptr = NULL;
+ ptr = *scan_ptr;
+
+ /* advance to 1st non blank position */
+ while(ptr)
+ {
+ if ((*ptr == '\0') || (*ptr == '\n'))
+ {
+ /* end of line (or string) reached */
+ *scan_ptr = NULL;
+ return (result_ptr);
+ }
+ if ((*ptr != ' ') && (*ptr != '\t'))
+ {
+ /* first non-white space character found */
+ result_ptr = ptr;
+ break;
+ }
+ ptr++; /* skip white space and continue */
+ }
+
+
+ while(ptr)
+ {
+ ptr++;
+ if ((*ptr == '\0') || (*ptr == '\n'))
+ {
+ *scan_ptr = NULL;
+ return (result_ptr);
+ }
+ if (*result_ptr == '"')
+ {
+ if(*ptr == '"')
+ {
+ ptr++;
+ *scan_ptr = ptr;
+ return (result_ptr);
+ }
+ }
+ else
+ {
+ if ((*ptr == ' ') || (*ptr == '\t'))
+ {
+ *scan_ptr = ptr;
+ return (result_ptr);
+ }
+ if (*ptr == ':')
+ {
+ ptr++;
+ *scan_ptr = ptr;
+ return (result_ptr);
+ }
+ }
+ }
+
+ return (result_ptr);
+} /* end p_parse_string_raw */
+
+/* --------------------------
+ * p_parse_string
+ * --------------------------
+ * return a pointer to the start of the next non-white space character
+ * in this line and advance the scan_ptr to the next white space
+ * or to one position after the ':' (that terminates key strings)
+ * NULL is returned if there is no (more) non-white space character
+ * left in the line rest (starting at *scan_ptr).
+ * the scan_ptr is rest to NULL when end of line \n or end of string \0
+ * is reached.
+ */
+char *
+p_parse_string(char **scan_ptr)
+{
+ char *l_ptr;
+ char *l_result;
+
+ l_result = NULL;
+ l_ptr = p_parse_string_raw(scan_ptr);
+ if(l_ptr != NULL)
+ {
+ l_result = g_strdup(l_ptr);
+ if (*scan_ptr != NULL)
+ {
+ l_result[*scan_ptr - l_ptr] = '\0';
+ }
+ }
+ if(gap_debug)
+ {
+ if(l_result)
+ {
+ printf("p_parse_string:(%s)\n", l_result);
+ }
+ else
+ {
+ printf("p_parse_string:(NULL)\n");
+ }
+ }
+ return (l_result);
+}
+
+/* --------------------------------------------
+ * p_parse_and_add_GapFmacRefEntry
+ * --------------------------------------------
+ * parse one record and add it to
+ * the the fmacContext->fmref_list on success.
+ */
+static void
+p_parse_and_add_GapFmacRefEntry(GapFmacContext *fmacContext, char *line_ptr)
+{
+ char *l_key;
+ char *l_value;
+ char *scan_ptr;
+
+ long id;
+ long ainfo_type;
+ long frame_nr;
+ long stackposition;
+ long track;
+ long mtime;
+ char *filename;
+
+ id = -1;
+ ainfo_type = -1;
+ frame_nr = -1;
+ stackposition = -1;
+ track = -1;
+ mtime = -1;
+ filename = NULL;
+
+ scan_ptr = line_ptr;
+ while (scan_ptr != NULL)
+ {
+ l_key = p_parse_string(&scan_ptr);
+ if (l_key == NULL)
+ {
+ break;
+ }
+ l_value = p_parse_string(&scan_ptr);
+ if (l_value == NULL)
+ {
+ g_free(l_key);
+ break;
+ }
+
+ if (strcmp(l_key, GAP_FMREF_ID) == 0)
+ {
+ id = atol(l_value);
+ }
+ else if (strcmp(l_key, GAP_FMREF_FRAME_NR) == 0)
+ {
+ frame_nr = atol(l_value);
+ }
+ else if (strcmp(l_key, GAP_FMREF_STACK) == 0)
+ {
+ stackposition = atol(l_value);
+ }
+ else if (strcmp(l_key, GAP_FMREF_TRACK) == 0)
+ {
+ track = atol(l_value);
+ }
+ else if (strcmp(l_key, GAP_FMREF_MTIME) == 0)
+ {
+ mtime = atol(l_value);
+ }
+ else if (strcmp(l_key, GAP_FMREF_TYPE) == 0)
+ {
+ ainfo_type = atol(l_value);
+ }
+ else if (strcmp(l_key, GAP_FMREF_FILE) == 0)
+ {
+ int len;
+ char *l_raw_filename;
+
+ l_raw_filename = l_value;
+ if(gap_debug)
+ {
+ printf("RAW filename:%s:\n", l_raw_filename);
+ }
+ if (*l_raw_filename == '"')
+ {
+ l_raw_filename++;
+ }
+ len = strlen(l_raw_filename);
+ if (len > 0)
+ {
+ if (l_raw_filename[len -1] == '"')
+ {
+ l_raw_filename[len -1] = '\0';
+ }
+ }
+ filename = g_strdup(l_raw_filename);
+ }
+ else
+ {
+ printf("WARNING: unkonwn token: %s\n", l_key);
+ }
+
+ g_free(l_key);
+ g_free(l_value);
+ }
+
+ /* now check if required attributes are present */
+ if (id < 0)
+ {
+ printf("ERROR: incomplete record, expected: %s is missing", GAP_FMREF_ID);
+ return;
+ }
+ if (frame_nr < 0)
+ {
+ printf("ERROR: incomplete record, expected: %s is missing", GAP_FMREF_FRAME_NR);
+ return;
+ }
+ if (filename == NULL)
+ {
+ printf("ERROR: incomplete record, expected: %s is missing", GAP_FMREF_FILE);
+ return;
+ }
+ if (ainfo_type < 0)
+ {
+ printf("ERROR: incomplete record, expected: %s is missing", GAP_FMREF_TYPE);
+ return;
+ }
+ if (mtime < 0)
+ {
+ printf("ERROR: incomplete record, expected: %s is missing", GAP_FMREF_MTIME);
+ return;
+ }
+
+ /* create and add the scanned entry to the list */
+ gap_fmct_add_GapFmacRefEntry(ainfo_type
+ , frame_nr
+ , stackposition
+ , track
+ , id
+ , filename
+ , TRUE /* force_id scanned from file (dont generate a new one ) */
+ , fmacContext
+ );
+
+ if (filename != NULL)
+ {
+ g_free(filename);
+ }
+
+} /* end p_parse_and_add_GapFmacRefEntry */
+
+
+/* --------------------------------------------
+ * gap_fmct_load_GapFmacContext
+ * --------------------------------------------
+ */
+void
+gap_fmct_load_GapFmacContext(GapFmacContext *fmacContext)
+{
+ GapValTextFileLines *txf_ptr_root;
+ GapValTextFileLines *txf_ptr;
+ gint32 line_nr;
+
+
+ gap_fmct_free_GapFmacRefList(fmacContext);
+
+ txf_ptr_root = gap_val_load_textfile(fmacContext->persistent_id_lookup_filename);
+ line_nr = 0;
+
+ for(txf_ptr = txf_ptr_root; txf_ptr != NULL; txf_ptr = (GapValTextFileLines *) txf_ptr->next)
+ {
+ gint l_len;
+
+ line_nr++;
+ if(gap_debug)
+ {
+ printf("line_nr: %d\n", (int)line_nr);
+ }
+ gap_file_chop_trailingspace_and_nl(&txf_ptr->line[0]);
+ l_len = strlen(txf_ptr->line);
+
+ if(gap_debug)
+ {
+ printf("line:%s:\n", txf_ptr->line);
+ }
+
+ if (line_nr == 1)
+ {
+ if (strncmp(txf_ptr->line, GAP_FMREF_FILEHEADER, strlen(GAP_FMREF_FILEHEADER)) != 0)
+ {
+ printf("ERROR: file:%s does not start with expected header:%s\n"
+ , fmacContext->persistent_id_lookup_filename
+ , GAP_FMREF_FILEHEADER
+ );
+ break;
+ }
+ }
+ else
+ {
+ if (*txf_ptr->line != '#')
+ {
+ p_parse_and_add_GapFmacRefEntry(fmacContext, txf_ptr->line);
+ }
+ }
+
+ }
+
+ if(txf_ptr_root)
+ {
+ gap_val_free_textfile_lines(txf_ptr_root);
+ }
+
+ if(gap_debug)
+ {
+ gap_fmct_debug_print_GapFmacContext(fmacContext);
+ }
+
+} /* end gap_fmct_load_GapFmacContext */
+
+
+/* --------------------------------------------
+ * gap_fmct_save_GapFmacContext
+ * --------------------------------------------
+ * save the list of filtermacro references (to persistent drawable ids)
+ * in the filename that is specified via persistent_id_lookup_filename
+ * in the filtermacro context.
+ * The file created or completely overwritten.
+ */
+void
+gap_fmct_save_GapFmacContext(GapFmacContext *fmacContext)
+{
+ GapFmacRefEntry *fmref_entry;
+ FILE *fp;
+
+ fp = g_fopen(fmacContext->persistent_id_lookup_filename, "w");
+ if (fp == NULL)
+ {
+ printf("ERROR: could not open write file:%s\n", fmacContext->persistent_id_lookup_filename);
+ return;
+ }
+
+ fprintf(fp, "%s\n", GAP_FMREF_FILEHEADER);
+ fprintf(fp, "# type: %d=IMAGE,%d=ANIMIMAGE,%d=FRAMES,%d=MOVIE\n"
+ , GAP_AINFO_IMAGE, GAP_AINFO_ANIMIMAGE, GAP_AINFO_FRAMES, GAP_AINFO_MOVIE);
+
+ /* write all reference entries in the following format:
+ * id:800000 frameNr:000001 stack:-1 file:"frame_000001.xcf" mtime:123455678
+ */
+ for(fmref_entry = fmacContext->fmref_list; fmref_entry != NULL; fmref_entry = fmref_entry->next)
+ {
+ fprintf(fp, "%s%06d %s%06d %s%02d %s%d %s%011d %s%d %s\"%s\"\n"
+ , GAP_FMREF_ID , fmref_entry->persistent_drawable_id
+ , GAP_FMREF_FRAME_NR , fmref_entry->frame_nr
+ , GAP_FMREF_STACK , fmref_entry->stackposition
+ , GAP_FMREF_TRACK , fmref_entry->track
+ , GAP_FMREF_MTIME , fmref_entry->mtime
+ , GAP_FMREF_TYPE , fmref_entry->ainfo_type
+ , GAP_FMREF_FILE , fmref_entry->filename
+ );
+ }
+
+ fclose(fp);
+
+} /* end gap_fmct_save_GapFmacContext */
+
+/* --------------------------------------------
+ * gap_fmct_debug_print_GapFmacContext
+ * --------------------------------------------
+ * print the current filtermacro context for debug purpose.
+ */
+void
+gap_fmct_debug_print_GapFmacContext(GapFmacContext *fmacContext)
+{
+ GapFmacRefEntry *fmref_entry;
+
+ printf("fmacContext START persistent_id_lookup_filename:%s\n"
+ , fmacContext->persistent_id_lookup_filename
+ );
+
+ printf(" recording_mode:%d enabled:%d ffetch_user_id:%d\n"
+ , fmacContext->recording_mode
+ , fmacContext->enabled
+ , fmacContext->ffetch_user_id
+ );
+
+ for(fmref_entry = fmacContext->fmref_list; fmref_entry != NULL; fmref_entry = fmref_entry->next)
+ {
+ printf("%s%06d %s%06d %s%02d %s%d %s%011d %s%d %s\"%s\"\n"
+ , GAP_FMREF_ID , fmref_entry->persistent_drawable_id
+ , GAP_FMREF_FRAME_NR , fmref_entry->frame_nr
+ , GAP_FMREF_STACK , fmref_entry->stackposition
+ , GAP_FMREF_TRACK , fmref_entry->track
+ , GAP_FMREF_MTIME , fmref_entry->mtime
+ , GAP_FMREF_TYPE , fmref_entry->ainfo_type
+ , GAP_FMREF_FILE , fmref_entry->filename
+ );
+ }
+
+ printf("fmacContext END persistent_id_lookup_filename:%s\n"
+ , fmacContext->persistent_id_lookup_filename
+ );
+
+} /* end gap_fmct_debug_print_GapFmacContext */
+
+
+
+/* --------------------------------------------
+ * gap_fmct_get_GapFmacRefEntry_by_persitent_id
+ * --------------------------------------------
+ */
+GapFmacRefEntry *
+gap_fmct_get_GapFmacRefEntry_by_persitent_id(GapFmacContext *fmacContext, gint32 persistent_drawable_id)
+{
+ GapFmacRefEntry *fmref_entry;
+
+ for(fmref_entry = fmacContext->fmref_list; fmref_entry != NULL; fmref_entry = fmref_entry->next)
+ {
+ if (fmref_entry->persistent_drawable_id == persistent_drawable_id)
+ {
+ return(fmref_entry);
+ }
+ }
+ return (NULL);
+
+} /* end gap_fmct_get_GapFmacRefEntry_by_persitent_id */
+
+/* --------------------------------------------
+ * gap_fmct_add_GapFmacRefEntry
+ * --------------------------------------------
+ */
+gint32
+gap_fmct_add_GapFmacRefEntry(GapLibAinfoType ainfo_type
+ , gint32 frame_nr
+ , gint32 stackposition
+ , gint32 track
+ , gint32 drawable_id
+ , const char *filename
+ , gboolean force_id
+ , GapFmacContext *fmacContext)
+{
+ GapFmacRefEntry *new_fmref_entry;
+ GapFmacRefEntry *fmref_entry;
+ gint32 l_max_persistent_drawable_id;
+
+ if(filename == NULL)
+ {
+ return (drawable_id);
+ }
+ if(!g_file_test(filename, G_FILE_TEST_EXISTS))
+ {
+ return (drawable_id);
+ }
+ if(fmacContext == NULL)
+ {
+ return (drawable_id);
+ }
+
+
+ l_max_persistent_drawable_id = GAP_FMCT_MIN_PERSISTENT_DRAWABLE_ID;
+
+ /* check if entry already present in the list */
+ for(fmref_entry = fmacContext->fmref_list; fmref_entry != NULL; fmref_entry = fmref_entry->next)
+ {
+ if((fmref_entry->ainfo_type == ainfo_type)
+ && (fmref_entry->frame_nr == frame_nr)
+ && (fmref_entry->stackposition == stackposition)
+ && (fmref_entry->track == track)
+ && (strcmp(fmref_entry->filename, filename) == 0))
+ {
+ /* the list already contains an equal entry, nothing left to do.. */
+ return(fmref_entry->persistent_drawable_id);
+ }
+ l_max_persistent_drawable_id = MAX(l_max_persistent_drawable_id, fmref_entry->persistent_drawable_id);
+ }
+
+ /* add the new entry (and assign a unique persistent_drawable_id) */
+ new_fmref_entry = g_new(GapFmacRefEntry, 1);
+
+ if(force_id)
+ {
+ new_fmref_entry->persistent_drawable_id = drawable_id;
+ }
+ else
+ {
+ new_fmref_entry->persistent_drawable_id = l_max_persistent_drawable_id + 1;
+ }
+ new_fmref_entry->ainfo_type = ainfo_type;
+ new_fmref_entry->frame_nr = frame_nr;
+ new_fmref_entry->stackposition = stackposition;
+ new_fmref_entry->track = track;
+ new_fmref_entry->mtime = gap_file_get_mtime(filename);
+ g_snprintf(new_fmref_entry->filename, sizeof(new_fmref_entry->filename), "%s", filename);
+
+
+ new_fmref_entry->next = fmacContext->fmref_list;
+ fmacContext->fmref_list = new_fmref_entry;
+
+ gap_fmct_save_GapFmacContext(fmacContext);
+
+ return(new_fmref_entry->persistent_drawable_id);
+
+} /* end gap_fmct_add_GapFmacRefEntry */
+
Added: trunk/gap/gap_fmac_context.h
==============================================================================
--- (empty file)
+++ trunk/gap/gap_fmac_context.h Thu Jul 31 18:05:59 2008
@@ -0,0 +1,96 @@
+/* gap_fmac_context.h
+ *
+ *
+ * This module handles the filtermacro context.
+ * The filtermacro context is used for itration of "persistent drawable ids"
+ * for animated (or constant) filter apply.
+ * If gap controlled filterapply is done via a filtermacro
+ * the iteration is done within a filtermacro context.
+ * (e.g. while filtermacro is beeing recorded or is applied)
+ * the handled drawable ids are mapped with the help of a filtermacro reference file
+ * In this case the "persitent_drawable_id" is used to open the referenced
+ * image, frame or videoframe at apply time (this may happen in another gimp
+ * session than the recording of the filtermacro was done).
+ *
+ *
+ * Copyright (C) 2008 Wolfgang Hofer <hof gimp org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GAP_FMAC_CONTEXT_H
+#define _GAP_FMAC_CONTEXT_H
+
+#include "libgimp/gimp.h"
+#include "libgimp/gimp.h"
+#include "gap_lib_common_defs.h"
+
+typedef struct GapFmacRefEntry {
+ GapLibAinfoType ainfo_type;
+ gint32 persistent_drawable_id;
+ gint32 frame_nr;
+ gint32 stackposition;
+ gint32 track;
+ gint32 mtime;
+ char filename[1024];
+ struct GapFmacRefEntry *next;
+} GapFmacRefEntry;
+
+
+typedef struct GapFmacContext {
+ gboolean recording_mode;
+ gboolean enabled;
+ gint32 ffetch_user_id;
+ char persistent_id_lookup_filename[1024];
+ GapFmacRefEntry *fmref_list;
+} GapFmacContext;
+
+
+
+#define GAP_FMREF_FILENAME_EXTENSION ".fmref"
+#define GAP_FMREF_FILEHEADER "GAP_FILTERMACRO_PERSITENT_DRAWABLE_ID_LOOKUP_FILE"
+#define GAP_FMREF_ID "id:"
+#define GAP_FMREF_FRAME_NR "frameNr:"
+#define GAP_FMREF_STACK "stack:"
+#define GAP_FMREF_TRACK "track:"
+#define GAP_FMREF_MTIME "mtime:"
+#define GAP_FMREF_TYPE "type:"
+#define GAP_FMREF_FILE "file:"
+
+
+#define GAP_FMAC_CONTEXT_KEYWORD "GAP_FMAC_CONTEXT_KEYWORD"
+#define GAP_FMCT_MIN_PERSISTENT_DRAWABLE_ID 800000
+
+void gap_fmct_set_derived_lookup_filename(GapFmacContext *fmacContext, const char *filename);
+void gap_fmct_setup_GapFmacContext(GapFmacContext *fmacContext, gboolean recording_mode, const char *filename);
+void gap_fmct_disable_GapFmacContext(void);
+void gap_fmct_debug_print_GapFmacContext(GapFmacContext *fmacContext);
+
+void gap_fmct_load_GapFmacContext(GapFmacContext *fmacContext);
+void gap_fmct_save_GapFmacContext(GapFmacContext *fmacContext);
+GapFmacRefEntry * gap_fmct_get_GapFmacRefEntry_by_persitent_id(GapFmacContext *fmacContext
+ , gint32 persistent_drawable_id);
+void gap_fmct_free_GapFmacRefList(GapFmacContext *fmacContext);
+gint32 gap_fmct_add_GapFmacRefEntry(GapLibAinfoType ainfo_type
+ , gint32 frame_nr
+ , gint32 stackposition
+ , gint32 track
+ , gint32 drawable_id
+ , const char *filename
+ , gboolean force_id
+ , GapFmacContext *fmacContext);
+
+#endif
Modified: trunk/gap/gap_fmac_main.c
==============================================================================
--- trunk/gap/gap_fmac_main.c (original)
+++ trunk/gap/gap_fmac_main.c Thu Jul 31 18:05:59 2008
@@ -58,6 +58,7 @@
#include "gap_fmac_base.h"
#include "gap_dbbrowser_utils.h"
#include "gap_lastvaldesc.h"
+#include "gap_fmac_context.h"
/* revision history:
* gimp 1.3.26b; 2004/02/29 hof: bugfix NONINTERACTIVE call did crash
@@ -129,6 +130,7 @@
static gboolean p_chk_filtermacro_file(const char *filtermacro_file);
static void p_print_and_free_msg(char *msg, GimpRunMode run_mode);
static gchar * p_get_gap_filter_data_string(const char *plugin_name);
+static gchar * p_get_mapped_gap_filter_data_string(const char *plugin_name, const char *filtermacro_file);
static gint p_fmac_add_filter_to_file(const char *filtermacro_file, const char *plugin_name);
static gint p_fmac_add_filter(const char *filtermacro_file, gint32 image_id);
static int p_fmac_pdb_constraint_proc(gchar *proc_name, gint32 image_id);
@@ -398,7 +400,10 @@
plugin_data = NULL;
- if(gap_debug) printf("p_get_gap_lastfilter: plugin_name:%s:\n", plugin_name);
+ if(gap_debug)
+ {
+ printf("p_get_gap_filter_data_string: plugin_name:%s:\n", plugin_name);
+ }
plugin_data_len = gimp_get_data_size (plugin_name);
if (plugin_data_len > 0)
@@ -426,7 +431,10 @@
l_str = g_strdup_printf("%s\n", l_str_tmp);
g_free(l_str_tmp);
- if (gap_debug) printf("p_get_gap_lastfilter: %s", l_str);
+ if (gap_debug)
+ {
+ printf("p_get_gap_filter_data_string: %s", l_str);
+ }
data_string = l_str;
g_free(plugin_data);
@@ -438,6 +446,121 @@
} /* end p_get_gap_filter_data_string */
+/* -----------------------------------
+ * p_get_mapped_gap_filter_data_string
+ * -----------------------------------
+ * return a textstring with the plugin_name
+ * and its values as textstring
+ * that has format like this:
+ * "plug_in_name" len hexbyte1 hexbyte2 .......\n
+ * example:
+ * "plug_in_sharpen" 4 0a 00 00 00
+ *
+ *
+ * In case the plugin has at least one iterable drawable id within its last values parameters
+ * those values are mapped to persistent_drawable_id's with the help of a special
+ * iterator call with a filtermacro context and a corresponding .fmref file in recording mode.
+ *
+ * return data_string or NULL pointer if nothing was found.
+ * the returned data_string should be g_free'd by the caller (if it was not NULL)
+ *
+ */
+static gchar *
+p_get_mapped_gap_filter_data_string(const char *plugin_name, const char *filtermacro_file)
+{
+ static char l_key_from[512];
+ static char l_key_to[512];
+ gint plugin_data_len;
+ guchar *plugin_data_bck;
+ gchar *data_string;
+ const char *l_iteratorname;
+ gint l_count;
+
+
+ data_string = NULL;
+
+ if(plugin_name == NULL)
+ {
+ return (NULL);
+ }
+ plugin_data_len = gimp_get_data_size (plugin_name);
+
+ if(gap_debug)
+ {
+ printf("p_get_mapped_gap_filter_data_string: plugin_name:%s: plugin_data_len:%d\n"
+ , plugin_name
+ , plugin_data_len
+ );
+ }
+
+ /* assign the matching Iterator PluginProcedures (if there is any) */
+ l_iteratorname = gap_filt_pdb_get_iterator_proc(plugin_name, &l_count);
+
+ if ((plugin_data_len > 0) && (l_iteratorname != NULL))
+ {
+ GapFmacContext theFmacContext;
+ GapFmacContext *fmacContext;
+
+ fmacContext = &theFmacContext;
+
+ if(gap_debug)
+ {
+ printf("p_get_mapped_gap_filter_data_string: l_iteratorname:%s:\n"
+ , l_iteratorname
+ );
+ }
+ gap_fmct_setup_GapFmacContext(fmacContext
+ , TRUE /* recording_mode */
+ , filtermacro_file
+ );
+
+
+ /* retrieve the data (to backup original data) */
+ plugin_data_bck = g_malloc0(plugin_data_len);
+ gimp_get_data(plugin_name, plugin_data_bck);
+
+
+ /* Set FROM and TO buffers.
+ * (in recording mode we use all the same data as the backup of the original buffer)
+ * those buffers are not relevant in recording mode, but are required
+ * for the iterator call interface.
+ */
+ g_snprintf(l_key_from, sizeof(l_key_from), "%s%s", plugin_name, GAP_ITER_TO_SUFFIX);
+ gimp_set_data(l_key_from, plugin_data_bck, plugin_data_len);
+
+ g_snprintf(l_key_to, sizeof(l_key_to), "%s%s", plugin_name, GAP_ITER_FROM_SUFFIX);
+ gimp_set_data(l_key_to, plugin_data_bck, plugin_data_len);
+
+ /* call the iterator in recording mode
+ * this triggers the mapping of drawable ids in the persistent .fmref file.
+ * (but only in case the called plugin has at least one an iterable drawable_id in its last_values paramters,
+ * otherwise the las values buffer shall not change by the iteratorcall,
+ * due to same settings for from and to values)
+ */
+ gap_filter_iterator_call(l_iteratorname
+ , 1 /* total_steps */
+ , 1.0 /* current_step */
+ , plugin_name
+ , plugin_data_len
+ );
+
+ data_string = p_get_gap_filter_data_string(plugin_name);
+
+ /* restore original data from backup buffer */
+ gimp_set_data(plugin_name, plugin_data_bck, plugin_data_len);
+
+ g_free(plugin_data_bck);
+
+ /* disable the sessionwide filtermacro context */
+ gap_fmct_disable_GapFmacContext();
+
+ }
+
+ return (data_string);
+
+} /* end p_get_mapped_gap_filter_data_string */
+
+
/* -------------------------
* p_fmac_add_filter_to_file
* -------------------------
@@ -472,12 +595,12 @@
{
char *data_string;
char *canonical_plugin_name;
-
+
canonical_plugin_name = gimp_canonicalize_identifier(plugin_name);
- data_string = p_get_gap_filter_data_string(canonical_plugin_name);
+ data_string = p_get_mapped_gap_filter_data_string(canonical_plugin_name, filtermacro_file);
g_free(canonical_plugin_name);
-
+
if(data_string)
{
fprintf(fp, "%s", data_string);
Added: trunk/gap/gap_frame_fetcher.c
==============================================================================
--- (empty file)
+++ trunk/gap/gap_frame_fetcher.c Thu Jul 31 18:05:59 2008
@@ -0,0 +1,872 @@
+/* gap_frame_fetcher.c
+ *
+ *
+ * The FrameFetcher provides access to frames both from imagefiles and videofiles.
+ *
+ * It holds a global image cache of temporary gimp images intended for
+ * read only access in various gimp-gap render processings.
+ *
+ * There are methods to get the temporary image
+ * or to get a duplicate that has only one layer at imagesize.
+ * (merged or picked via desired stackposition)
+ *
+ * For videofiles it holds a cache of open videofile handles.
+ * (note that caching of videoframes is already available in the videohandle)
+ *
+ * The current implementation of the frame fetcher is NOT multithred save !
+ * (the procedures may drop cached images that are still in use by a concurrent thread
+ * further the cache lists can be messe up if they are modified by concurrent threads
+ * at the same time.
+ *
+ * Currently there is no support to keep track of cached images during the full length
+ * of a gimp session. This simple version of the frame fetcher is limited
+ * to one main program (such as the storyboard or the filtermacro plug-in)
+ * and loses its information on exit of the main program.
+ * (If there are still registrated users at exit time, the cached images are still
+ * loaded in the gimp session)
+ * TODO: a more sophisticated version of the frame fetcher may keep its information
+ * using the gimp_det_data feature or mark the cached images with a tattoo.
+ *
+
+ *
+ *
+ * Copyright (C) 2008 Wolfgang Hofer <hof gimp org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * 2008.08.20 hof - created (moved image cache stuff from gap_story_render_processing modules to this new module)
+ * - new feature: caching of videohandles.
+ *
+ */
+
+#include <config.h>
+
+/* SYTEM (UNIX) includes */
+#include <stdlib.h>
+//#include <sys/types.h>
+//#include <sys/stat.h>
+//#include <math.h>
+//#include <errno.h>
+
+//#include <dirent.h>
+
+
+#include <glib/gstdio.h>
+
+
+
+/* GIMP includes */
+#include "gtk/gtk.h"
+#include "gap-intl.h"
+#include "libgimp/gimp.h"
+
+
+#include "gap_libgimpgap.h"
+#include "gap_lib_common_defs.h"
+#include "gap_file_util.h"
+#include "gap_vid_api.h"
+#include "gap_layer_copy.h"
+//#include "gap_fmac_name.h"
+
+#include "gap_frame_fetcher.h"
+
+#define GAP_FFETCH_MAX_IMG_CACHE_ELEMENTS 12
+#define GAP_FFETCH_MAX_GVC_CACHE_ELEMENTS 6
+#define GAP_FFETCH_GVA_FRAMES_TO_KEEP_CACHED 36
+
+
+
+typedef struct GapFFetchResourceUserElem
+{
+ gint32 ffetch_user_id;
+ void *next;
+} GapFFetchResourceUserElem;
+
+
+
+typedef struct GapFFetchDuplicatedImagesElem
+{
+ gint32 ffetch_user_id;
+ gint32 image_id;
+ void *next;
+} GapFFetchDuplicatedImagesElem;
+
+
+/* -------- types for the image cache ------- */
+
+typedef struct GapFFetchImageCacheElem
+{
+ gint32 image_id;
+ char *filename;
+ void *next;
+} GapFFetchImageCacheElem;
+
+typedef struct GapFFetchImageCache
+{
+ GapFFetchImageCacheElem *ic_list;
+ gint32 max_img_cache; /* number of images to hold in the cache */
+} GapFFetchImageCache;
+
+
+/* -------- types for the video handle cache ------- */
+
+typedef struct GapFFetchGvahandCacheElem
+{
+ t_GVA_Handle *gvahand;
+ gint32 mtime;
+ gint32 seltrack;
+ char *filename;
+ void *next;
+} GapFFetchGvahandCacheElem;
+
+
+typedef struct GapFFetchGvahandCache
+{
+ GapFFetchGvahandCacheElem *gvc_list;
+ gint32 max_vid_cache; /* number of videohandles to hold in the cache */
+} GapFFetchGvahandCache;
+
+
+
+extern int gap_debug; /* 1 == print debug infos , 0 dont print debug infos */
+
+/*************************************************************
+ * STATIC varaibles *
+ *************************************************************
+ */
+
+static GapFFetchDuplicatedImagesElem *global_duplicated_images = NULL;
+
+static GapFFetchImageCache *global_imcache = NULL;
+
+static GapFFetchGvahandCache *global_gvcache = NULL;
+
+static GapFFetchResourceUserElem *global_rsource_users = NULL;
+
+/*************************************************************
+ * FRAME FETCHER procedures *
+ *************************************************************
+ */
+static gint32 p_load_cache_image(const char* filename, gboolean addToCache);
+static void p_drop_image_cache_elem1(GapFFetchImageCache *imcache);
+static void p_drop_image_cache(void);
+#ifdef GAP_ENABLE_VIDEOAPI_SUPPORT
+static void p_drop_gvahand_cache_elem1(GapFFetchGvahandCache *gvcache);
+static void p_drop_vidhandle_cache(void);
+
+static t_GVA_Handle* p_ffetch_get_open_gvahand(const char* filename, gint32 seltrack
+ , const char *preferred_decoder);
+#endif
+
+static void p_add_image_to_list_of_duplicated_images(gint32 image_id, gint32 ffetch_user_id);
+
+
+/* ----------------------------------------------------
+ * p_find_img_cache_by_image_id
+ * ----------------------------------------------------
+ */
+static GapFFetchImageCacheElem *
+p_find_img_cache_by_image_id(gint32 image_id)
+{
+ GapFFetchImageCacheElem *ic_ptr;
+
+ if((global_imcache == NULL) || (image_id < 0))
+ {
+ return (NULL);
+ }
+
+ for(ic_ptr = global_imcache->ic_list; ic_ptr != NULL; ic_ptr = (GapFFetchImageCacheElem *)ic_ptr->next)
+ {
+ if(ic_ptr->image_id == image_id)
+ {
+ /* image found in cache */
+ return(ic_ptr);
+ }
+ }
+
+ return (NULL);
+} /* end p_find_img_cache_by_image_id */
+
+
+/* ----------------------------------------------------
+ * p_load_cache_image
+ * ----------------------------------------------------
+ */
+static gint32
+p_load_cache_image(const char* filename, gboolean addToCache)
+{
+ gint32 l_idx;
+ gint32 l_image_id;
+ GapFFetchImageCacheElem *ic_ptr;
+ GapFFetchImageCacheElem *ic_last;
+ GapFFetchImageCacheElem *ic_new;
+ GapFFetchImageCache *imcache;
+ char *l_filename;
+
+ if(filename == NULL)
+ {
+ printf("p_load_cache_image: ** ERROR cant load filename == NULL!\n");
+ return -1;
+ }
+
+ if(global_imcache == NULL)
+ {
+ /* init the global_image cache */
+ global_imcache = g_malloc0(sizeof(GapFFetchImageCache));
+ global_imcache->ic_list = NULL;
+ global_imcache->max_img_cache = GAP_FFETCH_MAX_IMG_CACHE_ELEMENTS;
+ }
+
+ imcache = global_imcache;
+ ic_last = imcache->ic_list;
+
+ l_idx = 0;
+ for(ic_ptr = imcache->ic_list; ic_ptr != NULL; ic_ptr = (GapFFetchImageCacheElem *)ic_ptr->next)
+ {
+ l_idx++;
+ if(strcmp(filename, ic_ptr->filename) == 0)
+ {
+ if(gap_debug)
+ {
+ printf("FrameFetcher: p_load_cache_image CACHE-HIT :%s (image_id:%d)\n"
+ , ic_ptr->filename, (int)ic_ptr->image_id);
+ }
+ /* image found in cache, can skip load */
+ return(ic_ptr->image_id);
+ }
+ ic_last = ic_ptr;
+ }
+
+ l_filename = g_strdup(filename);
+ l_image_id = gap_lib_load_image(l_filename);
+ if(gap_debug)
+ {
+ printf("FrameFetcher: loaded imafe from disk:%s (image_id:%d)\n"
+ , l_filename, (int)l_image_id);
+ }
+
+ if((l_image_id >= 0) && (addToCache == TRUE))
+ {
+ ic_new = g_malloc0(sizeof(GapFFetchImageCacheElem));
+ ic_new->filename = l_filename;
+ ic_new->image_id = l_image_id;
+
+ if(imcache->ic_list == NULL)
+ {
+ imcache->ic_list = ic_new; /* 1.st elem starts the list */
+ }
+ else
+ {
+ ic_last->next = (GapFFetchImageCacheElem *)ic_new; /* add new elem at end of the cache list */
+ }
+
+ if(l_idx > imcache->max_img_cache)
+ {
+ /* chache list has more elements than desired,
+ * drop the 1.st (oldest) entry in the chache list
+ */
+ p_drop_image_cache_elem1(imcache);
+ }
+ }
+ else
+ {
+ g_free(l_filename);
+ }
+ return(l_image_id);
+} /* end p_load_cache_image */
+
+
+/* ----------------------------------------------------
+ * p_drop_image_cache_elem1
+ * ----------------------------------------------------
+ */
+static void
+p_drop_image_cache_elem1(GapFFetchImageCache *imcache)
+{
+ GapFFetchImageCacheElem *ic_ptr;
+
+ if(imcache)
+ {
+ ic_ptr = imcache->ic_list;
+ if(ic_ptr)
+ {
+ if(gap_debug)
+ {
+ printf("p_drop_image_cache_elem1 delete:%s (image_id:%d)\n"
+ , ic_ptr->filename, (int)ic_ptr->image_id);
+ }
+ gap_image_delete_immediate(ic_ptr->image_id);
+ g_free(ic_ptr->filename);
+ imcache->ic_list = (GapFFetchImageCacheElem *)ic_ptr->next;
+ g_free(ic_ptr);
+ }
+ }
+} /* end p_drop_image_cache_elem1 */
+
+
+
+/* ----------------------------------------------------
+ * p_drop_image_cache
+ * ----------------------------------------------------
+ * drop the image cache.
+ */
+static void
+p_drop_image_cache(void)
+{
+ GapFFetchImageCache *imcache;
+
+ if(gap_debug)
+ {
+ printf("p_drop_image_cache START\n");
+ }
+ imcache = global_imcache;
+ if(imcache)
+ {
+ while(imcache->ic_list)
+ {
+ p_drop_image_cache_elem1(imcache);
+ }
+ }
+ global_imcache = NULL;
+
+ if(gap_debug)
+ {
+ printf("p_drop_image_cache END\n");
+ }
+
+} /* end p_drop_image_cache */
+
+
+
+#ifdef GAP_ENABLE_VIDEOAPI_SUPPORT
+
+
+/* ----------------------------------------------------
+ * p_drop_gvahand_cache_elem1
+ * ----------------------------------------------------
+ */
+static void
+p_drop_gvahand_cache_elem1(GapFFetchGvahandCache *gvcache)
+{
+ GapFFetchGvahandCacheElem *gvc_ptr;
+
+ if(gvcache)
+ {
+ gvc_ptr = gvcache->gvc_list;
+ if(gvc_ptr)
+ {
+ if(gap_debug)
+ {
+ printf("p_drop_gvahand_cache_elem1 delete:%s (gvahand:%d seltrack:%d mtime:%ld)\n"
+ , gvc_ptr->filename, (int)gvc_ptr->gvahand
+ , (int)gvc_ptr->seltrack, (long)gvc_ptr->mtime);
+ }
+ GVA_close(gvc_ptr->gvahand);
+ g_free(gvc_ptr->filename);
+ gvcache->gvc_list = (GapFFetchGvahandCacheElem *)gvc_ptr->next;
+ g_free(gvc_ptr);
+ }
+ }
+} /* end p_drop_gvahand_cache_elem1 */
+
+
+/* ----------------------------------------------------
+ * p_drop_vidhandle_cache
+ * ----------------------------------------------------
+ */
+static void
+p_drop_vidhandle_cache(void)
+{
+ GapFFetchGvahandCache *gvc_cache;
+
+ if(gap_debug)
+ {
+ printf("p_drop_vidhandle_cache START\n");
+ }
+ gvc_cache = global_gvcache;
+ if(gvc_cache)
+ {
+ while(gvc_cache->gvc_list)
+ {
+ p_drop_gvahand_cache_elem1(gvc_cache);
+ }
+ }
+ global_gvcache = NULL;
+
+ if(gap_debug)
+ {
+ printf("p_drop_vidhandle_cache END\n");
+ }
+
+
+} /* end p_drop_vidhandle_cache */
+
+
+
+
+/* ----------------------------------------------------
+ * p_ffetch_get_open_gvahand
+ * ----------------------------------------------------
+ * get videohandle from the cache of already open handles.
+ * opens a new handle if there is no cache hit.
+ * if too many handles are alredy open, the oldest one is closed.
+ * note that the cached handles must not be used outside the
+ * frame fetcher module. Therefore the closing old handles
+ * can be done.
+ */
+static t_GVA_Handle*
+p_ffetch_get_open_gvahand(const char* filename, gint32 seltrack, const char *preferred_decoder)
+{
+ gint32 l_idx;
+ t_GVA_Handle *l_gvahand;
+ GapFFetchGvahandCacheElem *gvc_ptr;
+ GapFFetchGvahandCacheElem *gvc_last;
+ GapFFetchGvahandCacheElem *gvc_new;
+ GapFFetchGvahandCache *gvcache;
+
+ if(filename == NULL)
+ {
+ printf("p_ffetch_get_open_gvahand: ** ERROR cant load video filename == NULL!\n");
+ return (NULL);
+ }
+
+ if(global_gvcache == NULL)
+ {
+ /* init the global_image cache */
+ global_gvcache = g_malloc0(sizeof(GapFFetchGvahandCache));
+ global_gvcache->gvc_list = NULL;
+ global_gvcache->max_vid_cache = GAP_FFETCH_MAX_GVC_CACHE_ELEMENTS;
+ }
+
+ gvcache = global_gvcache;
+ gvc_last = gvcache->gvc_list;
+
+ l_idx = 0;
+ for(gvc_ptr = gvcache->gvc_list; gvc_ptr != NULL; gvc_ptr = (GapFFetchGvahandCacheElem *)gvc_ptr->next)
+ {
+ l_idx++;
+ if((strcmp(filename, gvc_ptr->filename) == 0) && (seltrack == gvc_ptr->seltrack))
+ {
+ /* videohandle found in cache, can skip opening a new handle */
+ return(gvc_ptr->gvahand);
+ }
+ gvc_last = gvc_ptr;
+ }
+
+ if(preferred_decoder)
+ {
+ l_gvahand = GVA_open_read_pref(filename
+ , seltrack
+ , 1 /* aud_track */
+ , preferred_decoder
+ , FALSE /* use MMX if available (disable_mmx == FALSE) */
+ );
+ }
+ else
+ {
+ l_gvahand = GVA_open_read(filename
+ ,seltrack
+ ,1 /* aud_track */
+ );
+ }
+
+ if(l_gvahand)
+ {
+ GVA_set_fcache_size(l_gvahand, GAP_FFETCH_GVA_FRAMES_TO_KEEP_CACHED);
+
+ gvc_new = g_malloc0(sizeof(GapFFetchGvahandCacheElem));
+ gvc_new->filename = g_strdup(filename);
+ gvc_new->seltrack = seltrack;
+ gvc_new->mtime = GVA_file_get_mtime(filename);
+ gvc_new->gvahand = l_gvahand;
+
+ if(gvcache->gvc_list == NULL)
+ {
+ gvcache->gvc_list = gvc_new; /* 1.st elem starts the list */
+ }
+ else
+ {
+ gvc_last->next = (GapFFetchGvahandCacheElem *)gvc_new; /* add new elem at end of the cache list */
+ }
+
+ if(l_idx > gvcache->max_vid_cache)
+ {
+ /* chache list has more elements than desired,
+ * drop the 1.st (oldest) entry in the chache list
+ * (this closes the droped handle)
+ */
+ p_drop_gvahand_cache_elem1(gvcache);
+ }
+ }
+ return(l_gvahand);
+} /* end p_ffetch_get_open_gvahand */
+
+#endif
+
+/* -----------------------------------------
+ * p_add_image_to_list_of_duplicated_images
+ * -----------------------------------------
+ * add specified image to the list of duplicated images.
+ * this list contains temporary images of both fetched video frames
+ * and merged duplicates of the cached original images.
+ */
+static void
+p_add_image_to_list_of_duplicated_images(gint32 image_id, gint32 ffetch_user_id)
+{
+ GapFFetchDuplicatedImagesElem *dupElem;
+
+ dupElem = g_new(GapFFetchDuplicatedImagesElem, 1);
+ dupElem->next = global_duplicated_images;
+ dupElem->image_id = image_id;
+ dupElem->ffetch_user_id = ffetch_user_id;
+ global_duplicated_images = dupElem;
+} /* end p_add_image_to_list_of_duplicated_images */
+
+
+/* -------------------------------------------------
+ * gap_frame_fetch_delete_list_of_duplicated_images
+ * -------------------------------------------------
+ * deletes all duplicate imageas that wre created by the specified ffetch_user_id
+ * (if ffetch_user_id -1 is specified delte all duplicated images)
+ */
+void
+gap_frame_fetch_delete_list_of_duplicated_images(gint32 ffetch_user_id)
+{
+ GapFFetchDuplicatedImagesElem *dupElem;
+ GapFFetchDuplicatedImagesElem *nextDupElem;
+
+ dupElem = global_duplicated_images;
+ while(dupElem)
+ {
+ nextDupElem = dupElem->next;
+
+ if (((ffetch_user_id == dupElem->ffetch_user_id) || (ffetch_user_id < 0))
+ && (dupElem->image_id >= 0))
+ {
+ gap_image_delete_immediate(dupElem->image_id);
+ dupElem->image_id = -1; /* set image invalid */
+ }
+
+ if (ffetch_user_id < 0)
+ {
+ g_free(dupElem);
+ }
+
+ dupElem = nextDupElem;
+ }
+ if (ffetch_user_id < 0)
+ {
+ global_duplicated_images = NULL;
+ }
+} /* end gap_frame_fetch_delete_list_of_duplicated_images */
+
+
+
+
+
+
+/* ----------------------------
+ * gap_frame_fetch_orig_image
+ * ----------------------------
+ * returns image_id of the original cached image.
+ */
+gint32
+gap_frame_fetch_orig_image(gint32 ffetch_user_id
+ ,const char *filename /* full filename of the image */
+ ,gboolean addToCache /* enable caching */
+ )
+{
+ return (p_load_cache_image(filename, addToCache));
+} /* end gap_frame_fetch_orig_image */
+
+
+
+/* ----------------------------
+ * gap_frame_fetch_dup_image
+ * ----------------------------
+ * returns merged or selected layer_id
+ * (that is the only visible layer in temporary created scratch image)
+ * the caller is resonsible to delete the scratch image when processing is done.
+ * this can be done by calling gap_frame_fetch_delete_list_of_duplicated_images()
+ */
+gint32
+gap_frame_fetch_dup_image(gint32 ffetch_user_id
+ ,const char *filename /* full filename of the image (already contains framenr) */
+ ,gint32 stackpos /* 0 pick layer on top of stack, -1 merge visible layers */
+ ,gboolean addToCache /* enable caching */
+ )
+{
+ gint32 resulting_layer;
+ gint32 image_id;
+ gint32 dup_image_id;
+
+ resulting_layer = -1;
+ image_id = p_load_cache_image(filename, addToCache);
+ if (image_id < 0)
+ {
+ return(-1);
+ }
+
+ if (stackpos < 0)
+ {
+ dup_image_id = gimp_image_duplicate(image_id);
+ resulting_layer = gap_image_merge_visible_layers(dup_image_id, GIMP_CLIP_TO_IMAGE);
+ }
+ else
+ {
+ gint l_nlayers;
+ gint32 *l_layers_list;
+
+
+ l_layers_list = gimp_image_get_layers(image_id, &l_nlayers);
+ if(l_layers_list != NULL)
+ {
+ if (stackpos < l_nlayers)
+ {
+ gint32 src_layer_id;
+
+ src_layer_id = l_layers_list[stackpos];
+ dup_image_id = gimp_image_new (gimp_image_width(image_id)
+ , gimp_image_height(image_id)
+ , gimp_image_base_type(image_id)
+ );
+ resulting_layer = gap_layer_copy_to_image (dup_image_id, src_layer_id);
+ }
+
+ g_free (l_layers_list);
+ }
+ }
+
+ p_add_image_to_list_of_duplicated_images(dup_image_id, ffetch_user_id);
+
+
+ if (addToCache != TRUE)
+ {
+ GapFFetchImageCacheElem *ic_elem;
+
+ ic_elem = p_find_img_cache_by_image_id(image_id);
+
+ if (ic_elem == NULL)
+ {
+ /* the original image is not cached
+ * (delete it because the caller gets the preprocessed duplicate)
+ */
+ gap_image_delete_immediate(image_id);
+ }
+ }
+
+ return(resulting_layer);
+
+} /* end gap_frame_fetch_dup_image */
+
+
+
+/* ----------------------------
+ * gap_frame_fetch_dup_video
+ * ----------------------------
+ * returns the fetched video frame as gimp layer_id.
+ * the returned layer id is (the only layer) in a temporary image.
+ * note the caller is responsible to delete that temporary image after processing is done.
+ * this can be done by calling gap_frame_fetch_delete_list_of_duplicated_images()
+ */
+gint32
+gap_frame_fetch_dup_video(gint32 ffetch_user_id
+ ,const char *filename /* full filename of a video */
+ ,gint32 framenr /* frame within the video (starting at 1) */
+ ,gint32 seltrack /* videotrack */
+ ,const char *preferred_decoder)
+{
+ gint32 l_layer_id = -1;
+#ifdef GAP_ENABLE_VIDEOAPI_SUPPORT
+ t_GVA_Handle *gvahand;
+ t_GVA_RetCode l_fcr;
+
+ gvahand = p_ffetch_get_open_gvahand(filename, seltrack, preferred_decoder);
+ if (gvahand == NULL)
+ {
+ return(-1);
+ }
+
+ /* attempt to get frame from the handles internal cache */
+ l_fcr = GVA_frame_to_gimp_layer(gvahand
+ , TRUE /* delete_mode */
+ , framenr /* framenumber */
+ , 0 /* deinterlace */
+ , 0.0 /* threshold */
+ );
+
+ if (l_fcr != GVA_RET_OK)
+ {
+ /* if no success, we try explicite read that frame */
+ if(gvahand->current_seek_nr != framenr)
+ {
+ if(((gvahand->current_seek_nr + GAP_FFETCH_GVA_FRAMES_TO_KEEP_CACHED) > framenr)
+ && (gvahand->current_seek_nr < framenr ) )
+ {
+ /* near forward seek is performed by dummyreads to fill up the
+ * handles internal framecache
+ */
+ while(gvahand->current_seek_nr < framenr)
+ {
+ GVA_get_next_frame(gvahand);
+ }
+ }
+ else
+ {
+ GVA_seek_frame(gvahand, (gdouble)framenr, GVA_UPOS_FRAMES);
+ }
+ }
+
+ if(GVA_get_next_frame(gvahand) == GVA_RET_OK)
+ {
+ GVA_frame_to_gimp_layer(gvahand
+ , TRUE /* delete_mode */
+ , framenr /* framenumber */
+ , 0 /* deinterlace */
+ , 0.0 /* threshold */
+ );
+ }
+ }
+
+ /* return the newly created layer from the temporary image in the gvahand stucture.
+ */
+ l_layer_id = gvahand->layer_id;
+
+ p_add_image_to_list_of_duplicated_images(gvahand->image_id, ffetch_user_id);
+ gvahand->image_id = -1;
+ gvahand->layer_id = -1;
+
+#endif
+ return (l_layer_id);
+
+} /* end gap_frame_fetch_dup_video */
+
+
+/* -------------------------------------------------
+ * gap_frame_fetch_drop_resources
+ * -------------------------------------------------
+ * drop all cached resources and all working copies (in the list of duplicated images).
+ * (regardless if there are still resource users registrated)
+ */
+void
+gap_frame_fetch_drop_resources()
+{
+ gap_frame_fetch_delete_list_of_duplicated_images(-1);
+
+ p_drop_image_cache();
+ p_drop_vidhandle_cache();
+} /* end gap_frame_fetch_drop_resources */
+
+
+/* -------------------------------------------------
+ * gap_frame_fetch_register_user
+ * -------------------------------------------------
+ * register for using the frame fetcher resource.
+ * returns a unique resource user id.
+ */
+gint32
+gap_frame_fetch_register_user(const char *caller_name)
+{
+ gint32 max_ffetch_user_id;
+ GapFFetchResourceUserElem *usr_ptr;
+ GapFFetchResourceUserElem *new_usr_ptr;
+
+ max_ffetch_user_id = 0;
+ new_usr_ptr = NULL;
+
+ for(usr_ptr = global_rsource_users; usr_ptr != NULL; usr_ptr = (GapFFetchResourceUserElem *)usr_ptr->next)
+ {
+ printf("usr_ptr->ffetch_user_id: %d usr_ptr:%d\n", usr_ptr->ffetch_user_id, usr_ptr);
+
+ if (usr_ptr->ffetch_user_id >= 0)
+ {
+ max_ffetch_user_id = MAX(max_ffetch_user_id, usr_ptr->ffetch_user_id);
+ }
+ else
+ {
+ new_usr_ptr = usr_ptr; /* reuse inactive element */
+ }
+ }
+
+ max_ffetch_user_id++;
+ if (new_usr_ptr == NULL)
+ {
+ new_usr_ptr = g_new(GapFFetchResourceUserElem, 1);
+ new_usr_ptr->next = global_rsource_users;
+ global_rsource_users = new_usr_ptr;
+ }
+ new_usr_ptr->ffetch_user_id = max_ffetch_user_id;
+
+ if(gap_debug)
+ {
+ printf("gap_frame_fetch_register_user: REGISTRATED ffetch_user_id:%d caller_name:%s new_usr_ptr:%d\n"
+ , new_usr_ptr->ffetch_user_id
+ , caller_name
+ , new_usr_ptr
+ );
+ }
+ return (max_ffetch_user_id);
+} /* end gap_frame_fetch_register_user*/
+
+
+/* -------------------------------------------------
+ * gap_frame_fetch_unregister_user
+ * -------------------------------------------------
+ * unregister the specified resource user id.
+ + (if there are still registered resource users
+ * cached images and videohandles are kept.
+ * until the last resource user calls this procedure.
+ * if there are no more registered users all
+ * cached resources and duplicates are dropped)
+ */
+void
+gap_frame_fetch_unregister_user(gint32 ffetch_user_id)
+{
+ gint32 count_active_users;
+ GapFFetchResourceUserElem *usr_ptr;
+
+ if(gap_debug)
+ {
+ printf("gap_frame_fetch_unregister_user: UNREGISTER ffetch_user_id:%d\n"
+ , ffetch_user_id
+ );
+ }
+
+ count_active_users = 0;
+ for(usr_ptr = global_rsource_users; usr_ptr != NULL; usr_ptr = (GapFFetchResourceUserElem *)usr_ptr->next)
+ {
+ if (ffetch_user_id == usr_ptr->ffetch_user_id)
+ {
+ usr_ptr->ffetch_user_id = -1;
+ }
+ else if (usr_ptr->ffetch_user_id >= 0)
+ {
+ count_active_users++;
+ }
+ }
+
+ if(count_active_users == 0)
+ {
+ if(gap_debug)
+ {
+ printf("gap_frame_fetch_unregister_user: no more resource users, DROP cached resources\n");
+ }
+ gap_frame_fetch_drop_resources();
+ }
+
+} /* end gap_frame_fetch_unregister_user */
Added: trunk/gap/gap_frame_fetcher.h
==============================================================================
--- (empty file)
+++ trunk/gap/gap_frame_fetcher.h Thu Jul 31 18:05:59 2008
@@ -0,0 +1,137 @@
+/* gap_frame_fetcher.h
+ *
+ *
+ * The FrameFetcher provides access to frames both from imagefiles and videofiles.
+ *
+ * It holds a global image cache of temporary gimp images intended for
+ * read only access in various gimp-gap render processings.
+ *
+ * There are methods to get the temporary image
+ * or to get a duplicate that has only one layer at imagesize.
+ * (merged or picked via desired stackposition)
+ *
+ * For videofiles it holds a cache of open videofile handles.
+ * (note that caching of videoframes is already available in the videohandle)
+ *
+ *
+ * Copyright (C) 2008 Wolfgang Hofer <hof gimp org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GAP_FRAME_FETCHER_H
+#define _GAP_FRAME_FETCHER_H
+
+#include "libgimp/gimp.h"
+#include "libgimp/gimp.h"
+#ifdef GAP_ENABLE_VIDEOAPI_SUPPORT
+#include "gap_vid_api.h"
+#else
+#ifndef GAP_STUBTYPE_GVA_HANDLE
+typedef gpointer t_GVA_Handle;
+#define GAP_STUBTYPE_GVA_HANDLE
+#endif
+#endif
+
+/* -------------------------------------------------
+ * gap_frame_fetch_register_user
+ * -------------------------------------------------
+ * register for using the frame fetcher resource.
+ * returns a unique resource user id.
+ */
+gint32
+gap_frame_fetch_register_user(const char *caller_name);
+
+/* -------------------------------------------------
+ * gap_frame_fetch_unregister_user
+ * -------------------------------------------------
+ * unregister the specified resource user id.
+ + (if there are still registered resource users
+ * cached images and videohandles are kept.
+ * until the last resource user calls this procedure.
+ * if there are no more registered users all
+ * cached resources and duplicates are dropped)
+ */
+void
+gap_frame_fetch_unregister_user(gint32 user_id);
+
+/* -------------------------------------------------
+ * gap_frame_fetch_drop_resources
+ * -------------------------------------------------
+ * drop all cached resources
+ * (regardless if there are still resource users registrated)
+ */
+void
+gap_frame_fetch_drop_resources();
+
+/* -------------------------------------------------
+ * gap_frame_fetch_delete_list_of_duplicated_images
+ * -------------------------------------------------
+ * deletes all duplicate imageas that wre created by the specified ffetch_user_id
+ * (if ffetch_user_id -1 is specified delte all duplicated images)
+ */
+void
+gap_frame_fetch_delete_list_of_duplicated_images(gint32 ffetch_user_id);
+
+
+/* ----------------------------
+ * gap_frame_fetch_orig_image
+ * ----------------------------
+ * returns image_id of the original cached image.
+ * RESTRICTION: the Caller must NOT not modify that image and shall not open a display for it!
+ */
+gint32
+gap_frame_fetch_orig_image(gint32 ffetch_user_id
+ ,const char *filename /* full filename of the image */
+ ,gboolean addToCache /* enable caching */
+ );
+
+
+/* ----------------------------
+ * gap_frame_fetch_dup_image
+ * ----------------------------
+ * returns merged or selected layer_id
+ * (that is the only visible layer in temporary created scratch image)
+ * the caller is resonsible to delete the scratch image when processing is done.
+ * this can be done by calling gap_frame_fetch_delete_list_of_duplicated_images()
+ */
+gint32
+gap_frame_fetch_dup_image(gint32 ffetch_user_id
+ ,const char *filename /* full filename of the image (already contains framenr) */
+ ,gint32 stackpos /* 0 pick layer on top of stack, -1 merge visible layers */
+ ,gboolean addToCache /* enable caching */
+ );
+
+
+/* ----------------------------
+ * gap_frame_fetch_dup_video
+ * ----------------------------
+ * returns the fetched video frame as gimp layer_id.
+ * the returned layer id is (the only layer) in a temporary image.
+ * note the caller is responsible to delete that temporary image after processing is done.
+ * this can be done by calling gap_frame_fetch_delete_list_of_duplicated_images()
+ */
+gint32
+gap_frame_fetch_dup_video(gint32 ffetch_user_id
+ ,const char *filename /* full filename of a video */
+ ,gint32 framenr /* frame within the video (starting at 1) */
+ ,gint32 seltrack /* videotrack */
+ ,const char *preferred_decoder
+ );
+
+
+
+#endif
Modified: trunk/gap/gap_player_dialog.c
==============================================================================
--- trunk/gap/gap_player_dialog.c (original)
+++ trunk/gap/gap_player_dialog.c Thu Jul 31 18:05:59 2008
@@ -111,6 +111,7 @@
#include "gap_audio_extract.h"
#include "gap_audio_extract.h"
#include "gap_file_util.h"
+#include "gap_drawable_vref_parasite.h"
#include "gap-intl.h"
@@ -1211,6 +1212,40 @@
/* ------------------------------
+ * p_conditional_attach_dvref
+ * ------------------------------
+ * check if there is a valid current videoreference.
+ * if yes attach the reference as (temporary) videoreferenc parasite
+ * to the specified drawable_id
+ * (that is typically the layer in the mtrace image)
+ */
+static void
+p_conditional_attach_dvref(GapPlayerMainGlobalParams *gpp
+ ,gint32 drawable_id)
+{
+ if(gap_debug)
+ {
+ printf("MTRACE: mtrace_mode:%d (GAP_PLAYER_MTRACE_IMG_SIZE == %d) dvref\n"
+ ,(int)gpp->mtrace_mode
+ ,(int)GAP_PLAYER_MTRACE_IMG_SIZE
+ );
+ gap_dvref_debug_print_GapDrawableVideoRef(gpp->dvref_ptr);
+ }
+
+ if((gpp->mtrace_mode == GAP_PLAYER_MTRACE_IMG_SIZE)
+ && (gpp->dvref_ptr != NULL))
+ {
+ if(gpp->dvref_ptr->videofile != NULL)
+ {
+ if (gpp->dvref_ptr->videofile == gpp->gva_videofile)
+ {
+ gap_dvref_assign_videoref_parasites(gpp->dvref_ptr, drawable_id);
+ }
+ }
+ }
+} /* end p_conditional_attach_dvref */
+
+/* ------------------------------
* p_mtrace_image
* ------------------------------
* add image as one composite layer
@@ -1230,6 +1265,15 @@
gint32 dst_layer_id;
gint l_src_offset_x, l_src_offset_y; /* layeroffsets as they were in src_image */
+ if(gap_debug)
+ {
+ printf("MTRACE:p_mtrace_image START mtrace_mode:%d (GAP_PLAYER_MTRACE_IMG_SIZE == %d)\n"
+ ,(int)gpp->mtrace_mode
+ ,(int)GAP_PLAYER_MTRACE_IMG_SIZE
+ );
+ gap_dvref_debug_print_GapDrawableVideoRef(gpp->dvref_ptr);
+ }
+
if(gpp->mtrace_mode != GAP_PLAYER_MTRACE_OFF)
{
width = MAX(gimp_image_width(image_id), 1);
@@ -1262,6 +1306,8 @@
l_src_offset_y = (gint32)(((gdouble)mtrace_height / (gdouble)height) * (gdouble)l_src_offset_y);
}
gimp_layer_set_offsets(dst_layer_id, l_src_offset_x, l_src_offset_y);
+ p_conditional_attach_dvref(gpp, dst_layer_id);
+
{
gchar *l_name;
@@ -1330,6 +1376,8 @@
, 0 /* offset_y */
);
+ p_conditional_attach_dvref(gpp, dst_layer_id);
+
{
gchar *l_name;
@@ -2821,6 +2869,26 @@
g_free(th_data);
th_data = NULL;
}
+ else if (gpp->dvref_ptr != NULL)
+ {
+ /* refresh current videofile reference
+ * Note: the dvref_ptr->videofile gets no COPY but only a rference to the current videofilename
+ * this pointer can be reset to NULL any time (at p_display_frame)
+ * but MUST NOT free up the refered name.
+ */
+ gpp->dvref_ptr->videofile = gpp->gva_videofile;
+ gpp->dvref_ptr->para.framenr = framenumber;
+ gpp->dvref_ptr->para.seltrack = seltrack;
+ g_snprintf(&gpp->dvref_ptr->para.preferred_decoder[0], sizeof(gpp->dvref_ptr->para.preferred_decoder), "%s"
+ , preferred_decoder
+ );
+ if(gap_debug)
+ {
+ printf("p_fetch_videoframe: dvref\n");
+ gap_dvref_debug_print_GapDrawableVideoRef(gpp->dvref_ptr);
+ }
+
+ }
}
else
{
@@ -3650,6 +3718,11 @@
framenr_is_the_active_image = FALSE;
l_composite_image_id = -1;
+ if(gpp->dvref_ptr != NULL)
+ {
+ gpp->dvref_ptr->videofile = NULL;
+ }
+
if(gpp->stb_ptr)
{
l_flip_request = GAP_STB_FLIP_NONE;
@@ -4632,7 +4705,10 @@
GdkEventButton *bevent,
GapPlayerMainGlobalParams *gpp)
{
- /*if(gap_debug) printf("on_vid_preview_button_press_event: START\n"); */
+ if(gap_debug)
+ {
+ printf("on_vid_preview_button_press_event: START\n");
+ }
if(gpp->mtrace_mode == GAP_PLAYER_MTRACE_OFF)
{
@@ -8334,6 +8410,9 @@
gpp->old_resize_width = 0;
gpp->old_resize_height = 0;
+ gpp->dvref_ptr = g_new(GapDrawableVideoRef, 1);
+ gpp->dvref_ptr->videofile = NULL;
+
p_create_player_window(gpp);
p_set_frame_with_name_label(gpp);
Modified: trunk/gap/gap_player_main.c
==============================================================================
--- trunk/gap/gap_player_main.c (original)
+++ trunk/gap/gap_player_main.c Thu Jul 31 18:05:59 2008
@@ -222,6 +222,7 @@
, NULL /* GtkWidget *progress_bar_audio */
, NULL /* GtkWidget *audio_enable_checkbutton */
+, NULL /* GapDrawableVideoRef *dvref_ptr */
};
Modified: trunk/gap/gap_player_main.h
==============================================================================
--- trunk/gap/gap_player_main.h (original)
+++ trunk/gap/gap_player_main.h Thu Jul 31 18:05:59 2008
@@ -40,6 +40,7 @@
#include "gap_story_file.h"
#include "gap_player_cache.h"
#include "gap_story_render_types.h"
+#include "gap_drawable_vref_parasite.h"
#ifdef GAP_ENABLE_VIDEOAPI_SUPPORT
#include "gap_vid_api.h"
@@ -255,6 +256,7 @@
GtkWidget *progress_bar_audio;
GtkWidget *audio_enable_checkbutton;
+ GapDrawableVideoRef *dvref_ptr;
} GapPlayerMainGlobalParams;
Modified: trunk/gap/gap_story_dialog.c
==============================================================================
--- trunk/gap/gap_story_dialog.c (original)
+++ trunk/gap/gap_story_dialog.c Thu Jul 31 18:05:59 2008
@@ -65,6 +65,7 @@
#include "gap_story_vthumb.h"
#include "gap_story_section_properties.h"
#include "gap_file_util.h"
+#include "gap_frame_fetcher.h"
#include "images/gap-stock-pixbufs.h"
@@ -8450,8 +8451,19 @@
/* init player window */
p_player_img_mode_cb(NULL, sgpp);
- gtk_main ();
- gdk_flush ();
+ {
+ gint32 ffetch_user_id;
+
+ /* register for frame fetcher resources (image cache)
+ */
+ ffetch_user_id = gap_frame_fetch_register_user("gap_storyboard_dialog");
+
+ gtk_main ();
+ gdk_flush ();
+
+ /* unregister (shall drop cached resources of the frame fetcher) */
+ gap_frame_fetch_unregister_user(ffetch_user_id);
+ }
} /* end gap_storyboard_dialog */
Modified: trunk/gap/gap_story_file.c
==============================================================================
--- trunk/gap/gap_story_file.c (original)
+++ trunk/gap/gap_story_file.c Thu Jul 31 18:05:59 2008
@@ -4913,7 +4913,7 @@
fprintf(fp, "%s %s:\"%s\" %s:%d %s:%d\n"
, GAP_STBKEY_EDIT_SETTINGS
, l_parnam_tab.parname[1]
- , (int)section_name
+ , section_name
, l_parnam_tab.parname[2]
, (int)l_track
, l_parnam_tab.parname[3]
Modified: trunk/gap/gap_story_render_processor.c
==============================================================================
--- trunk/gap/gap_story_render_processor.c (original)
+++ trunk/gap/gap_story_render_processor.c Thu Jul 31 18:05:59 2008
@@ -111,8 +111,6 @@
static void p_init_stb_error(GapStoryRenderErrors *sterr);
static void p_free_stb_error(GapStoryRenderErrors *sterr);
static void p_set_stb_error(GapStoryRenderErrors *sterr, char *errtext);
-static void p_drop_image_cache_elem1(GapStoryRenderImageCache *imcache);
-static gint32 p_load_cache_image( char* filename);
static void p_find_min_max_vid_tracknumbers(GapStoryRenderFrameRangeElem *frn_list
, gint32 *lowest_tracknr
, gint32 *highest_tracknr
@@ -835,124 +833,6 @@
} /* end gap_story_render_set_stb_warning */
-/* ----------------------------------------------------
- * p_drop_image_cache_elem1
- * ----------------------------------------------------
- */
-static void
-p_drop_image_cache_elem1(GapStoryRenderImageCache *imcache)
-{
- GapStoryRenderImageCacheElem *ic_ptr;
-
- if(imcache)
- {
- ic_ptr = imcache->ic_list;
- if(ic_ptr)
- {
- if(gap_debug) printf("p_drop_image_cache_elem1 delete:%s (image_id:%d)\n", ic_ptr->filename, (int)ic_ptr->image_id);
- gap_image_delete_immediate(ic_ptr->image_id);
- g_free(ic_ptr->filename);
- imcache->ic_list = (GapStoryRenderImageCacheElem *)ic_ptr->next;
- g_free(ic_ptr);
- }
- }
-} /* end p_drop_image_cache_elem1 */
-
-
-/* ----------------------------------------------------
- * gap_story_render_drop_image_cache
- * ----------------------------------------------------
- */
-void
-gap_story_render_drop_image_cache(void)
-{
- GapStoryRenderImageCache *imcache;
-
- if(gap_debug) printf("gap_story_render_drop_image_cache START\n");
- imcache = global_imcache;
- if(imcache)
- {
- while(imcache->ic_list)
- {
- p_drop_image_cache_elem1(imcache);
- }
- }
- if(gap_debug) printf("gap_story_render_drop_image_cache END\n");
-
-} /* end gap_story_render_drop_image_cache */
-
-
-/* ----------------------------------------------------
- * p_load_cache_image
- * ----------------------------------------------------
- */
-static gint32
-p_load_cache_image( char* filename)
-{
- gint32 l_idx;
- gint32 l_image_id;
- GapStoryRenderImageCacheElem *ic_ptr;
- GapStoryRenderImageCacheElem *ic_last;
- GapStoryRenderImageCacheElem *ic_new;
- GapStoryRenderImageCache *imcache;
-
- if(filename == NULL)
- {
- printf("p_load_cache_image: ** ERROR cant load filename == NULL!\n");
- return -1;
- }
-
- if(global_imcache == NULL)
- {
- /* init the global_image cache */
- global_imcache = g_malloc0(sizeof(GapStoryRenderImageCache));
- global_imcache->ic_list = NULL;
- global_imcache->max_img_cache = MAX_IMG_CACHE_ELEMENTS;
- }
-
- imcache = global_imcache;
- ic_last = imcache->ic_list;
-
- l_idx = 0;
- for(ic_ptr = imcache->ic_list; ic_ptr != NULL; ic_ptr = (GapStoryRenderImageCacheElem *)ic_ptr->next)
- {
- l_idx++;
- if(strcmp(filename, ic_ptr->filename) == 0)
- {
- /* image found in cache, can skip load */
- return(ic_ptr->image_id);
- }
- ic_last = ic_ptr;
- }
-
- l_image_id = gap_lib_load_image(filename);
- if(l_image_id >= 0)
- {
- ic_new = g_malloc0(sizeof(GapStoryRenderImageCacheElem));
- ic_new->filename = g_strdup(filename);
- ic_new->image_id = l_image_id;
-
- if(imcache->ic_list == NULL)
- {
- imcache->ic_list = ic_new; /* 1.st elem starts the list */
- }
- else
- {
- ic_last->next = (GapStoryRenderImageCacheElem *)ic_new; /* add new elem at end of the cache list */
- }
-
- if(l_idx > imcache->max_img_cache)
- {
- /* chache list has more elements than desired,
- * drop the 1.st (oldest) entry in the chache list
- */
- p_drop_image_cache_elem1(imcache);
- }
- }
- return(l_image_id);
-} /* end p_load_cache_image */
-
-
/* ----------------------------------------------------
@@ -3167,6 +3047,8 @@
p_free_stb_error(vidhand->sterr);
p_free_mask_definitions(vidhand);
+ /* unregister frame fetcher resource usage (e.g. the image cache) */
+ gap_frame_fetch_unregister_user(vidhand->ffetch_user_id);
vidhand->section_list = NULL;
vidhand->frn_list = NULL;
vidhand->sterr = NULL;
@@ -3506,6 +3388,9 @@
vidhand->status_msg_len = 0;
}
+ /* registrate as user of the frame fetcher resources (e.g. the image cache) */
+ vidhand->ffetch_user_id = gap_frame_fetch_register_user("gap_story_render_processor.p_open_video_handle_private");
+
vidhand->frn_list = NULL;
vidhand->preferred_decoder = NULL;
vidhand->do_gimp_progress = do_gimp_progress;
@@ -4762,7 +4647,13 @@
{
gint32 l_orig_image_id;
- l_orig_image_id = p_load_cache_image(l_framename);
+ l_orig_image_id = gap_frame_fetch_orig_image(vidhand->ffetch_user_id
+ , l_framename /* full filename of the image */
+ , TRUE /* enable caching */
+ );
+
+
+
gimp_selection_none(l_orig_image_id);
if(l_frn_type == GAP_FRN_IMAGE)
{
Modified: trunk/gap/gap_story_render_types.h
==============================================================================
--- trunk/gap/gap_story_render_types.h (original)
+++ trunk/gap/gap_story_render_types.h Thu Jul 31 18:05:59 2008
@@ -319,6 +319,8 @@
struct GapStoryRenderMaskDefElem *maskdef_elem; /* list of mask definitions */
gboolean is_mask_handle;
+ gint32 ffetch_user_id;
+
} GapStoryRenderVidHandle; /* used for storyboard processing */
Modified: trunk/gap/gap_story_vthumb.c
==============================================================================
--- trunk/gap/gap_story_vthumb.c (original)
+++ trunk/gap/gap_story_vthumb.c Thu Jul 31 18:05:59 2008
@@ -332,7 +332,7 @@
if((l_have_valid_vindex == FALSE)
&& (vindex_permission))
{
- //if(gap_debug)
+ if(gap_debug)
{
printf("STORY: DEBUG: create vidindex start\n");
}
@@ -344,7 +344,7 @@
sgpp->gvahand->create_vindex = TRUE;
GVA_count_frames(sgpp->gvahand);
- //if(gap_debug)
+ if(gap_debug)
{
printf("STORY: DEBUG: create vidindex done\n");
}
Modified: trunk/libgapvidutil/gap_gve_story.h
==============================================================================
--- trunk/libgapvidutil/gap_gve_story.h (original)
+++ trunk/libgapvidutil/gap_gve_story.h Thu Jul 31 18:05:59 2008
@@ -45,6 +45,7 @@
#include "gap_vid_api.h"
#include "gap_story_file.h"
#include "gap_story_render_processor.h"
+#include "gap_frame_fetcher.h"
/* --------------------------*/
@@ -73,7 +74,7 @@
#define gap_gve_story_debug_print_framerange_list gap_story_render_debug_print_framerange_list
#define gap_gve_story_debug_print_audiorange_list gap_story_render_debug_print_audiorange_list
-#define gap_gve_story_drop_image_cache gap_story_render_drop_image_cache
+#define gap_gve_story_drop_image_cache gap_frame_fetch_drop_resources
#define gap_gve_story_remove_tmp_audiofiles gap_story_render_remove_tmp_audiofiles
#define gap_gve_story_drop_audio_cache gap_story_render_drop_audio_cache
#define gap_gve_story_fetch_composite_image gap_story_render_fetch_composite_image
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]