gimp-gap-2.6.0+dfsg.orig/0000755000175000017500000000000011212031413014744 5ustar thibautthibautgimp-gap-2.6.0+dfsg.orig/config.h.in0000644000175000017500000000530211212030533016771 0ustar thibautthibaut/* config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 to enable compile and link with libavformat */ #undef ENABLE_GVA_LIBAVFORMAT /* Define to 1 to enable compile and link with libmpeg3 */ #undef ENABLE_GVA_LIBMPEG3 /* Define to 1 to enable compile and link with libxvidcore */ #undef ENABLE_LIBXVIDCORE /* always defined to indicate that i18n is enabled */ #undef ENABLE_NLS /* Define to 1 to enable audio support */ #undef GAP_ENABLE_AUDIO_SUPPORT /* Define to 1 to enable videoapi support */ #undef GAP_ENABLE_VIDEOAPI_SUPPORT /* gimp-gap major release number */ #undef GAP_MAJOR_VERSION /* gimp-gap micro release number */ #undef GAP_MICRO_VERSION /* gimp-gap minor release number */ #undef GAP_MINOR_VERSION /* use Gdk for Pixbuf rendering in gap preview widget */ #undef GAP_PVIEW_USE_GDK_PIXBUF_RENDERING /* gimp-gap version string for registrating gap plug-ins */ #undef GAP_VERSION_WITH_DATE /* The gettext translation domain. */ #undef GETTEXT_PACKAGE /* Define to 1 if you have the `bind_textdomain_codeset' function. */ #undef HAVE_BIND_TEXTDOMAIN_CODESET /* Define to 1 if you have the `dcgettext' function. */ #undef HAVE_DCGETTEXT /* Define if the GNU gettext() function is already present or preinstalled. */ #undef HAVE_GETTEXT /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define if your file defines LC_MESSAGES. */ #undef HAVE_LC_MESSAGES /* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION gimp-gap-2.6.0+dfsg.orig/vid_enc_rawframes/0000755000175000017500000000000011212031413020422 5ustar thibautthibautgimp-gap-2.6.0+dfsg.orig/vid_enc_rawframes/Makefile.am0000644000175000017500000000245411212030253022464 0ustar thibautthibaut## Process this file with automake to produce Makefile.in libexecdir = $(GIMP_PLUGIN_DIR)/plug-ins scriptdatadir = $(GIMP_DATA_DIR)/scripts if GAP_VIDEOAPI_SUPPORT GAPVIDEOAPI = -L$(top_builddir)/libgapvidapi -lgapvidapi $(GAPVIDEOAPI_EXTLIBS) INC_GAPVIDEOAPI = -I$(top_srcdir)/libgapvidapi $(GAPVIDEOAPI_EXTINCS) endif LIBGAPBASE = $(top_builddir)/libgapbase/libgapbase.a INC_LIBGAPBASE = -I$(top_srcdir)/libgapbase LIBGAPSTORY = -L$(top_builddir)/gap -lgapstory INC_LIBGAPSTORY = -I$(top_srcdir)/gap LIBGAPVIDUTIL = -L$(top_builddir)/libgapvidutil -lgapvidutil INC_LIBGAPVIDUTIL = -I$(top_srcdir)/libgapvidutil libexec_PROGRAMS = gap_vid_enc_rawframes gap_vid_enc_rawframes_SOURCES = \ gap_enc_rawframes_main.c AM_CPPFLAGS = \ -DGAPLIBDIR=\""$(GAPLIBDIR)"\" \ -DLOCALEDIR=\""$(LOCALEDIR)"\" INCLUDES = \ -I$(top_srcdir) \ -I$(top_srcdir)/libwavplayclient \ $(INC_LIBGAPBASE) \ $(INC_GAPVIDEOAPI) \ $(INC_LIBGAPSTORY) \ $(INC_LIBGAPVIDUTIL) \ $(GIMP_CFLAGS) \ -I$(includedir) LDADD = $(GIMP_LIBS) # note: sequence of libs matters because LIBGAPVIDUTIL uses both LIBGAPSTORY and GAPVIDEOAPI # (if those libs appear before LIBGAPVIDUTIL the linker can not resolve those references. gap_vid_enc_rawframes_LDADD = $(LIBGAPVIDUTIL) $(LIBGAPSTORY) $(GAPVIDEOAPI) $(LIBGAPBASE) $(GIMP_LIBS) gimp-gap-2.6.0+dfsg.orig/vid_enc_rawframes/Makefile.in0000644000175000017500000004031511212030534022475 0ustar thibautthibaut# Makefile.in generated by automake 1.10.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = gap_vid_enc_rawframes$(EXEEXT) subdir = vid_enc_rawframes DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" libexecPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(libexec_PROGRAMS) am_gap_vid_enc_rawframes_OBJECTS = gap_enc_rawframes_main.$(OBJEXT) gap_vid_enc_rawframes_OBJECTS = $(am_gap_vid_enc_rawframes_OBJECTS) am__DEPENDENCIES_1 = @GAP_VIDEOAPI_SUPPORT_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) gap_vid_enc_rawframes_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(gap_vid_enc_rawframes_SOURCES) DIST_SOURCES = $(gap_vid_enc_rawframes_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BUILD_FFMPEG_LIBS = @BUILD_FFMPEG_LIBS@ BUILD_LIBMPEG3_LIB = @BUILD_LIBMPEG3_LIB@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXGMAKE = @EXGMAKE@ FFMPEG_DIR = @FFMPEG_DIR@ FFMPEG_LIBAVCODEC_A = @FFMPEG_LIBAVCODEC_A@ FFMPEG_LIBAVFORMAT_A = @FFMPEG_LIBAVFORMAT_A@ FFMPEG_LIBAVUTIL_A = @FFMPEG_LIBAVUTIL_A@ GAPLIBDIR = @GAPLIBDIR@ GAPVIDEOAPI_EXTINCS = @GAPVIDEOAPI_EXTINCS@ GAPVIDEOAPI_EXTLIBS = @GAPVIDEOAPI_EXTLIBS@ GAP_MAJOR_VERSION = @GAP_MAJOR_VERSION@ GAP_MICRO_VERSION = @GAP_MICRO_VERSION@ GAP_MINOR_VERSION = @GAP_MINOR_VERSION@ GAP_PTHREAD_LIB = @GAP_PTHREAD_LIB@ GAP_VERSION = @GAP_VERSION@ GAP_VERSION_WITH_DATE = @GAP_VERSION_WITH_DATE@ GAP_VINCS_FFMPEG = @GAP_VINCS_FFMPEG@ GAP_VINCS_MPEG3 = @GAP_VINCS_MPEG3@ GAP_VINCS_XVIDCORE = @GAP_VINCS_XVIDCORE@ GAP_VLIBS_FFMPEG = @GAP_VLIBS_FFMPEG@ GAP_VLIBS_MPEG3 = @GAP_VLIBS_MPEG3@ GAP_VLIBS_XVIDCORE = @GAP_VLIBS_XVIDCORE@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GIMP_CFLAGS = @GIMP_CFLAGS@ GIMP_DATA_DIR = @GIMP_DATA_DIR@ GIMP_LIBS = @GIMP_LIBS@ GIMP_PLUGIN_DIR = @GIMP_PLUGIN_DIR@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMAKE_AVAILABLE = @GMAKE_AVAILABLE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_NASM_ASSEMBLER = @HAVE_NASM_ASSEMBLER@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ INTLTOOL_MERGE = @INTLTOOL_MERGE@ INTLTOOL_PERL = @INTLTOOL_PERL@ INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBPREF = @LIBPREF@ LIBS = @LIBS@ LIBSUF = @LIBSUF@ LMPEG3_A = @LMPEG3_A@ LMPEG3_DIR = @LMPEG3_DIR@ LOCALEDIR = @LOCALEDIR@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ MSGMERGE = @MSGMERGE@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATHSEP = @PATHSEP@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WAVPLAY_SERVER = @WAVPLAY_SERVER@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = $(GIMP_PLUGIN_DIR)/plug-ins localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ scriptdatadir = $(GIMP_DATA_DIR)/scripts @GAP_VIDEOAPI_SUPPORT_TRUE@GAPVIDEOAPI = -L$(top_builddir)/libgapvidapi -lgapvidapi $(GAPVIDEOAPI_EXTLIBS) @GAP_VIDEOAPI_SUPPORT_TRUE@INC_GAPVIDEOAPI = -I$(top_srcdir)/libgapvidapi $(GAPVIDEOAPI_EXTINCS) LIBGAPBASE = $(top_builddir)/libgapbase/libgapbase.a INC_LIBGAPBASE = -I$(top_srcdir)/libgapbase LIBGAPSTORY = -L$(top_builddir)/gap -lgapstory INC_LIBGAPSTORY = -I$(top_srcdir)/gap LIBGAPVIDUTIL = -L$(top_builddir)/libgapvidutil -lgapvidutil INC_LIBGAPVIDUTIL = -I$(top_srcdir)/libgapvidutil gap_vid_enc_rawframes_SOURCES = \ gap_enc_rawframes_main.c AM_CPPFLAGS = \ -DGAPLIBDIR=\""$(GAPLIBDIR)"\" \ -DLOCALEDIR=\""$(LOCALEDIR)"\" INCLUDES = \ -I$(top_srcdir) \ -I$(top_srcdir)/libwavplayclient \ $(INC_LIBGAPBASE) \ $(INC_GAPVIDEOAPI) \ $(INC_LIBGAPSTORY) \ $(INC_LIBGAPVIDUTIL) \ $(GIMP_CFLAGS) \ -I$(includedir) LDADD = $(GIMP_LIBS) # note: sequence of libs matters because LIBGAPVIDUTIL uses both LIBGAPSTORY and GAPVIDEOAPI # (if those libs appear before LIBGAPVIDUTIL the linker can not resolve those references. gap_vid_enc_rawframes_LDADD = $(LIBGAPVIDUTIL) $(LIBGAPSTORY) $(GAPVIDEOAPI) $(LIBGAPBASE) $(GIMP_LIBS) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu vid_enc_rawframes/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu vid_enc_rawframes/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(libexecdir)" || $(MKDIR_P) "$(DESTDIR)$(libexecdir)" @list='$(libexec_PROGRAMS)'; for p in $$list; do \ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ if test -f $$p \ ; then \ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ echo " $(INSTALL_PROGRAM_ENV) $(libexecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(libexecdir)/$$f'"; \ $(INSTALL_PROGRAM_ENV) $(libexecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(libexecdir)/$$f" || exit 1; \ else :; fi; \ done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; for p in $$list; do \ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ echo " rm -f '$(DESTDIR)$(libexecdir)/$$f'"; \ rm -f "$(DESTDIR)$(libexecdir)/$$f"; \ done clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) gap_vid_enc_rawframes$(EXEEXT): $(gap_vid_enc_rawframes_OBJECTS) $(gap_vid_enc_rawframes_DEPENDENCIES) @rm -f gap_vid_enc_rawframes$(EXEEXT) $(LINK) $(gap_vid_enc_rawframes_OBJECTS) $(gap_vid_enc_rawframes_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_enc_rawframes_main.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-info: install-info-am install-man: install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libexecPROGRAMS ctags distclean distclean-compile \ distclean-generic distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libexecPROGRAMS install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-libexecPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gimp-gap-2.6.0+dfsg.orig/vid_enc_rawframes/gap_enc_rawframes_main.c0000644000175000017500000007613211212030253025247 0ustar thibautthibaut/* gap_enc_rawframes_main.c * by hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This is the MAIN Module for a rawframes video extract encoder * This encoder writes the videoframes 1:1 as single files to disc * instead of encoding to one videofile. It is mainly intended for * extracting I Frames 1:1 from MPEG or AVI as JPEG files * where the decoding and reencoding process is skipped where possible * This results in fast and lossless extract of keyframes frames. * (example: AVI files recoded by the OLYMPUS SP560UZ digitalcamera * ........ * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 2.5.0; 2008.06.01 hof: created */ #include #include #include #define GAP_PLUGIN_NAME_RAWFRAMES_PARAMS "extension-gap-encpar-rawframes" #include "gap_gvetypes.h" #include "gap_libgapvidutil.h" #include "gap_libgimpgap.h" /* rawframe specific encoder params */ typedef struct { gint32 dum_par; /* unused */ } GapGveRawValues; typedef struct GapGveRawGlobalParams { /* nick: gpp */ GapGveCommonValues val; GapGveEncAInfo ainfo; GapGveEncList *ecp; GapGveRawValues evl; } GapGveRawGlobalParams; void p_rawframe_init_default_params(GapGveRawValues *epp); gint p_rawframe_encode(GapGveRawGlobalParams *gpp); gint p_rawframe_encode_dialog(GapGveRawGlobalParams *gpp); gchar* p_build_format_from_framename(gchar *framename); /* Includes for extra LIBS */ #define GAP_PLUGIN_NAME_rawframeS_ENCODE "plug-in-gap-enc-rawframes" /* ------------------------ * global gap DEBUG switch * ------------------------ */ /* int gap_debug = 1; */ /* print debug infos */ /* int gap_debug = 0; */ /* 0: dont print debug infos */ int gap_debug = 0; GapGveRawGlobalParams global_params; int global_nargs_raw_enc_par; static void query(void); static void run (const gchar *name, /* name of plugin */ gint n_params, /* number of in-paramters */ const GimpParam * param, /* in-parameters */ gint *nreturn_vals, /* number of out-parameters */ GimpParam ** return_vals); /* out-parameters */ static void p_gimp_get_data(const char *key, void *buffer, gint expected_size); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; /* ------------------------ * MAIN * ------------------------ */ MAIN () /* -------------------------------- * query * -------------------------------- */ static void query () { gchar *l_ecp_key; /* video encoder standard parameters (same for each encoder) */ static GimpParamDef args_raw_enc[] = { {GIMP_PDB_INT32, "run_mode", "non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_STRING, "videofile", "framename of the 1.st sinle framefile to write"}, {GIMP_PDB_INT32, "range_from", "number of first frame"}, {GIMP_PDB_INT32, "range_to", "number of last frame"}, {GIMP_PDB_INT32, "vid_width", "Width of resulting Video Frames (all Frames are scaled to this width)"}, {GIMP_PDB_INT32, "vid_height", "Height of resulting Video Frames (all Frames are scaled to this height)"}, {GIMP_PDB_INT32, "vid_format", "videoformat: 0=comp., 1=PAL, 2=NTSC, 3=SECAM, 4=MAC, 5=unspec"}, {GIMP_PDB_FLOAT, "framerate", "framerate in frames per seconds"}, {GIMP_PDB_INT32, "samplerate", "audio samplerate in samples per seconds (is ignored .wav files are used)"}, {GIMP_PDB_STRING, "audfile", "optional audiodata file .wav must contain uncompressed 16 bit samples. pass empty string if no audiodata should be included"}, {GIMP_PDB_INT32, "use_rest", "0 == use default values for encoder specific params, 1 == use encoder specific params"}, {GIMP_PDB_STRING, "filtermacro_file", "macro to apply on each handled frame. (textfile with filter plugin names and LASTVALUE bufferdump"}, {GIMP_PDB_STRING, "storyboard_file", "textfile with list of one or more framesequences"}, {GIMP_PDB_INT32, "input_mode", "0 ... image is one of the frames to encode, range_from/to params refere to numberpart of the other frameimages on disc. \n" "1 ... image is multilayer, range_from/to params refere to layer index. \n" "2 ... image is ignored, input is specified by storyboard_file parameter."}, {GIMP_PDB_INT32, "master_encoder_id", "id of the master encoder that called this plug-in (typically the pid)"}, }; static int nargs_raw_enc = sizeof(args_raw_enc) / sizeof(args_raw_enc[0]); /* video encoder specific parameters */ static GimpParamDef args_raw_enc_par[] = { {GIMP_PDB_INT32, "run_mode", "interactive, non-interactive"}, {GIMP_PDB_STRING, "key_stdpar", "key to get standard video encoder params via gimp_get_data"}, {GIMP_PDB_INT32, "dum_par", "Dummy parameter (unused)"}, }; static int nargs_raw_enc_par = sizeof(args_raw_enc_par) / sizeof(args_raw_enc_par[0]); static GimpParamDef *return_vals = NULL; static int nreturn_vals = 0; /* video encoder standard query (same for each encoder) */ static GimpParamDef args_in_ecp[] = { {GIMP_PDB_STRING, "param_name", "name of the parameter, supported: menu_name, video_extension"}, }; static GimpParamDef args_out_ecp[] = { {GIMP_PDB_STRING, "param_value", "parmeter value"}, }; static int nargs_in_enp = sizeof(args_in_ecp) / sizeof(args_in_ecp[0]); static int nargs_out_enp = (sizeof(args_out_ecp) / sizeof(args_out_ecp[0])); INIT_I18N(); global_nargs_raw_enc_par = nargs_raw_enc_par; gimp_install_procedure(GAP_PLUGIN_NAME_rawframeS_ENCODE, _("rawframes video encoding for anim frames. Menu: @rawframeS@"), _("This plugin has a video encoder API" " but writes a series of single raw frames instead of one videofile." " the filetype of the output frames is derived from the extension." " the extension is the suffix part of the parameter \"videofile\"." " the names of the output frame(s) are same as the parameter \"videofile\"" " but the framenumber part is replaced by the current framenumber" " (or added automatic if videofile has no number part)" " audiodata is ignored." "WARNINGS: for proper operation, the handled frames shall refere to single" " video file without any transitions. this allows fetching frames" " as raw data chunks. The chunks are 1:1 written to disc as framefiles." " The resulting raw data frames on disc may be unusable if the raw chunk data" " is not compatible to any image fileformat." " MPEG I frames, and MJPG files may be extractable to the JPEG fileformat." " A call of" "\"" GAP_PLUGIN_NAME_RAWFRAMES_PARAMS "\"" " to set encoder specific parameters, is not required because" " this release of the rawframe encoder has NO encoder specific parameters"), "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, NULL, /* has no Menu entry, just a PDB interface */ "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_raw_enc, nreturn_vals, args_raw_enc, return_vals); gimp_install_procedure(GAP_PLUGIN_NAME_RAWFRAMES_PARAMS, _("Set Parameters for GAP rawframes video encoder Plugins"), _("This plugin sets rawframes specific video encoding parameters."), "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, NULL, /* has no Menu entry, just a PDB interface */ NULL, GIMP_PLUGIN, nargs_raw_enc_par, nreturn_vals, args_raw_enc_par, return_vals); l_ecp_key = g_strdup_printf("%s%s", GAP_QUERY_PREFIX_VIDEO_ENCODERS, GAP_PLUGIN_NAME_rawframeS_ENCODE); gimp_install_procedure(l_ecp_key, _("Get GUI Parameters for GAP rawframes video encoder"), _("This plugin returns rawframes encoder specific parameters."), "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, NULL, /* has no Menu entry, just a PDB interface */ NULL, GIMP_PLUGIN, nargs_in_enp , nargs_out_enp, args_in_ecp, args_out_ecp); g_free(l_ecp_key); } /* end query */ /* -------------------------------- * run * -------------------------------- */ static void run (const gchar *name, /* name of plugin */ gint n_params, /* number of in-parameters */ const GimpParam * param, /* in-parameters */ gint *nreturn_vals, /* number of out-parameters */ GimpParam ** return_vals) /* out-parameters */ { GapGveRawValues *epp; GapGveRawGlobalParams *gpp; static GimpParam values[1]; gint32 l_rc; const char *l_env; char *l_ecp_key1; char *l_encoder_key; gpp = &global_params; epp = &gpp->evl; *nreturn_vals = 1; *return_vals = values; l_rc = 0; INIT_I18N(); values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = GIMP_PDB_SUCCESS; l_env = g_getenv("GAP_DEBUG_ENC"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } if(gap_debug) printf("\n\nSTART of PlugIn: %s\n", name); l_ecp_key1 = g_strdup_printf("%s%s", GAP_QUERY_PREFIX_VIDEO_ENCODERS, GAP_PLUGIN_NAME_rawframeS_ENCODE); l_encoder_key = g_strdup(GAP_PLUGIN_NAME_rawframeS_ENCODE); p_rawframe_init_default_params(epp); if (strcmp (name, l_ecp_key1) == 0) { /* this interface replies to the queries of the common encoder gui */ gchar *param_name; param_name = param[0].data.d_string; if(gap_debug) printf("query for param_name: %s\n", param_name); *nreturn_vals = 2; values[1].type = GIMP_PDB_STRING; if(strcmp (param_name, GAP_VENC_PAR_MENU_NAME) == 0) { values[1].data.d_string = g_strdup("rawframeS"); } else if (strcmp (param_name, GAP_VENC_PAR_VID_EXTENSION) == 0) { values[1].data.d_string = g_strdup(".jpg"); } else if (strcmp (param_name, GAP_VENC_PAR_SHORT_DESCRIPTION) == 0) { values[1].data.d_string = g_strdup(_("The rawframes Encoder\n" "writes single frames instead of one videofile\n" "the fileformat of the frames is derived from the\n" "extension of the video name, frames are named\n" "video name plus 6-digit number + extension" ) ); } else if (strcmp (param_name, GAP_VENC_PAR_GUI_PROC) == 0) { //values[1].data.d_string = g_strdup(GAP_PLUGIN_NAME_RAWFRAMES_PARAMS); /* the rawframes encoder has no encoder specific parameters. * deliver empty string for the parameter GUI procedure * in this case the master video encoder disables the button for * invoking encoder specific parameter dialog. * The currently implemented dialog is just a dummy popup */ values[1].data.d_string = g_strdup("\0"); } else { values[1].data.d_string = g_strdup("\0"); } } else if (strcmp (name, GAP_PLUGIN_NAME_RAWFRAMES_PARAMS) == 0) { /* this interface sets the encoder specific parameters */ gint l_set_it; gchar *l_key_stdpar; gpp->val.run_mode = param[0].data.d_int32; l_key_stdpar = param[1].data.d_string; gpp->val.vid_width = 320; gpp->val.vid_height = 200; p_gimp_get_data(l_key_stdpar, &gpp->val, sizeof(GapGveCommonValues)); if(gap_debug) printf("rate: %f w:%d h:%d\n", (float)gpp->val.framerate, (int)gpp->val.vid_width, (int)gpp->val.vid_height); l_set_it = TRUE; if (gpp->val.run_mode == GIMP_RUN_NONINTERACTIVE) { /* set video encoder specific params */ if (n_params != global_nargs_raw_enc_par) { values[0].data.d_status = GIMP_PDB_CALLING_ERROR; l_set_it = FALSE; } else { epp->dum_par = param[2+1].data.d_int32; } } else { /* try to read encoder specific params */ p_gimp_get_data(l_encoder_key, epp, sizeof(GapGveRawValues)); if(0 != p_rawframe_encode_dialog(gpp)) { l_set_it = FALSE; } } if(l_set_it) { if(gap_debug) printf("Setting Encoder specific Params\n"); gimp_set_data(l_encoder_key, epp, sizeof(GapGveRawValues)); } } else if (strcmp (name, GAP_PLUGIN_NAME_rawframeS_ENCODE) == 0) { char *l_base; int l_l; /* run the video encoder procedure */ gpp->val.run_mode = param[0].data.d_int32; /* get image_ID and animinfo */ gpp->val.image_ID = param[1].data.d_image; gap_gve_misc_get_ainfo(gpp->val.image_ID, &gpp->ainfo); /* set initial (default) values */ l_base = g_strdup(gpp->ainfo.basename); l_l = strlen(l_base); if (l_l > 0) { if(l_base[l_l -1] == '_') { l_base[l_l -1] = '\0'; } } if(gap_debug) printf("Init Default parameters for %s base: %s\n", name, l_base); g_snprintf(gpp->val.videoname, sizeof(gpp->val.videoname), "%s.mpg", l_base); gpp->val.audioname1[0] = '\0'; gpp->val.filtermacro_file[0] = '\0'; gpp->val.storyboard_file[0] = '\0'; gpp->val.framerate = gpp->ainfo.framerate; gpp->val.range_from = gpp->ainfo.curr_frame_nr; gpp->val.range_to = gpp->ainfo.last_frame_nr; gpp->val.samplerate = 0; gpp->val.vid_width = gimp_image_width(gpp->val.image_ID) - (gimp_image_width(gpp->val.image_ID) % 16); gpp->val.vid_height = gimp_image_height(gpp->val.image_ID) - (gimp_image_height(gpp->val.image_ID) % 16); gpp->val.vid_format = VID_FMT_NTSC; gpp->val.input_mode = GAP_RNGTYPE_FRAMES; g_free(l_base); if (n_params != GAP_VENC_NUM_STANDARD_PARAM) { values[0].data.d_status = GIMP_PDB_CALLING_ERROR; } else { if(gap_debug) printf("Reading Standard parameters for %s\n", name); if (param[3].data.d_string[0] != '\0') { g_snprintf(gpp->val.videoname, sizeof(gpp->val.videoname), "%s", param[3].data.d_string); } if (param[4].data.d_int32 >= 0) { gpp->val.range_from = param[4].data.d_int32; } if (param[5].data.d_int32 >= 0) { gpp->val.range_to = param[5].data.d_int32; } if (param[6].data.d_int32 > 0) { gpp->val.vid_width = param[6].data.d_int32; } if (param[7].data.d_int32 > 0) { gpp->val.vid_height = param[7].data.d_int32; } if (param[8].data.d_int32 > 0) { gpp->val.vid_format = param[8].data.d_int32; } gpp->val.framerate = param[9].data.d_float; gpp->val.samplerate = param[10].data.d_int32; g_snprintf(gpp->val.audioname1, sizeof(gpp->val.audioname1), "%s", param[11].data.d_string); /* use rawframes specific encoder parameters (0==run with default values) */ if (param[12].data.d_int32 == 0) { if(gap_debug) printf("Running the Encoder %s with Default Values\n", name); } else { /* try to read encoder specific params */ p_gimp_get_data(name, epp, sizeof(GapGveRawValues)); } if (param[13].data.d_string[0] != '\0') { g_snprintf(gpp->val.filtermacro_file, sizeof(gpp->val.filtermacro_file), "%s", param[13].data.d_string); } if (param[14].data.d_string[0] != '\0') { g_snprintf(gpp->val.storyboard_file, sizeof(gpp->val.storyboard_file), "%s", param[14].data.d_string); } if (param[15].data.d_int32 >= 0) { gpp->val.input_mode = param[15].data.d_int32; } gpp->val.master_encoder_id = param[16].data.d_int32; } if (values[0].data.d_status == GIMP_PDB_SUCCESS) { if (l_rc >= 0 ) { l_rc = p_rawframe_encode(gpp); /* delete images in the cache * (the cache may have been filled while parsing * and processing a storyboard file) */ gap_gve_story_drop_image_cache(); } } } else { values[0].data.d_status = GIMP_PDB_CALLING_ERROR; } if(l_rc < 0) { values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; } } /* end run */ /* -------------------------------- * p_gimp_get_data * -------------------------------- */ static void p_gimp_get_data(const char *key, void *buffer, gint expected_size) { if(gimp_get_data_size(key) == expected_size) { if(gap_debug) printf("p_gimp_get_data: key:%s\n", key); gimp_get_data(key, buffer); } else { if(gap_debug) { printf("ERROR: p_gimp_get_data key:%s failed\n", key); printf("ERROR: gimp_get_data_size:%d expected size:%d\n" , (int)gimp_get_data_size(key) , (int)expected_size); } } } /* end p_gimp_get_data */ /* -------------------------------- * p_rawframe_init_default_params * -------------------------------- */ void p_rawframe_init_default_params(GapGveRawValues *epp) { if(gap_debug) printf("p_rawframe_init_default_params\n"); epp->dum_par = 0; } /* end p_rawframe_init_default_params */ /* -------------------------------- * p_rawframe_encode_dialog * -------------------------------- */ gint p_rawframe_encode_dialog(GapGveRawGlobalParams *gpp) { gap_arr_msg_popup(GIMP_RUN_INTERACTIVE, _("the rawframe Encoder has no encoder specific Parameters")); return 0; } /* end p_rawframe_encode_dialog */ /* ---------------------------------------------------- * p_build_format_from_framename * ---------------------------------------------------- * IN: framename_0001.jpg * OUT: framename_%06d.jpg */ gchar * p_build_format_from_framename(gchar *framename) { gchar *l_fmt; gchar *l_fmtnum; gchar *l_framename; gint l_idx; gint l_len; gchar *l_ext_ptr; gchar *l_num_ptr; gint l_idx_numlen; l_framename = g_strdup(framename); l_ext_ptr = NULL; l_num_ptr = NULL; l_idx_numlen = 0; l_len = strlen(l_framename); /* findout the numberpart and extension */ for(l_idx=l_len-1; l_idx >= 0; l_idx--) { if (l_framename[l_idx] == '.') { l_ext_ptr = &l_framename[l_idx]; l_idx_numlen = 0; l_num_ptr = NULL; while(l_idx >= 0) { l_idx--; if(g_ascii_isdigit(l_framename[l_idx])) { l_idx_numlen++; } else { l_num_ptr = &l_framename[l_idx]; break; /* stop if ran out of number part */ } } break; } if(g_ascii_isdigit(l_framename[l_idx])) { if(l_num_ptr == NULL) { l_idx_numlen++; } } else { if (g_ascii_isdigit(l_framename[l_idx +1]) && (l_num_ptr == NULL)) { l_num_ptr = &l_framename[l_idx]; } } } if(l_num_ptr) { l_num_ptr++; *l_num_ptr = '\0'; /* set end of string marker */ } if(l_ext_ptr) { *l_ext_ptr = '\0'; /* set end of string marker */ l_ext_ptr++; } /* if(l_idx_numlen > 0) l_fmtnum = g_strdup_printf("%%0%dd", (int)l_idx_numlen); * else l_fmtnum = g_strdup("_%06d"); */ l_fmtnum = g_strdup("_%06d"); /* always use 6digit framenumbers */ if(l_ext_ptr) { l_fmt = g_strdup_printf("%s%s.%s", l_framename, l_fmtnum, l_ext_ptr); } else { l_fmt = g_strdup_printf("%s%s", l_framename, l_fmtnum); } g_free(l_fmtnum); g_free(l_framename); return(l_fmt); } /* end p_build_format_from_framename */ /* -------------------------------- * p_save_chunk_as_frame * -------------------------------- */ gboolean p_save_chunk_as_frame(const char *filename, unsigned char *video_chunk, gint32 video_frame_chunk_size, gint32 header_length) { FILE *fp; char *dataPtr; gint32 dataSize; dataSize = video_frame_chunk_size - header_length; dataPtr = video_chunk + header_length; fp = fopen(filename, "w"); if (fp) { fwrite(dataPtr, dataSize, 1, fp); fclose(fp); return (TRUE); } printf("ERROR cant write to file:%s\n", filename); return (FALSE); } /* end p_save_chunk_as_frame */ gint32 p_dimSizeOfRawFrame(GapGveRawGlobalParams *gpp) { gint32 sizeOfRawFrame; /* size of uncompressed RGBA frame + safety of 1000 bytes should be * more than enough */ sizeOfRawFrame = 1000 + (gpp->val.vid_width * gpp->val.vid_height * 4); return (sizeOfRawFrame); } /* end p_dimSizeOfRawFrame */ gboolean p_is_videoname_jpeg(const char *videoname) { const char *ext; gint len; gint idx; ext = videoname; if (ext == NULL) { return (FALSE); } len = strlen(videoname); for(idx = len-1; idx >= 0; idx--) { ext = &videoname[idx]; if (*ext == '.') { ext++; break; } } if (strcmp(ext, "jpg") == 0) { return (TRUE); } if (strcmp(ext, "JPG") == 0) { return (TRUE); } if (strcmp(ext, "jpeg") == 0) { return (TRUE); } if (strcmp(ext, "JPEG") == 0) { return (TRUE); } return (FALSE); } /* -------------------------------- * p_rawframe_encode * -------------------------------- */ gint p_rawframe_encode(GapGveRawGlobalParams *gpp) { static GapGveStoryVidHandle *l_vidhand = NULL; gint32 l_tmp_image_id; gint32 l_layer_id; long l_cur_frame_nr; long l_step, l_begin, l_end; gdouble l_percentage, l_percentage_step; int l_rc; unsigned char *l_video_chunk_ptr; gint32 l_maxSizeOfRawFrame; gint32 l_max_master_frame_nr; gint32 l_cnt_encoded_frames; gint32 l_cnt_reused_frames; gint32 l_check_flags; gchar *l_frame_fmt; /* format string has one %d for the framenumber */ gint32 l_out_frame_nr; GimpRunMode l_save_runmode; GapGveMasterEncoderStatus encStatus; if(gap_debug) { printf("p_rawframe_encode: START\n"); printf(" videoname: %s\n", gpp->val.videoname); printf(" audioname1: %s\n", gpp->val.audioname1); printf(" basename: %s\n", gpp->ainfo.basename); printf(" extension: %s\n", gpp->ainfo.extension); printf(" range_from: %d\n", (int)gpp->val.range_from); printf(" range_to: %d\n", (int)gpp->val.range_to); printf(" framerate: %f\n", (float)gpp->val.framerate); printf(" samplerate: %d\n", (int)gpp->val.samplerate); printf(" vid_width: %d\n", (int)gpp->val.vid_width); printf(" vid_height: %d\n", (int)gpp->val.vid_height); printf(" image_ID: %d\n", (int)gpp->val.image_ID); printf(" storyboard_file: %s\n", gpp->val.storyboard_file); printf(" input_mode: %d\n", gpp->val.input_mode); printf(" master_encoder_id:%d:\n", gpp->val.master_encoder_id); } l_maxSizeOfRawFrame = p_dimSizeOfRawFrame(gpp); l_video_chunk_ptr = g_malloc0(l_maxSizeOfRawFrame); l_out_frame_nr = 0; l_rc = 0; l_layer_id = -1; l_cnt_encoded_frames = 0; l_cnt_reused_frames = 0; l_tmp_image_id = -1; l_check_flags = GAP_VID_CHCHK_FLAG_SIZE; if(p_is_videoname_jpeg(gpp->val.videoname) == TRUE) { l_check_flags += GAP_VID_CHCHK_FLAG_JPG; if(gap_debug) { printf("check fetched chunks for JPEG frames activated\n"); } } l_frame_fmt = p_build_format_from_framename(gpp->val.videoname); if(gap_debug) printf("rawframes will be saved with filename: %s\n", l_frame_fmt); /* make list of frameranges */ { gint32 l_total_framecount; l_vidhand = gap_gve_story_open_vid_handle (gpp->val.input_mode ,gpp->val.image_ID ,gpp->val.storyboard_file ,gpp->ainfo.basename ,gpp->ainfo.extension ,gpp->val.range_from ,gpp->val.range_to ,&l_total_framecount ); l_vidhand->do_gimp_progress = FALSE; } /* TODO check for overwrite */ /* here we could open the video file for write */ /* gpp->val.videoname */ l_percentage = 0.0; if(gpp->val.run_mode == GIMP_RUN_INTERACTIVE) { gap_gve_misc_initGapGveMasterEncoderStatus(&encStatus , gpp->val.master_encoder_id , abs(gpp->val.range_to - gpp->val.range_from) + 1 /* total_frames */ ); } if(gpp->val.range_from > gpp->val.range_to) { l_step = -1; /* operate in descending (reverse) order */ l_percentage_step = 1.0 / ((1.0 + gpp->val.range_from) - gpp->val.range_to); } else { l_step = 1; /* operate in ascending order */ l_percentage_step = 1.0 / ((1.0 + gpp->val.range_to) - gpp->val.range_from); } l_begin = gpp->val.range_from; l_end = gpp->val.range_to; l_max_master_frame_nr = abs(l_end - l_begin) + 1; l_cur_frame_nr = l_begin; l_save_runmode = GIMP_RUN_INTERACTIVE; while(l_rc >= 0) { gboolean l_fetch_ok; gboolean l_force_keyframe; gint32 l_video_frame_chunk_size; gint32 l_video_frame_chunk_hdr_size; l_out_frame_nr++; l_fetch_ok = gap_story_render_fetch_composite_image_or_chunk(l_vidhand , l_cur_frame_nr , (gint32) gpp->val.vid_width , (gint32) gpp->val.vid_height , gpp->val.filtermacro_file , &l_layer_id /* output */ , &l_tmp_image_id /* output */ , TRUE /* dont_recode_flag */ , NULL /* GapCodecNameElem *vcodec_list NULL == no checks */ , &l_force_keyframe , l_video_chunk_ptr , &l_video_frame_chunk_size /* actual chunk size (incl. header) */ , l_maxSizeOfRawFrame /* IN max size */ , gpp->val.framerate , l_max_master_frame_nr , &l_video_frame_chunk_hdr_size , l_check_flags ); if(l_fetch_ok != TRUE) { printf("ERROR: fetching of frame: %d FAILED, terminating\n", (int)l_cur_frame_nr); return -1; } else { gchar *l_sav_name; l_sav_name = g_strdup_printf(l_frame_fmt, (int)l_out_frame_nr); if (l_video_frame_chunk_size > 0) { gboolean l_saveOk; l_cnt_reused_frames++; if (gap_debug) { printf("DEBUG: 1:1 copy of frame %d (fetch as chunk OK) chunk_ptr:%d chunk_size:%d chunk_hdr_size:%d\n" , (int)l_cur_frame_nr , (int)l_video_chunk_ptr , (int)l_video_frame_chunk_size , (int)l_video_frame_chunk_hdr_size ); } /* dont recode, just write video chunk to output frame file */ l_saveOk = p_save_chunk_as_frame(l_sav_name, l_video_chunk_ptr, l_video_frame_chunk_size, l_video_frame_chunk_hdr_size); if (!l_saveOk) { return -1; } } else { l_cnt_encoded_frames++; if (gap_debug) { printf("DEBUG: saving recoded frame %d (fetch as chunk FAILED)\n", (int)l_cur_frame_nr); } if(gpp->val.run_mode == GIMP_RUN_INTERACTIVE) { char *l_msg; l_msg = g_strdup_printf(_("SAVING: %s\n"), l_sav_name); gimp_progress_init(l_msg); g_free(l_msg); } { gint32 l_sav_rc; if(gap_debug) { printf("rawframe mode:%d, image_id:%d save: %s l_sav_name\n" ,(int)l_save_runmode ,(int)l_tmp_image_id ,l_sav_name ); } l_sav_rc = gap_lib_save_named_image(l_tmp_image_id, l_sav_name, l_save_runmode); if(l_sav_rc < 0) { g_message(_("** Save FAILED on file\n%s"), l_sav_name); l_rc = -1; } } l_save_runmode = GIMP_RUN_WITH_LAST_VALS; if(l_tmp_image_id < 0) { return -1; } } g_free(l_sav_name); } if(l_tmp_image_id >= 0) { /* destroy the tmp image */ gap_image_delete_immediate(l_tmp_image_id); } l_percentage += l_percentage_step; if(gap_debug) printf("PROGRESS: %f\n", (float) l_percentage); if(gpp->val.run_mode == GIMP_RUN_INTERACTIVE) { encStatus.frames_processed++; encStatus.frames_encoded = l_cnt_encoded_frames; encStatus.frames_copied_lossless = l_cnt_reused_frames; gap_gve_misc_do_master_encoder_progress(&encStatus); } /* terminate on cancel reqeuset (CANCEL button was pressed in the master encoder dialog) */ if(gap_gve_misc_is_master_encoder_cancel_request(&encStatus)) { break; } /* advance to next frame */ if((l_cur_frame_nr == l_end) || (l_rc < 0)) { break; } l_cur_frame_nr += l_step; } g_free(l_frame_fmt); if(l_vidhand) { gap_gve_story_close_vid_handle(l_vidhand); } /* statistics */ if(gap_debug) { printf("encoded frames: %d\n", (int)l_cnt_encoded_frames); printf("1:1 copied frames: %d\n", (int)l_cnt_reused_frames); printf("total handled frames: %d\n", (int)l_cnt_encoded_frames + l_cnt_reused_frames); } return l_rc; } /* end p_rawframe_encode */ gimp-gap-2.6.0+dfsg.orig/intltool-extract.in0000644000175000017500000000000011212030535020602 0ustar thibautthibautgimp-gap-2.6.0+dfsg.orig/install-sh0000755000175000017500000003246411170314110016762 0ustar thibautthibaut#!/bin/sh # install - install a program, script, or datafile scriptversion=2006-12-25.00 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: gimp-gap-2.6.0+dfsg.orig/libgapvidapi/0000755000175000017500000000000011212031410017374 5ustar thibautthibautgimp-gap-2.6.0+dfsg.orig/libgapvidapi/gap_vid_api_gimp.c0000644000175000017500000002653511212030253023035 0ustar thibautthibaut/* gap_vid_api_gimp.c * * GAP Video read API implementation for singleframe sequence * wrappers for gap/gimp generic file load procedure * * please note that the singleframes are loaded as flatened frames * when they are read by this API. * * 2003.05.09 hof created * */ /* ================================================ gimp * gimp (singleframe access via gap/gimp) gimp * ================================================ gimp * ================================================ gimp */ #ifdef ENABLE_GVA_GIMP static gchar *global_gva_gimp_filename = NULL; static gint32 global_gva_gimp_image_id = -1; /* ------------------------- * API READ extension GIMP * ------------------------- */ /* structure with gap specific anim information */ typedef struct t_GVA_gimp { gint32 initial_image_id; long first_frame_nr; long last_frame_nr; long curr_frame_nr; long frame_cnt; char basename[1024]; /* may include path */ char extension[50]; gdouble framerate; } t_GVA_gimp; /* ----------------------------- * p_wrapper_gimp_check_sig * ----------------------------- */ gboolean p_wrapper_gimp_check_sig(char *filename) { gint32 l_image_id; if(gap_debug) printf("p_wrapper_gimp_check_sig: START filename:%s\n", filename); l_image_id = gimp_file_load(GIMP_RUN_NONINTERACTIVE, filename, filename); if (l_image_id < 0) { if(gap_debug) printf("p_wrapper_gimp_check_sig:%s: could not load file\n", filename); return(FALSE); } /* we do not delete l_image_id at this point. * in most cases the check_sig call is followed by open_read * where we need that image again */ if(global_gva_gimp_filename) g_free(global_gva_gimp_filename); global_gva_gimp_filename = g_strdup(filename); global_gva_gimp_image_id = l_image_id; if(gap_debug) printf("p_wrapper_gimp_check_sig: compatible is TRUE\n"); return (TRUE); } /* ----------------------------- * p_wrapper_gimp_open_read * ----------------------------- * open performs a GAP directory scan to findout * how many frames we have. * the initial image (the one with filename) * will be loaded as gimp_image and kept cached until close. */ void p_wrapper_gimp_open_read(char *filename, t_GVA_Handle *gvahand) { t_GVA_gimp* handle; t_GVA_DecoderElem *dec_elem; gint32 l_image_id; if(gap_debug) printf("p_wrapper_gimp_open_read: START filename:%s\n", filename); gvahand->decoder_handle = (void *)NULL; handle = g_malloc0(sizeof(t_GVA_gimp)); l_image_id = -1; if(global_gva_gimp_filename) { if(strcmp(global_gva_gimp_filename, filename) == 0) { l_image_id = global_gva_gimp_image_id; } } if(l_image_id < 0) { l_image_id = gimp_file_load(GIMP_RUN_NONINTERACTIVE, filename, filename); if (l_image_id < 0) { g_free(handle); return; } } /* the initial image is now flattened and kept until close * (read ops for the curr_frame_nr will read from the initial_image_id * and can skip the slower file load) */ gimp_image_flatten(l_image_id); handle->initial_image_id = l_image_id; gvahand->gva_thread_save = FALSE; /* calls to gimp from 2 threads do crash */ gvahand->vtracks = 1; gvahand->atracks = 0; gvahand->frame_bpp = 3; /* RGB pixelformat */ gvahand->total_aud_samples = 0; gvahand->width = gimp_image_width(l_image_id); gvahand->height = gimp_image_height(l_image_id); /* fetch animframe informations (perform GAP directoryscan) */ if(l_image_id >= 0) { static char *l_called_proc = "plug_in_gap_get_animinfo"; GimpParam *return_vals; int nreturn_vals; gint32 dummy_layer_id; dummy_layer_id = gap_image_get_any_layer(l_image_id); return_vals = gimp_run_procedure (l_called_proc, &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, l_image_id, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_END); if (return_vals[0].data.d_status != GIMP_PDB_SUCCESS) { printf("Error: PDB call of %s failed, image_ID: %d\n", l_called_proc, (int)l_image_id); g_free(handle); return; } handle->first_frame_nr = return_vals[1].data.d_int32; handle->last_frame_nr = return_vals[2].data.d_int32; handle->curr_frame_nr = return_vals[3].data.d_int32; handle->frame_cnt = return_vals[4].data.d_int32; g_snprintf(handle->basename, sizeof(handle->basename), "%s", return_vals[5].data.d_string); g_snprintf(handle->extension, sizeof(handle->extension), "%s", return_vals[6].data.d_string); handle->framerate = return_vals[7].data.d_float; } gvahand->framerate = handle->framerate; gvahand->total_frames = handle->frame_cnt; gvahand->all_frames_counted = TRUE; /* handle->frame_cnt is the exact total_frames number */ dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(dec_elem) { if(dec_elem->decoder_description) { g_free(dec_elem->decoder_description); } dec_elem->decoder_description = g_strdup_printf("GAP Decoder (for all GIMP readable imagefiles)\n" " (EXT: .xcf,.jpg,.gif,.png,.tif,...)" ); } gvahand->decoder_handle = (void *)handle; if(gap_debug) printf("p_wrapper_gimp_open_read: END, OK\n"); } /* end p_wrapper_gimp_open_read */ /* ----------------------------- * p_wrapper_gimp_close * ----------------------------- */ void p_wrapper_gimp_close(t_GVA_Handle *gvahand) { t_GVA_gimp *handle; if(gap_debug) printf("p_wrapper_gimp_close: START\n"); handle = (t_GVA_gimp *)gvahand->decoder_handle; /* delete the initial image at close */ p_gimp_image_delete(handle->initial_image_id); return; } /* end p_wrapper_gimp_close */ /* ---------------------------------- * p_wrapper_gimp_get_next_frame * ---------------------------------- * read singleframe with current_seek_nr and advance position * TODO: EOF detection * */ t_GVA_RetCode p_wrapper_gimp_get_next_frame(t_GVA_Handle *gvahand) { t_GVA_gimp *handle; gchar *l_framename; gint32 l_image_id; gint32 l_frame_nr; t_GVA_RetCode l_rc; handle = (t_GVA_gimp *)gvahand->decoder_handle; l_frame_nr = gvahand->current_seek_nr + (handle->first_frame_nr - 1); if(1==0 /*l_frame_nr == handle->curr_frame_nr*/) { /* this frame_nr is the initial_image, that is always cached * as gimp image (without a display) * no need to load agian, just transfer to rowbuffer */ l_rc = GVA_gimp_image_to_rowbuffer(gvahand, handle->initial_image_id); } else { l_framename = p_alloc_fname(handle->basename ,l_frame_nr ,handle->extension ); l_image_id = gimp_file_load(GIMP_RUN_NONINTERACTIVE, l_framename, l_framename); if(l_image_id < 0) { l_rc = GVA_RET_ERROR; } else { l_rc = GVA_gimp_image_to_rowbuffer(gvahand, l_image_id); p_gimp_image_delete(l_image_id); } g_free(l_framename); } if (l_rc == GVA_RET_OK) { gvahand->current_frame_nr = gvahand->current_seek_nr; gvahand->current_seek_nr++; return(GVA_RET_OK); } return(l_rc); } /* end p_wrapper_gimp_get_next_frame */ /* ------------------------------ * p_wrapper_gimp_seek_frame * ------------------------------ * - for the singleframe decoder * we just set the current framenumber. */ t_GVA_RetCode p_wrapper_gimp_seek_frame(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit) { t_GVA_gimp *handle; gint32 l_frame_pos; handle = (t_GVA_gimp *)gvahand->decoder_handle; switch(pos_unit) { case GVA_UPOS_FRAMES: l_frame_pos = (gint32)pos; break; case GVA_UPOS_SECS: l_frame_pos = (gint32)rint (pos * gvahand->framerate); break; case GVA_UPOS_PRECENTAGE: /* is not reliable until all_frames_counted == TRUE */ l_frame_pos = (gint32)GVA_percent_2_frame(gvahand->total_frames, pos); break; default: l_frame_pos = (gint32)pos; break; } gvahand->percentage_done = 0.0; if(l_frame_pos < gvahand->total_frames) { if(gap_debug) printf("p_wrapper_gimp_seek_frame: SEEK OK: l_frame_pos: %d cur_seek:%d cur_frame:%d\n", (int)l_frame_pos, (int)gvahand->current_seek_nr, (int)gvahand->current_frame_nr); gvahand->current_seek_nr = (gint32)l_frame_pos; return(GVA_RET_OK); } return(GVA_RET_EOF); } /* end p_wrapper_gimp_seek_frame */ /* ------------------------------ * p_wrapper_gimp_seek_audio * ------------------------------ */ t_GVA_RetCode p_wrapper_gimp_seek_audio(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit) { printf("p_wrapper_gimp_get_audio: there is NO adiosupport for single frames\n"); return(GVA_RET_ERROR); } /* end p_wrapper_gimp_seek_audio */ /* ------------------------------ * p_wrapper_gimp_get_audio * ------------------------------ */ t_GVA_RetCode p_wrapper_gimp_get_audio(t_GVA_Handle *gvahand ,gint16 *output_i ,gint32 channel ,gdouble samples ,t_GVA_AudPos mode_flag ) { printf("p_wrapper_gimp_get_audio: there is NO adiosupport for single frames\n"); return(GVA_RET_ERROR); } /* end p_wrapper_gimp_get_audio */ /* ---------------------------------- * p_wrapper_gimp_count_frames * ---------------------------------- * (re)open a separated handle for counting * to ensure that stream positions are not affected by the count. */ t_GVA_RetCode p_wrapper_gimp_count_frames(t_GVA_Handle *gvahand) { gvahand->percentage_done = 0.0; /* do not count at all, exact total_frames is known at open_read time */ return(GVA_RET_OK); } /* end p_wrapper_gimp_count_frames */ /* ---------------------------------- * p_wrapper_gimp_seek_support * ---------------------------------- */ t_GVA_SeekSupport p_wrapper_gimp_seek_support(t_GVA_Handle *gvahand) { return(GVA_SEEKSUPP_NATIVE); } /* end p_wrapper_gimp_seek_support */ /* ----------------------------- * p_gimp_new_dec_elem * ----------------------------- * create a new decoder element and init with * functionpointers referencing the GIMP singleframe * specific Procedures */ t_GVA_DecoderElem * p_gimp_new_dec_elem(void) { t_GVA_DecoderElem *dec_elem; dec_elem = g_malloc0(sizeof(t_GVA_DecoderElem)); if(dec_elem) { dec_elem->decoder_name = g_strdup("gimp/gap"); dec_elem->decoder_description = g_strdup("gimp singleframe loader (EXT: .xcf,.jpg,.gif,.tif,.bmp,...)"); dec_elem->fptr_check_sig = &p_wrapper_gimp_check_sig; dec_elem->fptr_open_read = &p_wrapper_gimp_open_read; dec_elem->fptr_close = &p_wrapper_gimp_close; dec_elem->fptr_get_next_frame = &p_wrapper_gimp_get_next_frame; dec_elem->fptr_seek_frame = &p_wrapper_gimp_seek_frame; dec_elem->fptr_seek_audio = &p_wrapper_gimp_seek_audio; dec_elem->fptr_get_audio = &p_wrapper_gimp_get_audio; dec_elem->fptr_count_frames = &p_wrapper_gimp_count_frames; dec_elem->fptr_seek_support = &p_wrapper_gimp_seek_support; dec_elem->fptr_get_video_chunk = NULL; /* singleframes dont have compressed video chunks */ dec_elem->next = NULL; } return (dec_elem); } /* end p_gimp_new_dec_elem */ #endif /* ENABLE_GVA_GIMP */ gimp-gap-2.6.0+dfsg.orig/libgapvidapi/gap_vid_api_vidindex.c0000644000175000017500000004660411212030253023712 0ustar thibautthibaut/* vid_api_vidindex.c * * GAP Video read API implementation of vidindex file handling procedures. * vidindex files are created optional to speed up * frame seek operations. * vidindex files are machine and decoder dependent files * that store seek offsets (gint64 or gdouble) in an access table where (framenumber / stepsize) * is the table index. * standard stepsize of 50 results in one entry for every 50.th frame. * usually vidindex is built in the frame_count procedure, * but only if the decoder has an implementation for videoindex. * (the 1.st decoder with videoindex implementation is libavformat FFMPEG) * * 2004.03.06 hof created * */ static char * p_build_videoindex_filename(const char *filename, gint32 track, const char *decoder_name); static gboolean p_equal_mtime(time_t mtime_idx, time_t mtime_file); /* ---------------------------------- * GVA_build_videoindex_filename * ---------------------------------- * external variante using track numbers starting at 1 */ char * GVA_build_videoindex_filename(const char *filename, gint32 track, const char *decoder_name) { return (p_build_videoindex_filename(filename , MIN(track -1, 0) ,decoder_name )); } /* end GVA_build_videoindex_filename */ /* ------------------------------------ * p_build_gvaidx_filename * ------------------------------------ * internal variante using track numbers starting at 0 */ static char * p_build_gvaidx_filename(const char *filename, gint32 track, const char *decoder_name , const char *suffix) { static gchar name[40]; gchar *vindex_file; gchar *filename_part; gchar *uri; gchar *gvaindexes_dir; uri = GVA_filename_to_uri(filename); if(uri) { GVA_md5_string(name, uri); } else { return (NULL); } filename_part = g_strdup_printf("%s.%d.%s.%s" , name , (int)track , decoder_name , suffix ); gvaindexes_dir = gimp_gimprc_query("video-index-dir"); if(gvaindexes_dir) { vindex_file = g_build_filename(gvaindexes_dir, filename_part, NULL); g_free(gvaindexes_dir); } else { /* nothing configured. in that case we use a default directory */ //vindex_file = g_build_filename(g_get_home_dir(), "gvaindexes", filename_part, NULL); vindex_file = g_build_filename(gimp_directory(), "gvaindexes", filename_part, NULL); } if(gap_debug) { printf("VIDINDEX: filename_part: %s\n", filename_part); printf("VIDINDEX: vindex_file: %s\n", vindex_file); } g_free(filename_part); return(vindex_file); } /* end p_build_gvaidx_filename */ /* ------------------------------------ * p_build_videoindex_filename * ------------------------------------ * internal variante using track numbers starting at 0 */ static char * p_build_videoindex_filename(const char *filename, gint32 track, const char *decoder_name) { return(p_build_gvaidx_filename(filename, track, decoder_name, "gvaidx")); } /* end p_build_videoindex_filename */ /* ---------------------------------- * p_equal_mtime * ---------------------------------- * return if bot mtime values are equal * * if the difference is exactly 3600 seconds * accept this as equal and return TRUE * * return FALSE in all other cases. * * This behaviour compensates the problem were the video index creation * was done in normal time (for instance in december) * but the query is done after switch to daylight saving time (for instance in may) * where the mtime delivered via a query with stat uses 1 hour earlier mtime * (assuming that the video file was not modified since december) and won't match * with the mtime value stored in the videoindex. * * therefore we tolerate the difference (with a very little risk to use an old index * in case there really was a modififaction with exactly one hour difference) * but keeps all videoindexes usable after switch to daylight saving time. */ static gboolean p_equal_mtime(time_t mtime_idx, time_t mtime_file) { if(mtime_idx == mtime_file) { return (TRUE); } if (abs(mtime_idx - mtime_file) == 3600) { if(gap_debug) { printf("GVA_videoindex faking equal mtimes MTIME_INDEX:%ld MTIME_FILE:%ld (3600 sec different)\n" , (long)mtime_idx , (long)mtime_file); } return (TRUE); } return (FALSE); } /* end p_equal_mtime */ /* ---------------------------------- * GVA_build_video_toc_filename * ---------------------------------- */ char * GVA_build_video_toc_filename(const char *filename, const char *decoder_name) { static gchar name[40]; gchar *toc_file; gchar *filename_part; gchar *uri; gchar *gvaindexes_dir; uri = GVA_filename_to_uri(filename); if(uri) { GVA_md5_string(name, uri); } else { printf("TOC-NAME: uri is NULL filename:%s\n", filename); return (NULL); } filename_part = g_strdup_printf("%s.%s.toc", name, decoder_name); gvaindexes_dir = gimp_gimprc_query("video-index-dir"); if(gvaindexes_dir) { toc_file = g_build_filename(gvaindexes_dir, filename_part, NULL); g_free(gvaindexes_dir); } else { /* nothing configured. in that case we use a default directory */ //toc_file = g_build_filename(g_get_home_dir(), "gvaindexes", filename_part, NULL); toc_file = g_build_filename(gimp_directory(), "gvaindexes", filename_part, NULL); } if(gap_debug) { printf("TOC-NAME: filename_part: %s\n", filename_part); printf("TOC-NAME: toc_file: %s\n", toc_file); } g_free(filename_part); return(toc_file); } /* end GVA_build_video_toc_filename */ /* ---------------------------------- * GVA_new_videoindex * ---------------------------------- */ t_GVA_Videoindex * GVA_new_videoindex(void) { t_GVA_Videoindex *vindex; vindex = g_malloc0(sizeof(t_GVA_Videoindex)); if(vindex) { vindex->tabtype = GVA_IDX_TT_GINT64; vindex->videoindex_filename = NULL; vindex->videofile_uri = NULL; vindex->tocfile = NULL; vindex->stepsize = GVA_VIDINDEXTAB_DEFAULT_STEPSIZE; vindex->tabsize_used = 0; vindex->tabsize_allocated = 0; vindex->track = 1; vindex->total_frames = 0; vindex->mtime = 0; /* is set later when saved to file */ vindex->ofs_tab = NULL; } return(vindex); } /* end GVA_new_videoindex */ /* ---------------------------------- * GVA_free_videoindex * ---------------------------------- */ void GVA_free_videoindex(t_GVA_Videoindex **in_vindex) { t_GVA_Videoindex *vindex; if(in_vindex) { vindex = *in_vindex; if(vindex) { if(vindex->videoindex_filename) { g_free(vindex->videoindex_filename); } if(vindex->videofile_uri) { g_free(vindex->videofile_uri); } if(vindex->ofs_tab) { g_free(vindex->ofs_tab); } if(vindex->tocfile) { g_free(vindex->tocfile); } g_free(vindex); } *in_vindex = NULL; } } /* end GVA_free_videoindex */ /* ---------------------------------- * p_debug_print_videoindex * ---------------------------------- */ static void p_debug_print_videoindex(t_GVA_Videoindex *vindex) { printf("\n"); printf("GVA_debug_print_videoindex: START\n"); if(vindex) { gint l_idx; printf("GVA_VIDEOINDEX dump START"); printf("\n\videoindex_filename:%s\n", vindex->videoindex_filename); printf(" MTIM: vindex->hdr.val_mtim:%s\n TYPE: vindex->hdr.val_type:%s\n" , vindex->hdr.val_mtim , vindex->hdr.val_type ); printf("TYPE:"); switch(vindex->tabtype) { case GVA_IDX_TT_WITHOUT_TIMECODE_GDOUBLE: printf("gdouble"); break; case GVA_IDX_TT_WITHOUT_TIMECODE_GINT64: printf("gint64"); break; case GVA_IDX_TT_GDOUBLE: printf("GDOUBLE"); break; case GVA_IDX_TT_GINT64: printf("GINT64"); break; default: printf("undefined"); break; } printf("\n"); printf("STEP:"); printf("%d\n", (int)vindex->stepsize); printf("SIZE:"); printf("%d\n", (int)vindex->tabsize_used); printf("TRAK:"); printf("%d\n", (int)vindex->track); printf("FTOT:"); printf("%d\n", (int)vindex->total_frames); printf("DECO:"); printf("%15s\n", vindex->hdr.val_deco); printf("MTIM:"); printf("%ld\n", (long)vindex->mtime); printf("FILE:%s\n\n", vindex->videofile_uri); for(l_idx=0; l_idx < vindex->tabsize_used; l_idx++) { printf("VINDEX: ofs_tab[%d]: ofs64: %lld seek_nr:%d flen:%d chk:%d dts:%lld\n" , (int)l_idx , vindex->ofs_tab[l_idx].uni.offset_gint64 , (int)vindex->ofs_tab[l_idx].seek_nr , (int)vindex->ofs_tab[l_idx].frame_length , (int)vindex->ofs_tab[l_idx].checksum , vindex->ofs_tab[l_idx].timecode_dts ); } } printf("GVA_debug_print_videoindex: END\n\n"); } /* end p_debug_print_videoindex */ /* ---------------------------------- * GVA_load_videoindex * ---------------------------------- * load videoindex from file * note that the old fileformat without dts timecode is supported for backwards compatibility. * the old format used lowercase type names "gint64" "gdouble" * the new format uses uppercase "GINT64" "GDOUBLE" */ t_GVA_Videoindex * GVA_load_videoindex(const char *filename, gint32 track, const char *decoder_name) { t_GVA_Videoindex *vindex; FILE *fp; gboolean success; gboolean delete_flag; if(gap_debug) { printf("GVA_load_videoindex START\n"); } if(filename == NULL) { return (NULL); } if(decoder_name == NULL) { return (NULL); } if(gap_debug) { printf("GVA_load_videoindex file:%s\n", filename); } success = FALSE; delete_flag = FALSE; vindex = GVA_new_videoindex(); if(vindex) { vindex->videoindex_filename = p_build_videoindex_filename(filename , track , decoder_name); if(vindex->videoindex_filename) { if(gap_debug) { printf("GVA_load_videoindex videoindex_filename:%s\n", vindex->videoindex_filename); } fp = g_fopen(vindex->videoindex_filename, "rb"); if(fp) { gint32 rd_len; gint32 rd_size; gint l_flen; gint32 l_mtime; rd_len = fread(&vindex->hdr, 1, sizeof(vindex->hdr), fp); if(rd_len) { vindex->stepsize = atol(vindex->hdr.val_step); vindex->tabsize_used = atol(vindex->hdr.val_size); vindex->track = atol(vindex->hdr.val_trak); vindex->total_frames = atol(vindex->hdr.val_ftot); vindex->tabsize_allocated = atol(vindex->hdr.val_size); vindex->mtime = atol(vindex->hdr.val_mtim); if(gap_debug) { printf("GVA_load_videoindex MTIM: vindex->hdr.val_mtim:%s\n" , vindex->hdr.val_mtim); } l_mtime = gap_file_get_mtime(filename); if(p_equal_mtime(l_mtime, vindex->mtime) == TRUE) { l_flen = atol(vindex->hdr.val_flen); if(l_flen > 0) { /* read the videofile_uri of the videofile */ vindex->videofile_uri = g_malloc0(l_flen); if(vindex->videofile_uri) { rd_len = fread(vindex->videofile_uri, 1, l_flen, fp); } else { fseek(fp, l_flen, SEEK_CUR); } } vindex->tabtype = GVA_IDX_TT_UNDEFINED; if(strcmp(vindex->hdr.val_type, "GINT64") == 0) { vindex->tabtype = GVA_IDX_TT_GINT64; } else if(strcmp(vindex->hdr.val_type, "GDOUBLE") == 0) { vindex->tabtype = GVA_IDX_TT_GDOUBLE; } else if(strcmp(vindex->hdr.val_type, "gint64") == 0) { vindex->tabtype = GVA_IDX_TT_WITHOUT_TIMECODE_GINT64; } else if(strcmp(vindex->hdr.val_type, "gdouble") == 0) { vindex->tabtype = GVA_IDX_TT_WITHOUT_TIMECODE_GDOUBLE; } rd_len = 0; rd_size = -1; switch(vindex->tabtype) { case GVA_IDX_TT_WITHOUT_TIMECODE_GINT64: /* old format */ case GVA_IDX_TT_WITHOUT_TIMECODE_GDOUBLE: /* old format */ delete_flag = TRUE; //rd_size = sizeof(t_GVA_IndexElem) * vindex->tabsize_used; //if(rd_size > 0) //{ // vindex->ofs_tab = g_new(t_GVA_IndexElem, vindex->tabsize_used); // if(vindex->ofs_tab) // { // int ii; // t_GVA_IndexElemWithoutTimecode *oldIndexformatTab; // // oldIndexformatTab = g_new(t_GVA_IndexElemWithoutTimecode, vindex->tabsize_used); // rd_len = fread(oldIndexformatTab, 1, rd_size, fp); // // /* migration loop to convert from old index format */ // for(ii=0; ii < vindex->tabsize_used; ii++) // { // vindex->ofs_tab[ii].timecode_dts = AV_NOPTS_VALUE; // vindex->ofs_tab[ii].uni.offset_gint64 = oldIndexformatTab[ii].uni.offset_gint64; // vindex->ofs_tab[ii].seek_nr = oldIndexformatTab[ii].seek_nr; // vindex->ofs_tab[ii].frame_length = oldIndexformatTab[ii].frame_length; // vindex->ofs_tab[ii].checksum = oldIndexformatTab[ii].checksum; // } // } //} break; case GVA_IDX_TT_GINT64: case GVA_IDX_TT_GDOUBLE: rd_size = sizeof(t_GVA_IndexElem) * vindex->tabsize_used; if(rd_size > 0) { vindex->ofs_tab = g_new(t_GVA_IndexElem, vindex->tabsize_used); if(vindex->ofs_tab) { rd_len = fread(vindex->ofs_tab, 1, rd_size, fp); } } break; default: break; } if(rd_len == rd_size) { success = TRUE; if(gap_debug) { p_debug_print_videoindex(vindex); printf("GVA_load_videoindex SUCCESS\n"); } } } else { delete_flag = TRUE; if(gap_debug) { printf("\nGVA_load_videoindex TOO OLD videoindex_filename:%s\n" , vindex->videoindex_filename); printf("GVA_load_videoindex MTIME_INDEX:%ld FILE:%ld\n" , (long)vindex->mtime , (long)l_mtime); } } } fclose(fp); if(delete_flag) { /* delete OLD videoindex * (that has become unusable because mtime does not match with videofile) */ g_remove(vindex->videoindex_filename); } } else { if(gap_debug) { printf("GVA_load_videoindex FILE NOT FOUND %s\n", vindex->videoindex_filename); } } } if(!success) { if(gap_debug) { printf("GVA_load_videoindex NO vindex available\n"); } GVA_free_videoindex(&vindex); } } return(vindex); } /* end GVA_load_videoindex */ /* ---------------------------------- * GVA_save_videoindex * ---------------------------------- * save videoindex to fileformat * (always save the new format with dts timecode) */ gboolean GVA_save_videoindex(t_GVA_Videoindex *vindex, const char *filename, const char *decoder_name) { FILE *fp; gint l_flen; if(vindex == NULL) { return (FALSE); } if(filename == NULL) { return (FALSE); } if(decoder_name == NULL) { return (FALSE); } if(vindex->videofile_uri) { g_free(vindex->videofile_uri); } vindex->videofile_uri = GVA_filename_to_uri(filename); if(vindex->videofile_uri == NULL) { return (FALSE); } vindex->mtime = gap_file_get_mtime(filename); /* use one or 2 extra bytes for one or 2 terminating \0 characters * (l_flen must be even number) */ l_flen = 1 + (strlen(vindex->videofile_uri) / 2); l_flen *= 2; g_snprintf(vindex->hdr.key_identifier, sizeof(vindex->hdr), "GVA_VIDEOINDEX"); g_snprintf(vindex->hdr.key_type, sizeof(vindex->hdr.key_type), "TYPE:"); switch(vindex->tabtype) { case GVA_IDX_TT_GDOUBLE: case GVA_IDX_TT_WITHOUT_TIMECODE_GDOUBLE: g_snprintf(vindex->hdr.val_type, sizeof(vindex->hdr.val_type), "GDOUBLE"); break; case GVA_IDX_TT_GINT64: case GVA_IDX_TT_WITHOUT_TIMECODE_GINT64: case GVA_IDX_TT_UNDEFINED: g_snprintf(vindex->hdr.val_type, sizeof(vindex->hdr.val_type), "GINT64"); break; } g_snprintf(vindex->hdr.key_step, sizeof(vindex->hdr.key_step), "STEP"); g_snprintf(vindex->hdr.val_step, sizeof(vindex->hdr.val_step), "%d", (int)vindex->stepsize); g_snprintf(vindex->hdr.key_size, sizeof(vindex->hdr.key_size), "SIZE"); g_snprintf(vindex->hdr.val_size, sizeof(vindex->hdr.val_size), "%d", (int)vindex->tabsize_used); g_snprintf(vindex->hdr.key_trak, sizeof(vindex->hdr.key_trak), "TRAK"); g_snprintf(vindex->hdr.val_trak, sizeof(vindex->hdr.val_trak), "%d", (int)vindex->track); g_snprintf(vindex->hdr.key_ftot, sizeof(vindex->hdr.key_ftot), "FTOT"); g_snprintf(vindex->hdr.val_ftot, sizeof(vindex->hdr.val_ftot), "%d", (int)vindex->total_frames); g_snprintf(vindex->hdr.key_deco, sizeof(vindex->hdr.key_deco), "DECO"); g_snprintf(vindex->hdr.val_deco, sizeof(vindex->hdr.val_deco), "%s", decoder_name); g_snprintf(vindex->hdr.key_mtim, sizeof(vindex->hdr.key_mtim), "MTIM"); g_snprintf(vindex->hdr.val_mtim, sizeof(vindex->hdr.val_mtim), "%ld", (long)vindex->mtime); g_snprintf(vindex->hdr.key_flen, sizeof(vindex->hdr.key_flen), "FLEN"); g_snprintf(vindex->hdr.val_flen, sizeof(vindex->hdr.val_flen), "%d", l_flen); vindex->videoindex_filename = p_build_videoindex_filename(filename, vindex->track, decoder_name); if(vindex->videoindex_filename) { fp = g_fopen(vindex->videoindex_filename, "wb"); if(fp) { /* write HEAEDR */ fwrite(&vindex->hdr, 1, sizeof(vindex->hdr), fp); /* write VIDEOFILE_URI + terminating \0 character(s) */ { gchar *uri_buffer; uri_buffer = g_malloc0(l_flen); g_snprintf(uri_buffer, l_flen, "%s", vindex->videofile_uri); fwrite(uri_buffer, 1, l_flen, fp); g_free(uri_buffer); } /* write offset table */ fwrite(vindex->ofs_tab, 1, sizeof(t_GVA_IndexElem) * vindex->tabsize_used, fp); fclose(fp); return(TRUE); } else { gint l_errno; l_errno = errno; g_message(_("ERROR: Failed to write videoindex file\n" "file: '%s'\n" "%s") , vindex->videoindex_filename , g_strerror (l_errno)); } } return (FALSE); } /* end GVA_save_videoindex */ /* ---------------------------------- * GVA_debug_print_videoindex * ---------------------------------- */ void GVA_debug_print_videoindex(t_GVA_Handle *gvahand) { t_GVA_Videoindex *vindex; vindex = gvahand->vindex; p_debug_print_videoindex(vindex); } /* end GVA_debug_print_videoindex */ gimp-gap-2.6.0+dfsg.orig/libgapvidapi/gap_vid_api_mpeg3.c0000644000175000017500000012214411212030253023105 0ustar thibautthibaut/* gap_vid_api_mpeg3.c * * * GAP Video read API implementation of libmpeg3 * based wrappers to read various MPEG encoded videofile formats * * 2004.04.12 hof added libmpeg3 specific TOC file support * 2004.04.03 hof upgrade to libmpeg3-1.5.4 * - mpeg3_seek_percentage no longer supported * - MMX support sometimes delivers stripes of noise when frames are read * so we dont use MMX at all any more. * 2003.05.09 hof created * * */ /* ================================================ MPEG3 * libmpeg3 MPEG3 * ================================================ MPEG3 * ================================================ MPEG3 */ #ifdef ENABLE_GVA_LIBMPEG3 #include "libmpeg3.h" #define GVA_LIBMPEG3_DECODER_NAME "libmpeg3" typedef struct t_GVA_mpeg3 { mpeg3_t *main_handle; mpeg3_t *raw_handle; gint32 raw_pos; unsigned long prev_code; /* previous code for raw chunk reads */ } t_GVA_mpeg3; static int p_mpeg3_gopseek(mpeg3_t* handle, gint32 seekto_frame, t_GVA_Handle *gvahand); static int p_mpeg3_emulate_seek(mpeg3_t* handle, gint32 seekto_frame, t_GVA_Handle *gvahand); static gboolean p_check_libmpeg3_toc_file(const char *filename); #ifndef G_OS_WIN32 static gboolean p_mpeg3_sig_workaround_fork(const char *filename); #endif #define GVA_PROCESS_EXIT_OK 0 #define GVA_PROCESS_EXIT_FAILURE 1 #ifndef G_OS_WIN32 /* ----------------------------- * p_mpeg3_sig_handler * ----------------------------- */ static void p_mpeg3_sig_handler(int sig_num) { printf("GVA_MP3: CILD SIG HANDLER workaround libmpeg3 close crash captured\n"); exit (GVA_PROCESS_EXIT_FAILURE); } /* end p_mpeg3_sig_handler */ /* ----------------------------- * p_mpeg3_sig_workaround_fork * ----------------------------- * call libmpeg3 open/close sequence as own * process, and deliver FALSE when the process has crashed */ static gboolean p_mpeg3_sig_workaround_fork(const char *filename) { pid_t l_pid; int l_status; l_pid = fork(); if(l_pid == 0) { mpeg3_t *tmp_handle; gint l_rc; char *l_filename; int l_error_return; /* here we are in the forked child process * where we install our own signal handlers */ l_rc = GVA_PROCESS_EXIT_FAILURE; l_filename = g_strdup(filename); signal(SIGBUS, p_mpeg3_sig_handler); signal(SIGSEGV, p_mpeg3_sig_handler); signal(SIGFPE, p_mpeg3_sig_handler); if(gap_debug) printf("GVA_MP3: CILD process before mpeg3_open\n"); tmp_handle = mpeg3_open(l_filename, &l_error_return); if(gap_debug) printf("GVA_MP3: CILD process after mpeg3_open\n"); if(tmp_handle) { if(gap_debug) printf("GVA_MP3: CILD process before mpeg3_close\n"); mpeg3_close(tmp_handle); /* this call causes the crash (sometimes) */ if(gap_debug) printf("GVA_MP3: CILD process after mpeg3_close\n"); if (l_error_return == 0) { l_rc = GVA_PROCESS_EXIT_OK; /* retcode for OK */ } } g_free(l_filename); exit (l_rc); } if(l_pid < 0) { if(gap_debug) printf("GVA_MP3: PARENT process fork failed\n"); /* negative pid indicates error to fork a child process */ return (FALSE); } if(gap_debug) printf("GVA_MP3: PARENT before waitpid(%d)\n", (int)l_pid); waitpid(l_pid, &l_status, 0); if(gap_debug) printf("GVA_MP3: PARENT after waitpid(%d) status:%d\n", (int)l_pid, (int)l_status); if(l_status == 0) { if(gap_debug) printf("GVA_MP3: PARENT child normal end(%d)\n", (int)l_pid); return(TRUE); } if(gap_debug) printf("GVA_MP3: PARENT child crashed (%d)\n", (int)l_pid); return(FALSE); } /* end p_mpeg3_sig_workaround_fork */ #endif /* ----------------------------- * p_wrapper_mpeg3_check_sig * ----------------------------- */ gboolean p_wrapper_mpeg3_check_sig(char *filename) { int major; int minor; int release; gboolean version_ok; gboolean sig_ok; major = mpeg3_major(); minor = mpeg3_minor(); release = mpeg3_release(); version_ok = TRUE; if(major < 1) { version_ok = FALSE; } else { if(major == 1) { if(minor < 5) { version_ok = FALSE; } else { if((minor == 5) && (release < 4)) { version_ok = FALSE; } } } } if(version_ok) { if(gap_debug) { printf("GVA info: the GAP Video API was linked with " " libmpeg3 %d.%d.%d (reqired version is 1.5.4 or better)\n" ,major ,minor ,release ); } } else { printf("## GVA WARNING: the GAP Video API was linked with " " an old version of libmpeg3 %d.%d.%d (reqired version is 1.5.4 or better)\n" " (the libmpeg3 based decoder is not available)" ,major ,minor ,release ); return (FALSE); } /* mpeg3_check_sig returns 1 if the file is compatible (MPEG1 or 2) */ sig_ok = mpeg3_check_sig(filename); #ifndef G_OS_WIN32 if(sig_ok) { gchar *libmpeg3_workaround; gboolean libmpeg3_workaround_enabled; libmpeg3_workaround_enabled = TRUE; /* enable per default if nothing configured in gimprc */ libmpeg3_workaround = gimp_gimprc_query("video-workaround-for-libmpeg3-close-bug"); if(libmpeg3_workaround) { libmpeg3_workaround_enabled = FALSE; if ((*libmpeg3_workaround == 'y') || (*libmpeg3_workaround == 'Y')) { libmpeg3_workaround_enabled = TRUE; } g_free(libmpeg3_workaround); } if(libmpeg3_workaround_enabled) { /* workaround: (available for UNIX systems only) * libmpeg3 does sometimes crash on close. * (some mpeg1 files encoded by ffmpeg) * this code tries open close sequence in a separated process * * to catch those crashes, and deliver sig_ok FALSE * in case of crash) */ sig_ok = p_mpeg3_sig_workaround_fork(filename); } } #endif return (sig_ok); } /* end p_wrapper_mpeg3_check_sig */ /* ----------------------------- * p_wrapper_mpeg3_open_read * ----------------------------- * - fill t_GVA_Handle with informations (Audio + Video) * - libmpeg3 typical tocfiles for fast seek access are supported. */ void p_wrapper_mpeg3_open_read(char *in_filename, t_GVA_Handle *gvahand) { t_GVA_mpeg3* handle; gint repeat_count; char *filename; char *tocfile; if(gap_debug) printf("p_wrapper_mpeg3_open_read: START in_filename: %s\n", in_filename); filename = in_filename; /* test TOCFILE and if frame exact positioning available */ { if(p_check_libmpeg3_toc_file(in_filename)) { if(gap_debug) printf("OPEN: tocfile %s OK (fast seek via mpeg3_set_frame is supported)\n", in_filename); gvahand->emulate_seek = FALSE; } else { /* check if there is a matching TOCFILE */ tocfile = GVA_build_video_toc_filename(in_filename, GVA_LIBMPEG3_DECODER_NAME); if(p_check_libmpeg3_toc_file(tocfile)) { if(gap_debug) printf("OPEN: additional tocfile: %s AVAILABLE (fast seek via mpeg3_set_frame is supported)\n", tocfile); gvahand->emulate_seek = FALSE; filename = tocfile; } else { if(gap_debug) printf("OPEN: %s is no tocfile (mpeg3_set_frame seek to frame NOT supported)\n", in_filename); gvahand->emulate_seek = TRUE; } } } handle = g_malloc0(sizeof(t_GVA_mpeg3)); handle->main_handle = NULL; handle->raw_handle = NULL; /* for reading compressed video chunks only */ handle->raw_pos = 0; /* start position is before frame 1 */ /* workaround: * sometimes open succeeds, but libmpeg3 does not recognize any video or audio channel * dont know whats wrong here. * as workaround this API tries repeart the open for 3 times (only if no tracks can be found) * hof: this happened in older libmpeg3 versions * */ for(repeat_count = 0; repeat_count < 3; repeat_count++) { int l_error_return; handle->main_handle = mpeg3_open(filename, &l_error_return); if(gap_debug) { printf("GVA: libmpeg3 OPEN handle->main_handle:%d l_error_return:%d\n" , (int)handle->main_handle , (int)l_error_return ); } if((handle->main_handle) && (l_error_return == 0)) { gvahand->decoder_handle = (void *)handle; gvahand->frame_bpp = 3; /* never use MMX, it sometimes delivers trashed frames * and has no advantages on modern CPU's at all * procedure mpeg3_set_mmx was removed since libmpeg3-1.8 */ /// mpeg3_set_mmx(handle->main_handle, FALSE); if(mpeg3_has_video(handle->main_handle)) { gvahand->vtracks = mpeg3_total_vstreams(handle->main_handle); gvahand->vid_track = CLAMP(gvahand->vid_track, 0, gvahand->vtracks -1); gvahand->total_frames = mpeg3_video_frames(handle->main_handle, (int)gvahand->vid_track); gvahand->framerate = mpeg3_frame_rate(handle->main_handle, (int)gvahand->vid_track); gvahand->width = mpeg3_video_width(handle->main_handle, (int)gvahand->vid_track); gvahand->height = mpeg3_video_height(handle->main_handle, (int)gvahand->vid_track); gvahand->aspect_ratio = mpeg3_aspect_ratio(handle->main_handle, (int)gvahand->vid_track); /* libmpeg3-1.5.4 has a bug and did always deliver apect ratio value 0.0 * the aspect was not recognized when it was there * tested with some DVD and MPEG1 videofiles */ /* printf("ASPECT RATIO: %f\n", (float)gvahand->aspect_ratio); */ if(gvahand->total_frames <= 1) { /* For DVD files, total_frames is 1 indicating that the number is unknown * We try to figure the number of frames using a guess based on filesize * as workaround */ gvahand->total_frames = p_guess_total_frames(gvahand); if(gap_debug) printf("GUESS TOTAL FRAMES %d\n", (int)gvahand->total_frames ); } } else { gvahand->total_frames = 0; gvahand->framerate = 1.0; gvahand->width = 0; gvahand->height = 0; } if(mpeg3_has_audio(handle->main_handle)) { gvahand->atracks = mpeg3_total_astreams(handle->main_handle); gvahand->aud_track = CLAMP(gvahand->aud_track, 0, gvahand->atracks -1); gvahand->samplerate = mpeg3_sample_rate(handle->main_handle, (int)gvahand->aud_track); gvahand->audio_cannels = mpeg3_audio_channels(handle->main_handle, (int)gvahand->aud_track); gvahand->total_aud_samples = mpeg3_audio_samples(handle->main_handle, (int)gvahand->aud_track); gvahand->audio_playtime_sec = (gdouble)gvahand->total_aud_samples / (gdouble)gvahand->samplerate; } if((gvahand->atracks > 0) || (gvahand->vtracks > 0)) { break; /* OK video and /or audio found */ } else { if(gap_debug) printf("GVA: mpeg3 Open problems attempt:%d\n", (int)repeat_count); mpeg3_close(handle->main_handle); /* workaround: close and try open another time */ if(gap_debug) printf("GVA: mpeg3 after close attempt:%d\n", (int)repeat_count); handle->main_handle = NULL; mpeg3_check_sig(filename); mpeg3_check_sig("dummy"); gvahand->decoder_handle = NULL; } } } /* end for repeat_count */ if(gvahand->vindex == NULL) { gvahand->vindex = GVA_load_videoindex(in_filename, gvahand->vid_track, GVA_LIBMPEG3_DECODER_NAME); if(gvahand->vindex) { if(gvahand->vindex->total_frames > 1) { /* we have a complete vindex and can * trust the total_frames in the vindex file */ gvahand->total_frames = gvahand->vindex->total_frames; gvahand->all_frames_counted = TRUE; } } } if(gvahand->decoder_handle == NULL) { if(handle) { g_free(handle); } } } /* end p_wrapper_mpeg3_open_read */ /* ----------------------------- * p_wrapper_mpeg3_close * ----------------------------- */ void p_wrapper_mpeg3_close(t_GVA_Handle *gvahand) { t_GVA_mpeg3 *handle; handle = (t_GVA_mpeg3 *)gvahand->decoder_handle; if(handle) { if(handle->main_handle) { mpeg3_close(handle->main_handle); } if(handle->raw_handle) { mpeg3_close(handle->raw_handle); } } } /* end p_wrapper_mpeg3_close */ /* ---------------------------------- * p_wrapper_mpeg3_get_next_frame * ---------------------------------- * TODO: * - Retocde evaluation (what is OK, EOF or ERROR ?) */ t_GVA_RetCode p_wrapper_mpeg3_get_next_frame(t_GVA_Handle *gvahand) { t_GVA_mpeg3 *handle; int l_rc; handle = (t_GVA_mpeg3 *)gvahand->decoder_handle; if(handle == NULL) { return(GVA_RET_ERROR); } if(handle->main_handle == NULL) { return(GVA_RET_ERROR); } /* Read a frame. The dimensions of the input area and output frame must be supplied. */ /* The frame is taken from the input area and scaled to fit the output frame in 1 step. */ /* Stream defines the number of the multiplexed stream to read. */ /* The last row of **output_rows must contain 4 extra bytes for scratch work. */ l_rc = mpeg3_read_frame(handle->main_handle ,gvahand->row_pointers /* Array of pointers to the start of each output row */ ,0 /* in_x Location in input frame to take picture */ ,0 /* in_y */ ,(int)gvahand->width ,(int)gvahand->height ,(int)gvahand->width /* Dimensions of output_rows */ ,(int)gvahand->height ,MPEG3_RGB888 /* One of the color model #defines MPEG3_RGB888 MPEG3_RGBA8888 */ ,(int)gvahand->vid_track /* stream */ ); if(l_rc == 0) { gvahand->current_frame_nr = gvahand->current_seek_nr; gvahand->current_seek_nr++; /* if we found more frames, increase total_frames */ gvahand->total_frames = MAX(gvahand->total_frames, gvahand->current_frame_nr); return(GVA_RET_OK); } if(l_rc == 1) { return(GVA_RET_EOF); } return(GVA_RET_ERROR); } /* end p_wrapper_mpeg3_get_next_frame */ /* ------------------------------ * p_wrapper_mpeg3_seek_frame * ------------------------------ * TODO: - Retocde evaluation (what is OK, EOF or ERROR ?) */ t_GVA_RetCode p_wrapper_mpeg3_seek_frame(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit) { t_GVA_mpeg3 *handle; int l_rc; long l_frame_pos; handle = (t_GVA_mpeg3 *)gvahand->decoder_handle; if(handle == NULL) { return(GVA_RET_ERROR); } if(handle->main_handle == NULL) { return(GVA_RET_ERROR); } switch(pos_unit) { case GVA_UPOS_FRAMES: l_frame_pos = (long)pos; break; case GVA_UPOS_SECS: l_frame_pos = (long)rint(pos * gvahand->framerate); break; case GVA_UPOS_PRECENTAGE: l_frame_pos = (long)GVA_percent_2_frame(gvahand->total_frames, pos); break; default: l_frame_pos = (long)pos; break; } if(l_frame_pos == gvahand->current_seek_nr) { /* dont need to seek */ l_rc = 0; if(gap_debug) printf("MPEG3_SEEK_FRAME(F): current_seek_nr:%d new_seek_nr:%d (NO SEEK)\n", (int)gvahand->current_seek_nr ,(int)l_frame_pos); } else { if(gap_debug) printf("MPEG3_SEEK_FRAME(F): current_seek_nr:%d new_seek_nr:%d (SEEK NEEDED)\n", (int)gvahand->current_seek_nr ,(int)l_frame_pos); if(gvahand->emulate_seek) { l_rc = p_mpeg3_emulate_seek(handle->main_handle, l_frame_pos -1, gvahand); } else { if (1==1) /* (gvahand->dirty_seek) */ { /* fast seek * (older libmpeg3 versions had aProblem: * a following read may deliver more or less thrashed images * until the next I frame is read in sequence) */ l_rc = mpeg3_set_frame(handle->main_handle, l_frame_pos, (int)gvahand->vid_track); } else { /* this dead code once was needed with older libmpeg3 versions * libmpeg3-1.5.4 seems to handle seek operations clean * without returning trash frames when seek to B or P frames */ l_rc = p_mpeg3_gopseek(handle->main_handle, l_frame_pos -1, gvahand); } } } if(l_rc == 0) { gvahand->current_seek_nr = l_frame_pos; return(GVA_RET_OK); } if(l_rc == 1) { return(GVA_RET_EOF); } return(GVA_RET_ERROR); } /* end p_wrapper_mpeg3_seek_frame */ /* ------------------------------ * p_wrapper_mpeg3_seek_audio * ------------------------------ * TODO: - Retocde evaluation (what is OK, EOF or ERROR ?) */ t_GVA_RetCode p_wrapper_mpeg3_seek_audio(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit) { t_GVA_mpeg3 *handle; int l_rc; long l_frame_pos; long l_sample_pos; handle = (t_GVA_mpeg3 *)gvahand->decoder_handle; if(handle == NULL) { return(GVA_RET_ERROR); } if(handle->main_handle == NULL) { return(GVA_RET_ERROR); } switch(pos_unit) { case GVA_UPOS_FRAMES: l_sample_pos = (long)GVA_frame_2_samples(gvahand->framerate, gvahand->samplerate, pos); break; case GVA_UPOS_SECS: l_sample_pos = (long)rint(pos / MAX(gvahand->samplerate, 1.0)); break; case GVA_UPOS_PRECENTAGE: l_frame_pos= (long)GVA_percent_2_frame(gvahand->total_frames, pos); l_sample_pos = (long)GVA_frame_2_samples(gvahand->framerate, gvahand->samplerate, l_frame_pos); break; default: l_sample_pos = 0; break; } /* seek to a sample in the stream gvahand->aud_track */ l_rc = mpeg3_set_sample(handle->main_handle, l_sample_pos, (int)gvahand->aud_track); if(l_rc == 0) { gvahand->current_sample = (gint32)l_sample_pos; return(GVA_RET_OK); } if(l_rc == 1) { return(GVA_RET_EOF); } return(GVA_RET_ERROR); } /* end p_wrapper_mpeg3_seek_audio */ /* ------------------------------ * p_wrapper_mpeg3_get_audio * ------------------------------ * TODO: - Retocde evaluation (what is OK, EOF or ERROR ?) */ t_GVA_RetCode p_wrapper_mpeg3_get_audio(t_GVA_Handle *gvahand ,gint16 *output_i ,gint32 channel ,gdouble samples ,t_GVA_AudPos mode_flag ) { t_GVA_mpeg3 *handle; int l_rc; handle = (t_GVA_mpeg3 *)gvahand->decoder_handle; if(handle == NULL) { return(GVA_RET_ERROR); } if(handle->main_handle == NULL) { return(GVA_RET_ERROR); } if(mode_flag == GVA_AMOD_FRAME) { p_wrapper_mpeg3_seek_audio(gvahand , (gdouble) gvahand->current_frame_nr , GVA_UPOS_FRAMES ); } if(mode_flag == GVA_AMOD_REREAD) { l_rc = mpeg3_reread_audio(handle->main_handle , NULL /* UNUSED Pointer to pre-allocated buffer of floats */ , (short *)output_i /* Pointer to pre-allocated buffer of int16's */ , (int) channel /* Channel to decode */ , (long) samples /* Number of samples to decode */ , (int) gvahand->aud_track /* Stream containing the channel */ ); } else { l_rc = mpeg3_read_audio(handle->main_handle , NULL /* UNUSED Pointer to pre-allocated buffer of floats */ , (short *)output_i /* Pointer to pre-allocated buffer of int16's */ , (int) channel /* Channel to decode */ , (long) samples /* Number of samples to decode */ , (int) gvahand->aud_track /* Stream containing the channel */ ); } if(l_rc == 0) { if(mode_flag != GVA_AMOD_REREAD) { gvahand->current_sample += samples; /* keep track of current sample position */ } return(GVA_RET_OK); } if(l_rc == 1) { return(GVA_RET_EOF); } return(GVA_RET_ERROR); } /* end p_wrapper_mpeg3_get_audio */ /* ---------------------------------- * p_wrapper_mpeg3_count_frames * ---------------------------------- */ t_GVA_RetCode p_wrapper_mpeg3_count_frames(t_GVA_Handle *gvahand) { gint32 l_total_frames; t_GVA_Videoindex *vindex; gvahand->percentage_done = 0.0; gvahand->cancel_operation = FALSE; /* reset cancel flag */ if(p_check_libmpeg3_toc_file(gvahand->filename)) { if(gap_debug) { printf("gap_mpeg3_count_frames NOP: filename: %s\n" , gvahand->filename); printf("is already a libmpeg3 TOC file\n"); fflush(stdout); } return(GVA_RET_OK); } l_total_frames = 0; if(gap_debug) { printf("gap_mpeg3_count_frames filename: %s\n", gvahand->filename); fflush(stdout); } if(gvahand->vindex == NULL) { gvahand->vindex = GVA_load_videoindex(gvahand->filename, gvahand->vid_track, GVA_LIBMPEG3_DECODER_NAME); } if(gvahand->vindex) { if((gvahand->vindex->total_frames > 0) && (gvahand->vindex->track == gvahand->vid_track)) { /* we already have a valid videoindex that contains the real total number */ gvahand->total_frames = gvahand->vindex->total_frames; gvahand->all_frames_counted = TRUE; /* for libmpeg3 implementation we need a 2.nd file, * the .toc file that does the job for fast seek access by libmeg3 internal methods * (the videoindex_file is just used to store the total_frames information, * that is not available in the .toc file) */ gvahand->vindex->tocfile = GVA_build_video_toc_filename(gvahand->filename, GVA_LIBMPEG3_DECODER_NAME); if(p_check_libmpeg3_toc_file(gvahand->vindex->tocfile)) { /* close video and switch to the TOC file */ if(gap_debug) { printf("gap_mpeg3_count_frames REOPEN using tocfile: %s\n" , gvahand->vindex->tocfile ); fflush(stdout); } p_wrapper_mpeg3_close(gvahand); p_wrapper_mpeg3_open_read(gvahand->vindex->tocfile, gvahand); return(GVA_RET_OK); } } /* throw away existing videoindex (because it is unusable) */ GVA_free_videoindex(&gvahand->vindex); } if(gap_debug) { printf("gap_mpeg3_count_frames filename: CREATE index & TOC-file\n"); fflush(stdout); } vindex = NULL; /* create_vindex */ { gvahand->vindex = GVA_new_videoindex(); vindex = gvahand->vindex; if(vindex) { vindex->tabtype = GVA_IDX_TT_GINT64; vindex->ofs_tab = g_new(t_GVA_IndexElem, GVA_VIDINDEXTAB_BLOCK_SIZE); vindex->track = gvahand->vid_track; if(vindex->ofs_tab) { vindex->tabsize_allocated = GVA_VIDINDEXTAB_BLOCK_SIZE; } } } /* create the libmpeg3 specific TOC file */ if(vindex) { vindex->tocfile = GVA_build_video_toc_filename(gvahand->filename, GVA_LIBMPEG3_DECODER_NAME); /* check if writeable by creating an empty toc file first */ { FILE *fp; gint l_errno; fp = g_fopen(vindex->tocfile, "wb"); if(fp) { int argc; char *argv[3]; fclose(fp); argc = 3; argv[0] = g_strdup("GVA_mpeg3toc"); argv[1] = g_strdup(gvahand->filename); argv[2] = g_strdup(vindex->tocfile); GVA_create_libmpeg3_toc(argc, argv, gvahand, &l_total_frames); g_free(argv[0]); g_free(argv[1]); g_free(argv[2]); } else { l_errno = errno; g_message(_("ERROR: Failed to write videoindex tocfile\n" "tocfile: '%s'\n" "%s") , vindex->tocfile , g_strerror (l_errno)); gvahand->cancel_operation = TRUE; } } if(gvahand->cancel_operation) { /* delete uncomplete TOC file * (dont know if libmpeg3 can use unfinished TOC files) */ g_remove(vindex->tocfile); } else { if(gap_debug) printf("GOT total_frames: %d\n", (int)l_total_frames); vindex->total_frames = l_total_frames; /* close video and switch to the TOC file */ p_wrapper_mpeg3_close(gvahand); p_wrapper_mpeg3_open_read(vindex->tocfile, gvahand); } } gvahand->percentage_done = 0.0; if(vindex) { if(gap_debug) { printf("p_wrapper_ffmpeg_count_frames: before GVA_save_videoindex\n"); printf("p_wrapper_ffmpeg_count_frames: gvahand->filename:%s\n", gvahand->filename); } if(gvahand->cancel_operation) { /* because of cancel the total_frames is still unknown * (vindex->total_frames == 0 is the indicator for incomplete index) * For libmpeg3: videoindex is just used to store total_frames info * so we dont save uncomplete videoindex file */ vindex->total_frames = 0; } else { GVA_save_videoindex(vindex, gvahand->filename, GVA_LIBMPEG3_DECODER_NAME); } } if(!gvahand->cancel_operation) { gvahand->total_frames = l_total_frames; gvahand->all_frames_counted = TRUE; } else { gvahand->total_frames = MAX(gvahand->total_frames, l_total_frames); gvahand->cancel_operation = FALSE; /* reset cancel flag */ return(GVA_RET_ERROR); } return(GVA_RET_OK); } /* end p_wrapper_mpeg3_count_frames */ /* ---------------------------------- * p_wrapper_mpeg3_seek_support * ---------------------------------- */ t_GVA_SeekSupport p_wrapper_mpeg3_seek_support(t_GVA_Handle *gvahand) { return(GVA_SEEKSUPP_VINDEX); } /* end p_wrapper_mpeg3_seek_support */ /* ------------------------------- * p_wrapper_mpeg3_get_video_chunk * ------------------------------- * read video_frame_chunk at frame_nr * we use a separate handle (raw_handle) for mpeg3 file access * to keep positions of the main_handle unaffected. * further we do not use seek ops * to get the exact frame numbers. */ t_GVA_RetCode p_wrapper_mpeg3_get_video_chunk(t_GVA_Handle *gvahand , gint32 frame_nr , unsigned char *chunk , gint32 *size , gint32 max_size) { t_GVA_mpeg3 *handle; int l_rc; long l_size; unsigned long code; unsigned char *buffer; int l_error_return; if(frame_nr < 1) { /* illegal frame_nr (first frame starts at Nr 1 */ return(GVA_RET_ERROR); } handle = (t_GVA_mpeg3 *)gvahand->decoder_handle; if(handle == NULL) { return(GVA_RET_ERROR); } if(handle->main_handle == NULL) { return(GVA_RET_ERROR); } if(handle->raw_handle != NULL) { if(handle->raw_pos >= frame_nr) { mpeg3_close(handle->raw_handle); handle->raw_handle = NULL; } } if(handle->raw_handle == NULL) { handle->raw_handle = mpeg3_open_copy(gvahand->filename, handle->main_handle, &l_error_return); if((handle->raw_handle == NULL) || (l_error_return != 0)) { return(GVA_RET_ERROR); } handle->raw_pos = 0; handle->prev_code = 0; } buffer = g_malloc(max_size); while (TRUE) { /* Read the next compressed frame including headers. */ /* Store the size in size and return a 1 if error. */ /* Stream defines the number of the multiplexed stream to read. */ l_rc = mpeg3_read_video_chunk(handle->raw_handle , buffer /* out: unsigned char *output */ , &l_size /* out: size of the chunk */ , (long) max_size ,(int)gvahand->vid_track /* stream */ ); if(l_rc == 0) { handle->raw_pos++; code = (unsigned long)buffer[l_size - 4] << 24; code |= (unsigned long)buffer[l_size - 3] << 16; code |= (unsigned long)buffer[l_size - 2] << 8; code |= (unsigned long)buffer[l_size - 1]; /* check if we have reached the wanted frame */ if(handle->raw_pos == frame_nr) { unsigned char *chunk_ptr; /* got start code of next frame at the end of the buffer ? */ if(handle->prev_code == MPEG3_PICTURE_START_CODE) { l_size -= 4; } *size = (gint32)l_size; chunk_ptr = chunk; if(handle->prev_code == MPEG3_PICTURE_START_CODE) { /* begin the chunk data with Picture start code * (from the end of prev. buffer) */ *size += 4; chunk_ptr[0] = (handle->prev_code >> 24) & 0xff; chunk_ptr[1] = (handle->prev_code >> 16) & 0xff; chunk_ptr[2] = (handle->prev_code >> 8) & 0xff; chunk_ptr[3] = handle->prev_code & 0xff; chunk_ptr += 4; } memcpy(chunk_ptr, buffer, l_size); handle->prev_code = code; g_free(buffer); return(GVA_RET_OK); } handle->prev_code = code; } else { g_free(buffer); if(l_rc == 1) { return(GVA_RET_EOF); } else { return(GVA_RET_ERROR); } } gvahand->percentage_done = (gdouble)handle->raw_pos / (gdouble)frame_nr; if(gvahand->do_gimp_progress) { gimp_progress_update (gvahand->percentage_done); } if(gvahand->fptr_progress_callback) { gvahand->cancel_operation = (*gvahand->fptr_progress_callback)(gvahand->percentage_done, gvahand->progress_cb_user_data); if(gvahand->cancel_operation) { break; } } } g_free(buffer); return(GVA_RET_ERROR); } /* end p_wrapper_mpeg3_get_video_chunk */ /* ----------------------------- * p_mpeg3_new_dec_elem * ----------------------------- * create a new decoder element and init with * functionpointers referencing the * LIBMPEG3 specific Procedures */ t_GVA_DecoderElem * p_mpeg3_new_dec_elem(void) { t_GVA_DecoderElem *dec_elem; dec_elem = g_malloc0(sizeof(t_GVA_DecoderElem)); if(dec_elem) { dec_elem->decoder_name = g_strdup(GVA_LIBMPEG3_DECODER_NAME); dec_elem->decoder_description = g_strdup("MPEG Decoder (MPEG1/2 video and system streams, DVD) (EXT: .mpg;.vob;.dat;.mpeg)"); dec_elem->fptr_check_sig = &p_wrapper_mpeg3_check_sig; dec_elem->fptr_open_read = &p_wrapper_mpeg3_open_read; dec_elem->fptr_close = &p_wrapper_mpeg3_close; dec_elem->fptr_get_next_frame = &p_wrapper_mpeg3_get_next_frame; dec_elem->fptr_seek_frame = &p_wrapper_mpeg3_seek_frame; dec_elem->fptr_seek_audio = &p_wrapper_mpeg3_seek_audio; dec_elem->fptr_get_audio = &p_wrapper_mpeg3_get_audio; dec_elem->fptr_count_frames = &p_wrapper_mpeg3_count_frames; dec_elem->fptr_seek_support = &p_wrapper_mpeg3_seek_support; dec_elem->fptr_get_video_chunk = &p_wrapper_mpeg3_get_video_chunk; dec_elem->next = NULL; } return (dec_elem); } /* end p_mpeg3_new_dec_elem */ /* * mpeg3 tool procedures * ------------------------------------- * ------------------------------------- */ /* ----------------------- * p_mpeg3_emulate_seek * ----------------------- * procedure to completly emulate frame seek by dummy reads * (is very slow but sets position to exact frame position * this is needed if we have no TOC file) */ #define GVA_CLEANSEEKSIZE 48 static int p_mpeg3_emulate_seek(mpeg3_t* handle, gint32 seekto_frame, t_GVA_Handle *gvahand) { gint32 l_clean_reads; gint32 l_dirty_reads; gint32 l_ii; int l_rc; mpeg3_t* seek_handle; char *dummy_y; char *dummy_u; char *dummy_v; int l_error_return; l_rc = 0; l_dirty_reads = 0; gvahand->percentage_done = 0.0001; if (seekto_frame < gvahand->current_seek_nr) { t_GVA_mpeg3* decoder_handle; l_clean_reads = seekto_frame; /* printf(" ++ 1 ++ p_mpeg3_emulate_seek before mpeg3_open_copy %s\n", gvahand->filename); */ /* bakward seek: reopen needed */ seek_handle = mpeg3_open_copy(gvahand->filename, handle, &l_error_return); /* printf(" ++ 2 ++ p_mpeg3_emulate_seek after mpeg3_open_copy %s\n", gvahand->filename); */ decoder_handle = (t_GVA_mpeg3*)gvahand->decoder_handle; if((seek_handle) && (l_error_return == 0)) { /* printf(" ++ 3 ++ p_mpeg3_emulate_seek before mpeg3_close\n"); */ mpeg3_close(decoder_handle->main_handle); decoder_handle->main_handle = seek_handle; } else { printf("p_mpeg3_emulate_seek(E): REOPEN ERROR filename: %s\n", gvahand->filename); } if(gap_debug) printf("p_mpeg3_emulate_seek(E): after REOPEN seek_handle: %d filename:%s\n", (int)seek_handle, gvahand->filename); } else { /* forward seek: continue reading * after open gvahand->current_seek_nr points to 1 (before the 1st frame) */ seek_handle = handle; l_clean_reads = 1 + (seekto_frame - gvahand->current_seek_nr); } if(l_clean_reads > 0) { /* after (re)open we must start with a clean read * (never start with a dirty read (because ist does not advance position as expected) */ l_clean_reads--; l_rc = mpeg3_read_yuvframe_ptr(seek_handle , &dummy_y , &dummy_u , &dummy_v ,(int)gvahand->vid_track ); } if (l_clean_reads > GVA_CLEANSEEKSIZE) { l_dirty_reads = l_clean_reads - GVA_CLEANSEEKSIZE; l_clean_reads = GVA_CLEANSEEKSIZE; } if(gap_debug) { printf("p_mpeg3_emulate_seek(E): current_seek_nr: %d seekto_frame: %d seek_handle:%d l_clean_reads: %d l_dirty_reads: %d\n" , (int)gvahand->current_seek_nr , (int)seekto_frame , (int)seek_handle , (int)l_clean_reads , (int)l_dirty_reads ); } /* dirty read ops without decoding at all */ if(l_dirty_reads > 0) { guchar *dummy_buffer; long dummy_buffer_size; long chunk_size; /* buffer large enough for one uncompressed frame */ dummy_buffer_size = mpeg3_video_width(seek_handle, (int)gvahand->vid_track) * mpeg3_video_height(seek_handle, (int)gvahand->vid_track) * 3; dummy_buffer = g_malloc(dummy_buffer_size); for(l_ii = 0; l_ii < l_dirty_reads; l_ii++) { /* read one frame (we use the comressed chunk * because this is a dummy read to skip frames only) */ l_rc = mpeg3_read_video_chunk(seek_handle, dummy_buffer, &chunk_size, dummy_buffer_size, gvahand->vid_track ); if(0 != l_rc) { break; /* eof, or fetch error */ } gvahand->percentage_done = (gdouble)l_ii / (l_clean_reads + l_dirty_reads); if(gvahand->do_gimp_progress) { gimp_progress_update (gvahand->percentage_done); } if(gvahand->fptr_progress_callback) { gvahand->cancel_operation = (*gvahand->fptr_progress_callback)(gvahand->percentage_done, gvahand->progress_cb_user_data); if(gvahand->cancel_operation) { return(-1); } } } g_free(dummy_buffer); } /* clean read ops with native yuv decoding */ for(l_ii = 0; l_ii < l_clean_reads; l_ii++) { /* Read a frame in the native color model used by the stream. */ /* The Y, U, and V planes are not copied but the _output pointers */ /* are redirected to the frame buffer. */ l_rc = mpeg3_read_yuvframe_ptr(seek_handle , &dummy_y , &dummy_u , &dummy_v ,(int)gvahand->vid_track ); if(l_rc != 0) { break; } gvahand->percentage_done = (gdouble)(l_ii + l_dirty_reads) / (l_clean_reads + l_dirty_reads); if(gvahand->do_gimp_progress) { gimp_progress_update (gvahand->percentage_done); } if(gvahand->fptr_progress_callback) { gvahand->cancel_operation = (*gvahand->fptr_progress_callback)(gvahand->percentage_done, gvahand->progress_cb_user_data); if(gvahand->cancel_operation) { return(-1); } } } gvahand->percentage_done = 0.0; return(l_rc); } /* end p_mpeg3_emulate_seek */ /* ----------------------- * p_mpeg3_gopseek DEPRECATED * ----------------------- * workaround procedure to perform frame seek * with a combination of seek and some dummy reads. * to avoid trashed images in subsequent read ops. * * hof: maybe i can drop that procedure * if tests with the new libmpeg3-1.5.4 work * without this workaround */ #define GVA_GOPSEEKSIZE 24 static int p_mpeg3_gopseek(mpeg3_t* handle, gint32 seekto_frame, t_GVA_Handle *gvahand) { gint32 l_gopseek; gint32 l_ii; gint32 l_clean_read; int l_rc; gdouble l_progress_step; mpeg3_t* seek_handle; t_GVA_mpeg3* decoder_handle; int l_error_return; l_rc = 0; l_gopseek = MAX((seekto_frame - GVA_GOPSEEKSIZE), 1); if(gap_debug) { printf("p_mpeg3_gopseek(F): current_seek_nr: %d seekto_frame: %d l_gopseek: %d\n" , (int)gvahand->current_seek_nr , (int)seekto_frame , (int)l_gopseek ); } gvahand->percentage_done = 0.0001; if(l_gopseek == 1) { seek_handle = mpeg3_open_copy(gvahand->filename, handle, &l_error_return); if((seek_handle) && (l_error_return == 0)) { decoder_handle = (t_GVA_mpeg3*)gvahand->decoder_handle; mpeg3_close(decoder_handle->main_handle); decoder_handle->main_handle = seek_handle; mpeg3_set_frame(seek_handle, 1, gvahand->vid_track); /* Seek to 1.st frame */ } } else { seek_handle = handle; } if(seekto_frame > 1) { l_progress_step = 1.0 / MAX((gdouble)seekto_frame - (gdouble)l_gopseek, 1.0); if ( (l_gopseek < gvahand->current_seek_nr) || ((gvahand->current_seek_nr + GVA_GOPSEEKSIZE) <= seekto_frame) ) { if(gap_debug) printf("p_mpeg3_gopseek(F): (GOPSEEK NEEDED)\n"); /* perform (faster) seek if we have to do backstep * or if we have to do a bigstep forward (greater than GVA_GOPSEEKSIZE) */ l_rc = mpeg3_set_frame(seek_handle, l_gopseek +1, (int)gvahand->vid_track); gvahand->percentage_done += l_progress_step; if(gvahand->do_gimp_progress) { gimp_progress_update (gvahand->percentage_done); } if(gvahand->fptr_progress_callback) { gvahand->cancel_operation = (*gvahand->fptr_progress_callback)(gvahand->percentage_done, gvahand->progress_cb_user_data); if(gvahand->cancel_operation) { return(-1); } } } /* advance position by dummy read ops, and (hopefully catching an I frame) * (the number of dummy Reads will be GVA_GOPSEEKSIZE * or less if seekto_frame is near, or in the first few frames of the video) */ l_clean_read = seekto_frame - l_gopseek; if (gap_debug) printf(" clean_reads: %d\n", (int) l_clean_read); for(l_ii = 0; l_ii < l_clean_read; l_ii++) { char *dummy_y; char *dummy_u; char *dummy_v; /* Read a frame in the native color model used by the stream. */ /* The Y, U, and V planes are not copied but the _output pointers */ /* are redirected to the frame buffer. */ l_rc = mpeg3_read_yuvframe_ptr(seek_handle , &dummy_y , &dummy_u , &dummy_v ,(int)gvahand->vid_track ); if(l_rc != 0) { break; } gvahand->percentage_done += l_progress_step; if(gvahand->do_gimp_progress) { gimp_progress_update (gvahand->percentage_done); } if(gvahand->fptr_progress_callback) { gvahand->cancel_operation = (*gvahand->fptr_progress_callback)(gvahand->percentage_done, gvahand->progress_cb_user_data); if(gvahand->cancel_operation) { return(-1); } } } } gvahand->percentage_done = 0.0; return(l_rc); } /* end p_mpeg3_gopseek */ /* ------------------------- * p_check_libmpeg3_toc_file * ------------------------- * check libmpeg3 if file is libmpeg3 typical table of content file * starting with "TOC " * libmpeg3-1.5.4 require toc files for exact frame seek operations * the name of the toc file must then be passed to the * the mpeg3_open procedure (rather than the original videofile) * * toc files can be created explicite with the commandline tool mpeg3toc * (that is part of the libmpeg3 distribution) * or implicite by the GVA video Api procedures. */ gboolean p_check_libmpeg3_toc_file(const char *filename) { FILE *fp; gboolean l_rc; l_rc = FALSE; fp = g_fopen(filename, "rb"); if(fp) { char buff[5]; buff[0] = '\0'; fread(&buff[0], 1, 4, fp); buff[4] = '\0'; if(strncmp(&buff[0], "TOC ", 4) == 0) { l_rc = TRUE; } fclose(fp); } return (l_rc); } /* end p_check_libmpeg3_toc_file */ #endif /* ENABLE_GVA_LIBMPEG3 */ gimp-gap-2.6.0+dfsg.orig/libgapvidapi/gap_vid_api-intl.h0000644000175000017500000000137311212030253022763 0ustar thibautthibaut#ifndef __GAP_VID_API_INTL_H__ #define __GAP_VID_API_INTL_H__ #ifndef GETTEXT_PACKAGE #error "config.h must be included prior to gap_vid_api-intl.h" #endif #ifndef __GAP_INTL_H__ #include #define _(String) gettext (String) #ifdef gettext_noop # define N_(String) gettext_noop (String) #else # define N_(String) (String) #endif #ifndef HAVE_BIND_TEXTDOMAIN_CODESET # define bind_textdomain_codeset(Domain, Codeset) (Domain) #endif #define INIT_I18N() G_STMT_START{ \ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); \ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); \ textdomain (GETTEXT_PACKAGE); \ }G_STMT_END #endif /* __GAP_INTL_H__ */ #endif /* __GAP_VID_API_INTL_H__ */ gimp-gap-2.6.0+dfsg.orig/libgapvidapi/gap_vid_api_util.c0000644000175000017500000004042411212030253023047 0ustar thibautthibaut/* vid_api_util.c * * GAP Video read API implementation of utility procedures. * * 2004.03.14 hof created * */ #include /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX END fcache procedures */ /* CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC START copies gap_lib procedures */ /* -------------------- * p_get_filesize * -------------------- * get the filesize of a file. * in: fname: The filename of the file to check. * returns: The filesize. */ static gint32 p_get_filesize(char *fname) { struct stat stat_buf; if (0 != g_stat(fname, &stat_buf)) { printf ("stat error on '%s'\n", fname); return(0); } return((gint32)(stat_buf.st_size)); } /* end p_get_filesize */ /* ---------------------------------- * p_alloc_fname * ---------------------------------- * build the framname by concatenating basename, nr and extension. * the Number part has leading zeroes, depending * on filenames with the same basename and extension on disc. * * if no similar discfiles were found 6 digits (with leading zeroes) * are used per default. * * if a similar discfilename is found, the number of digits/leading zeroes * is set equal to the discfile found. * example: * basename == "frame_", nr == 5, ext == ".xcf" * - discfile was found with name: "frame_00001.xcf" * return ("frame_00001.xcf"); * * - discfile was found with name: "frame_001.xcf" * return ("frame_001.xcf"); * * return the resulting framename string * (the calling program should g_free this string * after use) */ static char* p_alloc_fname(char *basename, long nr, char *extension) { gchar *l_fname; gint l_digits_used; gint l_len; long l_nr_chk; if(basename == NULL) return (NULL); l_len = (strlen(basename) + strlen(extension) + 10); l_fname = (char *)g_malloc(l_len); l_digits_used = 6; if(nr < 10000000) { /* try to figure out if the frame numbers are in * 4-digit style, with leading zeroes "frame_0001.xcf" * or not "frame_1.xcf" */ l_nr_chk = nr; while(l_nr_chk >= 0) { /* check if frame is on disk with 6-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%06ld%s", basename, l_nr_chk, extension); if (g_file_test(l_fname, G_FILE_TEST_EXISTS)) { l_digits_used = 6; break; } /* check if frame is on disk with 8-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%08ld%s", basename, l_nr_chk, extension); if (g_file_test(l_fname, G_FILE_TEST_EXISTS)) { l_digits_used = 8; break; } /* check if frame is on disk with 7-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%07ld%s", basename, l_nr_chk, extension); if (g_file_test(l_fname, G_FILE_TEST_EXISTS)) { l_digits_used = 7; break; } /* check if frame is on disk with 5-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%05ld%s", basename, l_nr_chk, extension); if (g_file_test(l_fname, G_FILE_TEST_EXISTS)) { l_digits_used = 5; break; } /* check if frame is on disk with 4-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%04ld%s", basename, l_nr_chk, extension); if (g_file_test(l_fname, G_FILE_TEST_EXISTS)) { l_digits_used = 4; break; } /* check if frame is on disk with 3-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%03ld%s", basename, l_nr_chk, extension); if (g_file_test(l_fname, G_FILE_TEST_EXISTS)) { l_digits_used = 3; break; } /* check if frame is on disk with 2-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%02ld%s", basename, l_nr_chk, extension); if (g_file_test(l_fname, G_FILE_TEST_EXISTS)) { l_digits_used = 2; break; } /* now check for filename without leading zeroes in the framenumber */ g_snprintf(l_fname, l_len, "%s%ld%s", basename, l_nr_chk, extension); if (g_file_test(l_fname, G_FILE_TEST_EXISTS)) { l_digits_used = 1; break; } l_nr_chk--; /* if the frames nr and nr-1 were not found * try to check frames 1 and 0 * to limit down the loop to max 4 cycles */ if((l_nr_chk == nr -2) && (l_nr_chk > 1)) { l_nr_chk = 1; } } } else { /* numbers > 10000000 have 9 digits or more */ l_digits_used = 0; } g_free(l_fname); switch(l_digits_used) { case 6: l_fname = g_strdup_printf("%s%06ld%s", basename, nr, extension); break; case 8: l_fname = g_strdup_printf("%s%08ld%s", basename, nr, extension); break; case 7: l_fname = g_strdup_printf("%s%07ld%s", basename, nr, extension); break; case 5: l_fname = g_strdup_printf("%s%05ld%s", basename, nr, extension); break; case 4: l_fname = g_strdup_printf("%s%04ld%s", basename, nr, extension); break; case 3: l_fname = g_strdup_printf("%s%03ld%s", basename, nr, extension); break; case 2: l_fname = g_strdup_printf("%s%02ld%s", basename, nr, extension); break; default: l_fname = g_strdup_printf("%s%ld%s", basename, nr, extension); break; } return(l_fname); } /* end p_alloc_fname */ /* ---------------------------------------------------- * DELETE image * ---------------------------------------------------- * this procedure deletes a frame image * (only from the GIMP allocated Memory) * * further it makes a Workaround for a memory leak Problem in gimp-1.2.2 */ static void p_gimp_image_delete(gint32 image_id) { gimp_image_undo_disable(image_id); /* clear undo stack */ gimp_image_scale(image_id, 2, 2); if(gap_debug) printf("SCALED down to 2x2 id = %d (workaround for gimp_image-delete problem)\n", (int)image_id); gimp_image_undo_enable(image_id); /* clear undo stack */ gimp_image_delete(image_id); } /* CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC END copies of gap_lib procedures */ /* -------------------------------- * GVA_md5_string * -------------------------------- * name must point to a buffer of at least 32 Bytes * tht will be filled with the MD5 hashstring. */ void GVA_md5_string(char *name, const char *uri) { if(uri) { guchar digest[16]; guchar n; gint i; gimp_md5_get_digest (uri, -1, digest); for (i = 0; i < 16; i++) { n = (digest[i] >> 4) & 0xF; name[i * 2] = (n > 9) ? 'a' + n - 10 : '0' + n; n = digest[i] & 0xF; name[i * 2 + 1] = (n > 9) ? 'a' + n - 10 : '0' + n; } name[32] = '\0'; } } /* end GVA_md5_string */ /* -------------------------------- * GVA_filename_to_uri * -------------------------------- */ gchar* GVA_filename_to_uri(const char *filename) { gchar *uri; gchar *absolute; if (! g_path_is_absolute (filename)) { gchar *current; current = g_get_current_dir (); absolute = g_build_filename (current, filename, NULL); g_free (current); } else { absolute = g_strdup (filename); } uri = g_filename_to_uri (absolute, NULL, NULL); g_free (absolute); return uri; } /* end GVA_filename_to_uri */ /* -------------------------------- * GVA_util_check_mpg_frame_type * -------------------------------- * this procedure is typically used after the caller * has fetched uncompressed MPEG frames (using GVA_get_video_chunk) * to find out the type of the fetched frame. * in: buffer that should contain (at least) one compressed MPEG frame * that may be prefixed by Sequence Header or GOP header data * return: int frametype of the 1.st frame found in the buffer. * where 1 == intra, 2 == predicted, 3 == bidrectional predicted * -1 is returned if no frame was found. */ gint GVA_util_check_mpg_frame_type(unsigned char *buffer, gint32 buf_size) { unsigned long code; gint l_idx; gint l_frame_type; unsigned l_picture_number; gint32 l_max_check_size; l_max_check_size = buf_size; l_frame_type = GVA_MPGFRAME_UNKNOWN; l_picture_number = 0; code = 0; l_idx = 0; while(l_idx < l_max_check_size) { code <<= 8; code |= buffer[l_idx++]; if(code == GVA_MPGHDR_PICTURE_START_CODE) { /* found a picture start code * get next 10 bits for picture_number */ l_picture_number =(unsigned long)buffer[l_idx] << 2; l_picture_number |= (unsigned long)((buffer[l_idx +1] >> 6) & 0x3); /* get next 3 bits for frame_type information */ l_frame_type = ((buffer[l_idx +1] >> 3) & 0x7); break; } } if(gap_debug) { printf("GVA_util_check_mpg_frame_type: Frame type:%d local_picnum:%d l_idx:%d\n" ,(int)l_frame_type ,(int)l_picture_number ,(int)l_idx ); } return(l_frame_type); } /* end GVA_util_check_mpg_frame_type */ /* ------------------------------- * GVA_util_fix_mpg_timecode * ------------------------------- * In: buffer (in length buf_size) * the buffer should contain one compressed MPEG * frame, optionally prefixed by Sequence Header, GOP Header ... * If the buffer contains a GOP header, * the timecode in the GOP Header is replaced with a new timecode, * matching master_frame_nr at playbackrate of master_framerate (fps) * * the timecode is not replaced if the old code is all zero (00:00:00:00) */ void GVA_util_fix_mpg_timecode(unsigned char *buffer ,gint32 buf_size ,gdouble master_framerate ,gint32 master_frame_nr ) { unsigned long code; gint l_idx; code = 0; l_idx = 0; while(l_idx < buf_size) { code <<= 8; code |= buffer[l_idx++]; if(code == GVA_MPGHDR_GOP_START_CODE) { int hour, minute, second, frame; float carry; /* Get the time old time code (including the drop_frame flag in the 1.st byte) */ code = (unsigned long)buffer[l_idx] << 24; code |= (unsigned long)buffer[l_idx + 1] << 16; code |= (unsigned long)buffer[l_idx + 2] << 8; code |= (unsigned long)buffer[l_idx + 3]; hour = code >> 26 & 0x1f; minute = code >> 20 & 0x3f; second = code >> 13 & 0x3f; frame = code >> 7 & 0x3f; if(gap_debug) { printf("Timecode old: %02d:%02d:%02d:%02d ", hour, minute, second, frame); } if((hour == 0) && (minute == 0) && (second == 0) && (frame == 0)) { if(gap_debug) { printf("\n"); } } else { /* Write a new time code */ hour = (long)((float)(master_frame_nr - 1) / master_framerate / 3600); carry = hour * 3600 * master_framerate; minute = (long)((float)(master_frame_nr - 1 - carry) / master_framerate / 60); carry += minute * 60 * master_framerate; second = (long)((float)(master_frame_nr - 1 - carry) / master_framerate); carry += second * master_framerate; frame = (master_frame_nr - 1 - carry); buffer[l_idx] = ((code >> 24) & 0x80) | (hour << 2) | (minute >> 4); buffer[l_idx + 1] = ((code >> 16) & 0x08) | ((minute & 0xf) << 4) | (second >> 3); buffer[l_idx + 2] = ((second & 0x7) << 5) | (frame >> 1); buffer[l_idx + 3] = (code & 0x7f) | ((frame & 0x1) << 7); if(gap_debug) { printf("new: %02d:%02d:%02d:%02d\n", hour, minute, second, frame); } } break; } } } /* end GVA_util_fix_mpg_timecode */ /* ---------------------------------------- * GVA_util_calculate_mpeg_frameheader_size * ---------------------------------------- * scan the buffer for the 1st Mpeg picture start code. * all information from start of the buffer inclusive the picuture header * are considered as MPG header information. * (TODO: ) * * returns the size of frame/gop header or 0 if no header is present. */ gint32 GVA_util_calculate_mpeg_frameheader_size(unsigned char *buffer ,gint32 buf_size ) { unsigned long code; gint l_idx; gint l_frame_type; unsigned l_picture_number; gint32 l_max_check_size; gint32 l_hdr_size; l_max_check_size = buf_size; l_frame_type = GVA_MPGFRAME_UNKNOWN; l_picture_number = 0; l_hdr_size = 0; code = 0; l_idx = 0; while(l_idx < l_max_check_size) { code <<= 8; code |= buffer[l_idx++]; if(code == GVA_MPGHDR_PICTURE_START_CODE) { /* found a picture start code * get next 10 bits for picture_number */ l_picture_number =(unsigned long)buffer[l_idx] << 2; l_picture_number |= (unsigned long)((buffer[l_idx +1] >> 6) & 0x3); /* get next 3 bits for frame_type information */ l_frame_type = ((buffer[l_idx +1] >> 3) & 0x7); l_hdr_size = l_idx + 2; // TODO dont know if there are more bytes in the picture header ??? break; } } if(gap_debug) { printf("GVA_util_calculate_mpeg_frameheader_size: %d l_picture_number:%d frame_type:%d (1=I,2=P,3=B)\n" ,(int)l_hdr_size ,(int)l_picture_number ,(int)l_frame_type ); } return(l_hdr_size); } /* end GVA_util_calculate_mpeg_frameheader_size */ /* ---------------------------------------- * GVA_util_check_jpg_picture * ---------------------------------------- * scan the buffer for the 1st JPEG picture. * This implementation checks for the jpeg typical "magic number" * ff d8 ff * TODO: if libjpeg is available (#ifdef HAVE_??LIBJPG) * we colud try to a more sophisticated check * via jpeg_read_header from memory... * * returns TRUE if the specified buffer contains a JPEG image. */ gboolean GVA_util_check_jpg_picture(unsigned char *buffer ,gint32 buf_size ,gint32 max_check_size ,gint32 *hdr_size ) { gint l_idx; gint32 l_max_check_size; gboolean l_jpeg_magic_number_found; l_max_check_size = MAX(max_check_size, 1); l_jpeg_magic_number_found = FALSE; l_idx = 0; while(l_idx < l_max_check_size) { /* check magic number */ if ((buffer[l_idx] == 0xff) && (buffer[l_idx +1] == 0xd8) && (buffer[l_idx +2] == 0xff)) { *hdr_size = l_idx; l_jpeg_magic_number_found = TRUE; break; } l_idx++; } if(gap_debug) { printf("GVA_util_check_jpg_magic_number: l_jpeg_magic_number_found:%d at idx:%d hdr_size:%d\n" ,(int)l_jpeg_magic_number_found ,(int)l_idx ,(int)*hdr_size ); } return(l_jpeg_magic_number_found); } /* end GVA_util_check_jpg_picture */ /* ---------------------------------------- * GVA_util_check_png_picture * ---------------------------------------- * scan the buffer for the 1st PNG picture. * This implementation checks for the PNG typical "magic number" * 89 50 4e 47 (.PNG) * * returns TRUE if the specified buffer contains a PNG image. */ gboolean GVA_util_check_png_picture(unsigned char *buffer ,gint32 buf_size ,gint32 max_check_size ,gint32 *hdr_size ) { gint l_idx; gint32 l_max_check_size; gboolean l_png_magic_number_found; l_max_check_size = MAX(max_check_size, 1); l_png_magic_number_found = FALSE; l_idx = 0; while(l_idx < l_max_check_size) { /* check magic number */ if ((buffer[l_idx] == 0x89) && (buffer[l_idx +1] == 0x50) // 'P' && (buffer[l_idx +2] == 0x4e) // 'N' && (buffer[l_idx +3] == 0x47)) // 'G' { *hdr_size = l_idx; l_png_magic_number_found = TRUE; break; } l_idx++; } if(gap_debug) { printf("GVA_util_check_png_picture: l_png_magic_number_found:%d at idx:%d hdr_size:%d\n" ,(int)l_png_magic_number_found ,(int)l_idx ,(int)*hdr_size ); } return(l_png_magic_number_found); } /* end GVA_util_check_png_picture */ gimp-gap-2.6.0+dfsg.orig/libgapvidapi/Makefile.am0000644000175000017500000000132611212030253021436 0ustar thibautthibaut## Process this file with automake to produce Makefile.in libexecdir = $(GAPLIBDIR) noinst_LIBRARIES = libgapvidapi.a AM_CPPFLAGS = \ -DLOCALEDIR=\""$(LOCALEDIR)"\" INC_LIBGAPBASE = -I$(top_srcdir)/libgapbase INCLUDES = \ -I$(top_srcdir) \ $(GAPVIDEOAPI_EXTINCS) \ $(GLIB_CFLAGS) \ $(GIMP_CFLAGS) \ $(INC_LIBGAPBASE) \ -I$(includedir) libgapvidapi_a_SOURCES = \ gap_vid_api.c \ gap_vid_api.h # the current implementation includes this # .c sourcefiles in gap_vid_api.c (except example.c) EXTRA_DIST = \ gap_vid_api_gimp.c \ gap_vid_api_ffmpeg.c \ gap_vid_api_mpeg3.c \ gap_vid_api_mpeg3toc.c \ gap_vid_api_quicktime.c \ gap_vid_api_util.c \ gap_vid_api_vidindex.c \ gap_vid_api-intl.h \ example.c gimp-gap-2.6.0+dfsg.orig/libgapvidapi/Makefile.in0000644000175000017500000003442611212030534021460 0ustar thibautthibaut# Makefile.in generated by automake 1.10.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = libgapvidapi DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = LIBRARIES = $(noinst_LIBRARIES) AR = ar ARFLAGS = cru libgapvidapi_a_AR = $(AR) $(ARFLAGS) libgapvidapi_a_LIBADD = am_libgapvidapi_a_OBJECTS = gap_vid_api.$(OBJEXT) libgapvidapi_a_OBJECTS = $(am_libgapvidapi_a_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libgapvidapi_a_SOURCES) DIST_SOURCES = $(libgapvidapi_a_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BUILD_FFMPEG_LIBS = @BUILD_FFMPEG_LIBS@ BUILD_LIBMPEG3_LIB = @BUILD_LIBMPEG3_LIB@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXGMAKE = @EXGMAKE@ FFMPEG_DIR = @FFMPEG_DIR@ FFMPEG_LIBAVCODEC_A = @FFMPEG_LIBAVCODEC_A@ FFMPEG_LIBAVFORMAT_A = @FFMPEG_LIBAVFORMAT_A@ FFMPEG_LIBAVUTIL_A = @FFMPEG_LIBAVUTIL_A@ GAPLIBDIR = @GAPLIBDIR@ GAPVIDEOAPI_EXTINCS = @GAPVIDEOAPI_EXTINCS@ GAPVIDEOAPI_EXTLIBS = @GAPVIDEOAPI_EXTLIBS@ GAP_MAJOR_VERSION = @GAP_MAJOR_VERSION@ GAP_MICRO_VERSION = @GAP_MICRO_VERSION@ GAP_MINOR_VERSION = @GAP_MINOR_VERSION@ GAP_PTHREAD_LIB = @GAP_PTHREAD_LIB@ GAP_VERSION = @GAP_VERSION@ GAP_VERSION_WITH_DATE = @GAP_VERSION_WITH_DATE@ GAP_VINCS_FFMPEG = @GAP_VINCS_FFMPEG@ GAP_VINCS_MPEG3 = @GAP_VINCS_MPEG3@ GAP_VINCS_XVIDCORE = @GAP_VINCS_XVIDCORE@ GAP_VLIBS_FFMPEG = @GAP_VLIBS_FFMPEG@ GAP_VLIBS_MPEG3 = @GAP_VLIBS_MPEG3@ GAP_VLIBS_XVIDCORE = @GAP_VLIBS_XVIDCORE@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GIMP_CFLAGS = @GIMP_CFLAGS@ GIMP_DATA_DIR = @GIMP_DATA_DIR@ GIMP_LIBS = @GIMP_LIBS@ GIMP_PLUGIN_DIR = @GIMP_PLUGIN_DIR@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMAKE_AVAILABLE = @GMAKE_AVAILABLE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_NASM_ASSEMBLER = @HAVE_NASM_ASSEMBLER@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ INTLTOOL_MERGE = @INTLTOOL_MERGE@ INTLTOOL_PERL = @INTLTOOL_PERL@ INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBPREF = @LIBPREF@ LIBS = @LIBS@ LIBSUF = @LIBSUF@ LMPEG3_A = @LMPEG3_A@ LMPEG3_DIR = @LMPEG3_DIR@ LOCALEDIR = @LOCALEDIR@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ MSGMERGE = @MSGMERGE@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATHSEP = @PATHSEP@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WAVPLAY_SERVER = @WAVPLAY_SERVER@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = $(GAPLIBDIR) localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ noinst_LIBRARIES = libgapvidapi.a AM_CPPFLAGS = \ -DLOCALEDIR=\""$(LOCALEDIR)"\" INC_LIBGAPBASE = -I$(top_srcdir)/libgapbase INCLUDES = \ -I$(top_srcdir) \ $(GAPVIDEOAPI_EXTINCS) \ $(GLIB_CFLAGS) \ $(GIMP_CFLAGS) \ $(INC_LIBGAPBASE) \ -I$(includedir) libgapvidapi_a_SOURCES = \ gap_vid_api.c \ gap_vid_api.h # the current implementation includes this # .c sourcefiles in gap_vid_api.c (except example.c) EXTRA_DIST = \ gap_vid_api_gimp.c \ gap_vid_api_ffmpeg.c \ gap_vid_api_mpeg3.c \ gap_vid_api_mpeg3toc.c \ gap_vid_api_quicktime.c \ gap_vid_api_util.c \ gap_vid_api_vidindex.c \ gap_vid_api-intl.h \ example.c all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libgapvidapi/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu libgapvidapi/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libgapvidapi.a: $(libgapvidapi_a_OBJECTS) $(libgapvidapi_a_DEPENDENCIES) -rm -f libgapvidapi.a $(libgapvidapi_a_AR) libgapvidapi.a $(libgapvidapi_a_OBJECTS) $(libgapvidapi_a_LIBADD) $(RANLIB) libgapvidapi.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_vid_api.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-exec-am: install-html: install-html-am install-info: install-info-am install-man: install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-noinstLIBRARIES ctags distclean distclean-compile \ distclean-generic distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gimp-gap-2.6.0+dfsg.orig/libgapvidapi/gap_vid_api.c0000644000175000017500000023752311212030253022022 0ustar thibautthibaut/* gap_vid_api.c * * This API (GAP Video Api) provides basic READ functions to access * Videoframes of some sopported Videoformats. * * ------------------------ * API READ movie frames * ------------------------ * * video decoder libraries can be turned on (conditional compile) * by define the following: * * ENABLE_GVA_LIBMPEG3 * ENABLE_GVA_LIBQUICKTIME * ENABLE_GVA_LIBAVFORMAT * ENABLE_GVA_GIMP * * this is done via options passed to the configure script in the * gap main directory. the configure script saaves the * selected configuration as #define statements in the config.h file * * --- API master Procedures * gap_api_vid.c * * --- the library dependent wrapper modules * --- (the modules are included and compiled * --- as one unit with this main api sourcefile. * this helps to keep the number of external symbols small) * * gap_api_vid_quicktime.h * gap_api_vid_quicktime.c * gap_api_vid_mpeg3.h * gap_api_vid_mpeg3.c * gap_api_vid_avi.h * gap_api_vid_avi.c * --------------------------------------------- */ /* API access for GIMP-GAP frame sequences needs no external * libraries and is always enabled * (there is no configuration parameter for this "decoder" implementation) */ #define ENABLE_GVA_GIMP 1 /* ------------------------------------------------ * revision history * * 2004.04.25 (hof) integration into gimp-gap, using config.h * 2004.02.28 (hof) added procedures GVA_frame_to_buffer, GVA_delace_frame */ #include #include #include #include #include #include #include #include #include #include #include /* includes for UNIX fork-based workarond for the libmpeg3 crash on close bug */ #ifndef G_OS_WIN32 #include /* for fork */ #include #include #endif extern int gap_debug; /* ==0 ... dont print debug infos */ #include "gap_vid_api.h" #include "gap_vid_api_util.c" #include "gap_vid_api_vidindex.c" t_GVA_DecoderElem *GVA_global_decoder_list = NULL; /* max threshold for row mix algorithm (used for deinterlacing frames) * (510*510) + (256+256+256) */ #define MIX_MAX_THRESHOLD 260865 static void p_alloc_rowpointers(t_GVA_Handle *gvahand, t_GVA_Frame_Cache_Elem *fc_ptr); static t_GVA_Frame_Cache_Elem * p_new_frame_cache_elem(t_GVA_Handle *gvahand); static void p_drop_next_frame_cache_elem(t_GVA_Frame_Cache *fcache); static void p_drop_frame_cache(t_GVA_Handle *gvahand); static gint32 p_build_frame_cache(t_GVA_Handle *gvahand, gint32 frames_to_keep_cahed); static gdouble p_guess_total_frames(t_GVA_Handle *gvahand); static void p_register_all_decoders(void); static void p_gva_worker_close(t_GVA_Handle *gvahand); static t_GVA_RetCode p_gva_worker_get_next_frame(t_GVA_Handle *gvahand); static t_GVA_RetCode p_gva_worker_seek_frame(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit); static t_GVA_RetCode p_gva_worker_seek_audio(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit); static t_GVA_RetCode p_gva_worker_get_audio(t_GVA_Handle *gvahand ,gint16 *output_i /* preallocated buffer large enough for samples * siezeof gint16 */ ,gint32 channel /* audiochannel 1 upto n */ ,gdouble samples /* number of samples to read */ ,t_GVA_AudPos mode_flag /* specify the position where to start reading audio from */ ); static t_GVA_RetCode p_gva_worker_count_frames(t_GVA_Handle *gvahand); static t_GVA_RetCode p_gva_worker_get_video_chunk(t_GVA_Handle *gvahand , gint32 frame_nr , unsigned char *chunk , gint32 *size , gint32 max_size); static t_GVA_Handle * p_gva_worker_open_read(const char *filename, gint32 vid_track, gint32 aud_track ,const char *preferred_decoder ,gboolean disable_mmx ); /* --------------------------- * GVA_percent_2_frame * --------------------------- * 0.0% returns frame #1 * 100.0 % returns frame #total_frames */ gint32 GVA_percent_2_frame(gint32 total_frames, gdouble percent) { gint32 framenr; gdouble ffrnr; ffrnr = 1.5 + (percent / 100.0) * MAX(((gdouble)total_frames -1), 0); framenr = (gint32)ffrnr; if(gap_debug) printf("GVA_percent_2_frame %f #:%d\n", (float)percent, (int)framenr ); return(framenr); } /* end GVA_percent_2_frame */ /* --------------------------- * GVA_frame_2_percent * --------------------------- */ gdouble GVA_frame_2_percent(gint32 total_frames, gdouble framenr) { gdouble percent; percent = 100.0 * ((gdouble)MAX((framenr -1),0) / MAX((gdouble)(total_frames -1) ,1.0)); if(gap_debug) printf("GVA_frame_2_percent %f #:%d\n", (float)percent, (int)framenr ); return(CLAMP(percent, 0.0, 100.0)); } /* end GVA_frame_2_percent */ /* --------------------------- * GVA_frame_2_secs * --------------------------- */ gdouble GVA_frame_2_secs(gdouble framerate, gint32 framenr) { gdouble secs; secs = ((gdouble)framenr / MAX(framerate, 1.0) ); if(gap_debug) printf("GVA_frame_2_secs %f #:%d\n", (float)secs, (int)framenr ); return(secs); } /* end GVA_frame_2_secs */ /* --------------------------- * GVA_frame_2_samples * --------------------------- */ gdouble GVA_frame_2_samples(gdouble framerate, gint32 samplerate, gint32 framenr) { gdouble samples; samples = ((gdouble)framenr / MAX(framerate, 1.0) ) * (gdouble)samplerate; if(gap_debug) printf("GVA_frame_2_samples %f #:%d\n", (float)samples, (int)framenr ); return(samples); } /* end GVA_frame_2_samples */ /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX BEGIN fcache procedures */ /* ---------------------------------------------------- * GVA_debug_print_fcache * ---------------------------------------------------- */ void GVA_debug_print_fcache(t_GVA_Handle *gvahand) { t_GVA_Frame_Cache *fcache; t_GVA_Frame_Cache_Elem *fc_ptr; printf("GVA_debug_print_fcache: START\n" ); fcache = &gvahand->fcache; if(fcache->fc_current) { gint ii; printf("frame_cache_size: %d\n", (int)fcache->frame_cache_size); fc_ptr = (t_GVA_Frame_Cache_Elem *)fcache->fc_current; for(ii=0; ii < fcache->frame_cache_size; ii++) { printf(" [%d] ID:%d framenumber: %d (my_adr: %d next:%d prev:%d)\n" , (int)ii , (int)fc_ptr->id , (int)fc_ptr->framenumber , (int)fc_ptr , (int)fc_ptr->next , (int)fc_ptr->prev ); fc_ptr = (t_GVA_Frame_Cache_Elem *)fc_ptr->prev; if(fcache->fc_current == fc_ptr) { printf("STOP, we are back at startpoint of the ringlist\n\n"); return; } if(fc_ptr == NULL) { printf("internal error, ringlist is broken !!!!!!!!!\n\n"); return; } } printf("internal error, too many elements found (maybe ringlist is not linked properly !!\n\n"); return; } printf("fcache is empty (no current element found)\n"); } /* end GVA_debug_print_fcache */ /* ------------------------------ * p_alloc_rowpointers * ------------------------------ * allocate frame_data buffer (for RGB or RGBA imagedata) * and row pointers for each row * We must allocate 4 extra bytes in the last output_row. * This is scratch area for the MMX routines used by some decoder libs. */ static void p_alloc_rowpointers(t_GVA_Handle *gvahand, t_GVA_Frame_Cache_Elem *fc_ptr) { int ii, wwidth, wheight, bpp; wwidth = MAX(gvahand->width, 2); wheight = MAX(gvahand->height, 2); bpp = gvahand->frame_bpp; fc_ptr->frame_data = g_malloc(wwidth * wheight * bpp + 4); fc_ptr->row_pointers = g_malloc(sizeof(unsigned char*) * wheight); /* init row pointers */ for(ii = 0; ii < wheight; ii++) { fc_ptr->row_pointers[ii] = &fc_ptr->frame_data[ii * wwidth * bpp]; } } /* end p_alloc_rowpointers */ /* ---------------------------------------------------- * p_new_frame_cache_elem * ---------------------------------------------------- */ static t_GVA_Frame_Cache_Elem * p_new_frame_cache_elem(t_GVA_Handle *gvahand) { t_GVA_Frame_Cache_Elem *fc_ptr; fc_ptr = g_malloc0(sizeof(t_GVA_Frame_Cache_Elem)); gvahand->fcache.max_fcache_id++; fc_ptr->id = gvahand->fcache.max_fcache_id; fc_ptr->framenumber = -1; /* marker for unused element, framedata is allocated but not initialized */ fc_ptr->prev = fc_ptr; fc_ptr->next = fc_ptr; p_alloc_rowpointers(gvahand, fc_ptr); return (fc_ptr); } /* end p_new_frame_cache_elem */ /* ---------------------------------------------------- * p_drop_next_frame_cache_elem * ---------------------------------------------------- * drop the next (== oldest) element of the frame cache list */ static void p_drop_next_frame_cache_elem(t_GVA_Frame_Cache *fcache) { t_GVA_Frame_Cache_Elem *fc_ptr; if(fcache) { if(fcache->fc_current) { fc_ptr = (t_GVA_Frame_Cache_Elem *)fcache->fc_current->next; if(fc_ptr) { if(gap_debug) printf("p_drop_next_frame_cache_elem framenumber:%d\n", (int)fc_ptr->framenumber); if(fc_ptr != fcache->fc_current) { t_GVA_Frame_Cache_Elem *fc_nxt; /* the ring still has 2 or more elements * we must update prev pointer of the next element * and next pointer of the previous element */ fc_nxt = (t_GVA_Frame_Cache_Elem *)fc_ptr->next; fcache->fc_current->next = fc_nxt; fc_nxt->prev = fcache->fc_current; } else { /* we are dropping the last element, set fc_current pointer to NULL */ fcache->fc_current = NULL; } g_free(fc_ptr->frame_data); g_free(fc_ptr->row_pointers); g_free(fc_ptr); } } } } /* end p_drop_next_frame_cache_elem */ /* ---------------------------------------------------- * p_drop_frame_cache * ---------------------------------------------------- */ static void p_drop_frame_cache(t_GVA_Handle *gvahand) { t_GVA_Frame_Cache *fcache; if(gap_debug) printf("p_drop_frame_cache START\n"); fcache = &gvahand->fcache; if(fcache) { while(fcache->fc_current) { p_drop_next_frame_cache_elem(fcache); } } if(gap_debug) printf("p_drop_frame_cache END\n"); } /* end p_drop_frame_cache */ /* ---------------------------------------------------- * p_build_frame_cache * ---------------------------------------------------- * the frame cache is a double linked ringlist. * this procedure creates such a list (if we have none) * or changes the (existing) ringlist to the desired number of elements. * this is done by dropping the oldest elements (if we already have to much) * or adding new elements (if we have not enough elements) * * if the fcache does not exist (if fcache gvahand->fcache.fc_current == NULL) * it will be created. * the pointers * gvahand->frame_data * gvahand->row_pointers * are set to point at the 1.st (current) fcache element in that case. */ static gint32 p_build_frame_cache(t_GVA_Handle *gvahand, gint32 frames_to_keep_cahed) { t_GVA_Frame_Cache *fcache; t_GVA_Frame_Cache_Elem *fc_ptr; fcache = &gvahand->fcache; fcache->frame_cache_size = 0; if(fcache->fc_current) { fcache->frame_cache_size = 1; fc_ptr = (t_GVA_Frame_Cache_Elem *)fcache->fc_current->next; while(fcache->fc_current != fc_ptr) { fcache->frame_cache_size++; fc_ptr = (t_GVA_Frame_Cache_Elem *)fc_ptr->next; if(fc_ptr == NULL) { printf("API internal ERROR (frame cache is not linked as ring)\n"); exit(1); } } /* if cache is greater than wanted size drop the oldest (next) * elements until we have desired number of elements */ while(fcache->frame_cache_size > frames_to_keep_cahed) { p_drop_next_frame_cache_elem(fcache); fcache->frame_cache_size--; } } else { /* create the 1st element, ring-linked to itself */ fc_ptr = p_new_frame_cache_elem(gvahand); fc_ptr->prev = fc_ptr; fc_ptr->next = fc_ptr; fcache->fc_current = fc_ptr; gvahand->frame_data = fc_ptr->frame_data; gvahand->row_pointers = fc_ptr->row_pointers; fcache->frame_cache_size = 1; } /* if current cache is smaller than requested, add the missing elements */ while(fcache->frame_cache_size < frames_to_keep_cahed) { t_GVA_Frame_Cache_Elem *fc_nxt; /* add a new element after the current element in the pointerring */ fc_nxt = (t_GVA_Frame_Cache_Elem *)fcache->fc_current->next; fc_ptr = p_new_frame_cache_elem(gvahand); fc_ptr->prev = fcache->fc_current; fc_ptr->next = fc_nxt; fc_nxt->prev = fc_ptr; fcache->fc_current->next = fc_ptr; fcache->frame_cache_size++; } return(fcache->frame_cache_size); } /* end p_build_frame_cache */ /* ------------------------------------ * GVA_set_fcache_size * ------------------------------------ */ void GVA_set_fcache_size(t_GVA_Handle *gvahand ,gint32 frames_to_keep_cahed ) { if(gvahand->fcache.fcache_locked) { printf("GVA_set_fcache_size: IGNORED " "because fcache is locked by running SEEK_FRAME or GET_NEXT FRAME)\n"); return; /* dont touch the fcache while locked */ } if ((frames_to_keep_cahed > 0) && (frames_to_keep_cahed <= GVA_MAX_FCACHE_SIZE)) { /* re-adjust fcache size as desired by calling program */ p_build_frame_cache(gvahand, frames_to_keep_cahed); } else { printf("GVA_set_fcache_size: size must be an integer > 0 and <= %d (value %d is ignored)\n" , (int)GVA_MAX_FCACHE_SIZE , (int)frames_to_keep_cahed); } } /* end GVA_set_fcache_size */ /* ------------------------------------ * GVA_search_fcache * ------------------------------------ * search the frame cache for given framenumber * and set the pointers * gvahand->fc_frame_data * gvahand->fc_row_pointers * * to point to the disired frame in the frame cache. * please note: if framenumber is not found, * the pointers are set to the current frame * * RETURN: GVA_RET_OK (0) if OK, * GVA_RET_EOF (1) if framenumber not found in fcache, or fcache LOCKED * GVA_RET_ERROR on other errors */ t_GVA_RetCode GVA_search_fcache(t_GVA_Handle *gvahand ,gint32 framenumber ) { t_GVA_Frame_Cache *fcache; t_GVA_Frame_Cache_Elem *fc_ptr; if(gap_debug) printf("GVA_search_fcache: search for framenumber: %d\n", (int)framenumber ); if(gvahand->fcache.fcache_locked) { return(GVA_RET_EOF); /* dont touch the fcache while locked */ } /* init with framedata of current frame * (for the case that framenumber not available in fcache) */ gvahand->fc_frame_data = gvahand->frame_data; gvahand->fc_row_pointers = gvahand->row_pointers; fcache = &gvahand->fcache; if(fcache->fc_current) { fc_ptr = (t_GVA_Frame_Cache_Elem *)fcache->fc_current; while(1 == 1) { if(framenumber == fc_ptr->framenumber) { if(fc_ptr->framenumber >= 0) { gvahand->fc_frame_data = fc_ptr->frame_data; /* framedata of cached frame */ gvahand->fc_row_pointers = fc_ptr->row_pointers; return(GVA_RET_OK); /* OK */ } } /* try to get framedata from fcache ringlist, * by stepping backwards the frames that were read before */ fc_ptr = (t_GVA_Frame_Cache_Elem *)fc_ptr->prev; if(fcache->fc_current == fc_ptr) { return (GVA_RET_EOF); /* STOP, we are back at startpoint of the ringlist */ } if(fc_ptr == NULL) { return (GVA_RET_ERROR); /* internal error, ringlist is broken */ } } } /* ringlist not found */ return (GVA_RET_ERROR); } /* end GVA_search_fcache */ /* ------------------------------------ * GVA_search_fcache_by_index * ------------------------------------ * search the frame cache backwards by given index * where index 0 is the current frame, * index 1 is the prev handled frame * (dont use negative indexes !!) * and set the pointers * gvahand->fc_frame_data * gvahand->fc_row_pointers * * to point to the disired frame in the frame cache. * please note: if framenumber is not found, * the pointers are set to the current frame * * RETURN: GVA_RET_OK (0) if OK, * GVA_RET_EOF (1) if framenumber not found in fcache, or fcache LOCKED * GVA_RET_ERROR on other errors */ t_GVA_RetCode GVA_search_fcache_by_index(t_GVA_Handle *gvahand ,gint32 index ,gint32 *framenumber ) { t_GVA_Frame_Cache *fcache; t_GVA_Frame_Cache_Elem *fc_ptr; if(gap_debug) printf("GVA_search_fcache_by_index: search for INDEX: %d\n", (int)index ); if(gvahand->fcache.fcache_locked) { return(GVA_RET_EOF); /* dont touch the fcache while locked */ } /* init with framedata of current frame * (for the case that framenumber not available in fcache) */ *framenumber = -1; gvahand->fc_frame_data = gvahand->frame_data; gvahand->fc_row_pointers = gvahand->row_pointers; fcache = &gvahand->fcache; if(fcache->fc_current) { gint32 ii; fc_ptr = (t_GVA_Frame_Cache_Elem *)fcache->fc_current; for(ii=0; 1==1; ii++) { if(index == ii) { *framenumber = fc_ptr->framenumber; if(fc_ptr->framenumber < 0) { if(gap_debug) printf("GVA_search_fcache_by_index: INDEX: %d NOT FOUND (fnum < 0) ###########\n", (int)index ); return (GVA_RET_EOF); } gvahand->fc_frame_data = fc_ptr->frame_data; /* framedata of cached frame */ gvahand->fc_row_pointers = fc_ptr->row_pointers; if(gap_debug) printf("GVA_search_fcache_by_index: fnum; %d INDEX: %d FOUND ;;;;;;;;;;;;;;;;;;\n", (int)*framenumber, (int)index ); return(GVA_RET_OK); /* OK */ } /* try to get framedata from fcache ringlist, * by stepping backwards the frames that were read before */ fc_ptr = (t_GVA_Frame_Cache_Elem *)fc_ptr->prev; if(fcache->fc_current == fc_ptr) { if(gap_debug) printf("GVA_search_fcache_by_index: INDEX: %d NOT FOUND (ring done) ************\n", (int)index ); return (GVA_RET_EOF); /* STOP, we are back at startpoint of the ringlist */ } if(fc_ptr == NULL) { return (GVA_RET_ERROR); /* internal error, ringlist is broken */ } } } /* ringlist not found */ return (GVA_RET_ERROR); } /* end GVA_search_fcache_by_index */ /* -------------------- * p_guess_total_frames * -------------------- */ static gdouble p_guess_total_frames(t_GVA_Handle *gvahand) { gdouble l_guess; gdouble l_guess_framesize; gint l_len; if(gap_debug) printf ("p_guess_total_frames START\n"); if(gvahand->filename == NULL) { if(gap_debug) printf ("p_guess_total_frames gvahand->filename: IS NULL\n"); return(1); } if(gap_debug) printf ("p_guess_total_frames gvahand->filename:%s\n", gvahand->filename); l_len = strlen(gvahand->filename); if(l_len > 4) { const char *suffix; suffix = gvahand->filename + (l_len - 4); if((strcmp(suffix, ".ifo") == 0) || (strcmp(suffix, ".IFO") == 0)) { /* for .ifo files it is not a good idea to guess the number * of frames from the filesize. * .ifo are typically used on DVD to referre to a set of .vob files * that makes up the whole movie. * without parsing the .ifo file we can not guess the number of * total frames of the whole movie. * This primitive workaround assumes a constant number of frames */ if(gap_debug) printf ("p_guess_total_frames .ifo using fix total_frames 30000\n"); return (30000.0); } } /* very unprecise guess total frames by checking the filesize * and assume compression 1/50 per compressed frame. * - compression rate 1/40 is a common value, but may differ heavily depending * depending on the used codec and its quality settings. * - audiotracks are ignored for this guess * - we need a guess to update the percentage_done used for progress indication) */ l_guess_framesize = (gvahand->width * gvahand->height * 3) / 50.0; l_guess = (gdouble)p_get_filesize(gvahand->filename) / (l_guess_framesize * MAX(gvahand->vtracks, 1.0)) ; if(gap_debug) printf ("p_guess_total_frames GUESS total_frames: %d\n", (int)l_guess); return(l_guess); } /* end p_guess_total_frames */ /* -------------------------------------------------------------------------------------- * --------------------------------------- FILE(S) gap_api_vid_DECODERTYPE.c Starts here * -------------------------------------------------------------------------------------- */ /* ---------------------------------------------- * WRAPPER PROCEDURES for built in Video Decoders * ---------------------------------------------- */ /* ================================================ FFMPEG * FFMPEG (libavformat libavcodec) FFMPEG * ================================================ FFMPEG * ================================================ FFMPEG */ #ifdef ENABLE_GVA_LIBAVFORMAT #include "avformat.h" #include "gap_vid_api_ffmpeg.c" #endif /* ENABLE_GVA_LIBAVFORMAT */ /* ================================================ GIMP-GAP * gimp (singleframe access via gap/gimp) GIMP-GAP * ================================================ GIMP-GAP * ================================================ GIMP-GAP */ #ifdef ENABLE_GVA_GIMP #include "gap_vid_api_gimp.c" #endif /* ENABLE_GVA_GIMP */ /* ================================================ QUICKTIME * quicktime QUICKTIME * ================================================ QUICKTIME * ================================================ QUICKTIME */ #ifdef ENABLE_GVA_LIBQUICKTIME #include "gap_vid_api_quicktime.c" #endif /* ENABLE_GVA_LIBQUICKTIME */ /* ================================================ LIBMEG3 * libmpeg3 LIBMEG3 * ================================================ LIBMEG3 * ================================================ LIBMEG3 */ #ifdef ENABLE_GVA_LIBMPEG3 #include "gap_vid_api_mpeg3toc.c" #include "gap_vid_api_mpeg3.c" #endif /* ENABLE_GVA_LIBMPEG3 */ /* ############################################################################### * ############################################################################### * ############################################################################### * ############################################################################### * * * -------------------------------------------------------------------------------------- * ---------------------------- API.c starts here * -------------------------------------------------------------------------------------- */ /* --------------------------- * p_register_all_decoders * --------------------------- * build the GVA_global_decoder_list * with one element for each available decoder. * * in case the caller does not specifiy a prefered_decoder * the order of registered decoders is relevant, because * the 1st one that can handle the video is picked at open. * * This is typical the last one that is added to begin of the list * (currently ffmpeg) */ static void p_register_all_decoders(void) { t_GVA_DecoderElem *dec_elem; /* register all internal decoders */ GVA_global_decoder_list = NULL; #ifdef ENABLE_GVA_GIMP dec_elem = p_gimp_new_dec_elem(); if(dec_elem) { dec_elem->next = GVA_global_decoder_list; GVA_global_decoder_list = dec_elem; } #endif #ifdef ENABLE_GVA_LIBQUICKTIME dec_elem = p_quicktime_new_dec_elem(); if(dec_elem) { dec_elem->next = GVA_global_decoder_list; GVA_global_decoder_list = dec_elem; } #endif #ifdef ENABLE_GVA_LIBMPEG3 dec_elem = p_mpeg3_new_dec_elem(); if(dec_elem) { dec_elem->next = GVA_global_decoder_list; GVA_global_decoder_list = dec_elem; } #endif #ifdef ENABLE_GVA_LIBAVFORMAT p_ffmpeg_init(); dec_elem = p_ffmpeg_new_dec_elem(); if(dec_elem) { dec_elem->next = GVA_global_decoder_list; GVA_global_decoder_list = dec_elem; } #endif } /* end p_register_all_decoders */ /* --------------------------- * p_gva_worker_xxx Procedures * --------------------------- * * call decoder specific methodes * for * - close a videofile. * - seek position of a frame * - get frame (into pre allocated frame_data) and advance pos to next frame * */ /* -------------------------- * p_gva_worker_close * -------------------------- */ static void p_gva_worker_close(t_GVA_Handle *gvahand) { if(gvahand) { t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(dec_elem) { if(gap_debug) printf("GVA: p_gva_worker_close: before CLOSE %s with decoder:%s\n", gvahand->filename, dec_elem->decoder_name); (*dec_elem->fptr_close)(gvahand); if(gap_debug) printf("GVA: p_gva_worker_close: after CLOSE %s with decoder:%s\n", gvahand->filename, dec_elem->decoder_name); if(gvahand->filename) { g_free(gvahand->filename); gvahand->filename = NULL; } /* free image buffer and row_pointers */ p_drop_frame_cache(gvahand); } } if(gap_debug) printf("GVA: p_gva_worker_close: END\n"); } /* end p_gva_worker_close */ /* --------------------------- * p_gva_worker_get_next_frame * --------------------------- */ static t_GVA_RetCode p_gva_worker_get_next_frame(t_GVA_Handle *gvahand) { t_GVA_Frame_Cache *fcache; t_GVA_RetCode l_rc; l_rc = GVA_RET_ERROR; if(gvahand) { t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(dec_elem) { if(dec_elem->fptr_get_next_frame == NULL) { printf("p_gva_worker_get_next_frame: Method not implemented in decoder %s\n", dec_elem->decoder_name); return(GVA_RET_ERROR); } fcache = &gvahand->fcache; fcache->fcache_locked = TRUE; if(fcache->fc_current) { /* if fcache framenumber is negative, we can reuse * that EMPTY element without advance */ if(fcache->fc_current->framenumber >= 0) { /* advance current write position to next element in the fcache ringlist */ fcache->fc_current = fcache->fc_current->next; fcache->fc_current->framenumber = -1; gvahand->frame_data = fcache->fc_current->frame_data; gvahand->row_pointers = fcache->fc_current->row_pointers; } /* CALL decoder specific implementation of GET_NEXT_FRAME procedure */ l_rc = (*dec_elem->fptr_get_next_frame)(gvahand); if (l_rc == GVA_RET_OK) { fcache->fc_current->framenumber = gvahand->current_frame_nr; } } fcache->fcache_locked = FALSE; } } return(l_rc); } /* end p_gva_worker_get_next_frame */ /* -------------------------- * p_gva_worker_seek_frame * -------------------------- */ static t_GVA_RetCode p_gva_worker_seek_frame(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit) { t_GVA_Frame_Cache *fcache; t_GVA_RetCode l_rc; l_rc = GVA_RET_ERROR; if(gvahand) { t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(dec_elem) { if(dec_elem->fptr_seek_frame == NULL) { printf("p_gva_worker_seek_frame: Method not implemented in decoder %s\n", dec_elem->decoder_name); return(GVA_RET_ERROR); } fcache = &gvahand->fcache; fcache->fcache_locked = TRUE; if(fcache->fc_current) { /* if fcache framenumber is negative, we can reuse * that EMPTY element without advance */ if(fcache->fc_current->framenumber >= 0) { /* advance current write position to next element in the fcache ringlist * Some of the seek procedure implementations do dummy reads * therefore we provide a fcache element, but leave the * framenumber -1 because this element is invalid in most cases */ fcache->fc_current = fcache->fc_current->next; fcache->fc_current->framenumber = -1; gvahand->frame_data = fcache->fc_current->frame_data; gvahand->row_pointers = fcache->fc_current->row_pointers; } } /* CALL decoder specific implementation of SEEK_FRAME procedure */ l_rc = (*dec_elem->fptr_seek_frame)(gvahand, pos, pos_unit); fcache->fcache_locked = FALSE; } } return(l_rc); } /* end p_gva_worker_seek_frame */ /* -------------------------- * p_gva_worker_seek_audio * -------------------------- */ static t_GVA_RetCode p_gva_worker_seek_audio(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit) { t_GVA_RetCode l_rc; l_rc = GVA_RET_ERROR; if(gvahand) { t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(dec_elem) { if(dec_elem->fptr_seek_audio == NULL) { printf("p_gva_worker_seek_audio: Method not implemented in decoder %s\n", dec_elem->decoder_name); return(GVA_RET_ERROR); } l_rc = (*dec_elem->fptr_seek_audio)(gvahand, pos, pos_unit); } } return(l_rc); } /* end p_gva_worker_seek_audio */ /* -------------------------- * p_gva_worker_get_audio * -------------------------- */ static t_GVA_RetCode p_gva_worker_get_audio(t_GVA_Handle *gvahand ,gint16 *output_i /* preallocated buffer large enough for samples * siezeof gint16 */ ,gint32 channel /* audiochannel 1 upto n */ ,gdouble samples /* number of samples to read */ ,t_GVA_AudPos mode_flag /* specify the position where to start reading audio from */ ) { t_GVA_RetCode l_rc; l_rc = GVA_RET_ERROR; if(gvahand) { t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(dec_elem) { if(dec_elem->fptr_get_audio == NULL) { printf("p_gva_worker_get_audio: Method not implemented in decoder %s\n", dec_elem->decoder_name); return(GVA_RET_ERROR); } l_rc = (*dec_elem->fptr_get_audio)(gvahand ,output_i ,channel ,samples ,mode_flag ); } } return(l_rc); } /* end p_gva_worker_get_audio */ /* -------------------------- * p_gva_worker_count_frames * -------------------------- */ static t_GVA_RetCode p_gva_worker_count_frames(t_GVA_Handle *gvahand) { t_GVA_RetCode l_rc; l_rc = GVA_RET_ERROR; if(gvahand) { t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(dec_elem) { if(dec_elem->fptr_count_frames == NULL) { printf("p_gva_worker_count_frames: Method not implemented in decoder %s\n", dec_elem->decoder_name); return(GVA_RET_ERROR); } l_rc = (*dec_elem->fptr_count_frames)(gvahand); } } return(l_rc); } /* end p_gva_worker_count_frames */ /* ------------------------------- * p_gva_worker_check_seek_support * ------------------------------- */ static t_GVA_SeekSupport p_gva_worker_check_seek_support(t_GVA_Handle *gvahand) { t_GVA_SeekSupport l_rc; l_rc = GVA_SEEKSUPP_NONE; if(gvahand) { t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(dec_elem) { if(dec_elem->fptr_seek_support == NULL) { printf("p_gva_worker_check_seek_support: Method not implemented in decoder %s\n", dec_elem->decoder_name); return(GVA_SEEKSUPP_NONE); } l_rc = (*dec_elem->fptr_seek_support)(gvahand); } } return(l_rc); } /* end p_gva_worker_check_seek_support */ /* ---------------------------- * p_gva_worker_get_video_chunk * ---------------------------- */ static t_GVA_RetCode p_gva_worker_get_video_chunk(t_GVA_Handle *gvahand , gint32 frame_nr , unsigned char *chunk , gint32 *size , gint32 max_size) { t_GVA_RetCode l_rc; l_rc = GVA_RET_ERROR; if(gvahand) { t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(dec_elem) { if(dec_elem->fptr_get_video_chunk == NULL) { printf("p_gva_worker_get_video_chunk: Method not implemented in decoder %s\n", dec_elem->decoder_name); return(GVA_RET_ERROR); } l_rc = (*dec_elem->fptr_get_video_chunk)(gvahand , frame_nr , chunk , size , max_size ); } } return(l_rc); } /* end p_gva_worker_get_video_chunk */ /* ---------------------------- * p_gva_worker_get_codec_name * ---------------------------- */ static char * p_gva_worker_get_codec_name(t_GVA_Handle *gvahand ,t_GVA_CodecType codec_type ,gint32 track_nr ) { char *codec_name; codec_name = NULL; if(gvahand) { t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(dec_elem) { if(dec_elem->fptr_get_codec_name == NULL) { printf("p_gva_worker_get_codec_name: Method not implemented in decoder %s\n", dec_elem->decoder_name); return(NULL); } codec_name = (*dec_elem->fptr_get_codec_name)(gvahand , codec_type , track_nr ); } } return(codec_name); } /* end p_gva_worker_get_codec_name */ /* -------------------------- * p_gva_worker_open_read * -------------------------- * * open a videofile for reading. * this procedure tries to findout a compatible * decoder for the videofile. * if a compatible decoder is available, * a t_GVA_Handle Structure (with informations * about the video and the decoder) is returned. * NULL is returned, if none of the known decoders * can read the videofile. * * in case of successful open a buffer for one uncompressed RGBA frame * and row_pointers are allocated automatically. * (and will be freed automatically by the close procedure) */ static t_GVA_Handle * p_gva_worker_open_read(const char *filename, gint32 vid_track, gint32 aud_track ,const char *preferred_decoder ,gboolean disable_mmx ) { t_GVA_Handle *gvahand; t_GVA_DecoderElem *dec_elem; gvahand = g_malloc0(sizeof(t_GVA_Handle)); gvahand->dec_elem = NULL; /* init no decoder found */ gvahand->decoder_handle = NULL; gvahand->vid_track = MAX(vid_track -1, 0); gvahand->aud_track = MAX(aud_track -1, 0); gvahand->aspect_ratio = 0.0; gvahand->vtracks = 0; gvahand->atracks = 0; gvahand->progress_cb_user_data = NULL; gvahand->fptr_progress_callback = NULL; gvahand->frame_data = NULL; gvahand->row_pointers = NULL; gvahand->fc_frame_data = NULL; gvahand->fc_row_pointers = NULL; gvahand->fcache.fc_current = NULL; gvahand->fcache.frame_cache_size = 0; gvahand->fcache.max_fcache_id = 0; gvahand->fcache.fcache_locked = FALSE; gvahand->image_id = -1; gvahand->layer_id = -1; gvahand->disable_mmx = disable_mmx; gvahand->dirty_seek = FALSE; gvahand->emulate_seek = FALSE; gvahand->create_vindex = FALSE; gvahand->vindex = NULL; gvahand->mtime = 0; gvahand->do_gimp_progress = FALSE; /* WARNING: dont try to set this TRUE if you call the API from a pthread !! */ gvahand->all_frames_counted = FALSE; gvahand->all_samples_counted = FALSE; gvahand->critical_timecodesteps_found = FALSE; gvahand->cancel_operation = FALSE; gvahand->filename = g_strdup(filename); gvahand->current_frame_nr = 0; gvahand->current_seek_nr = 1; gvahand->current_sample = 1.0; gvahand->reread_sample_pos = 1.0; gvahand->audio_playtime_sec = 0.0; gvahand->total_aud_samples = 0; gvahand->samplerate = 0; gvahand->audio_cannels = 0; gvahand->percentage_done = 0.0; gvahand->frame_counter = 0; gvahand->gva_thread_save = TRUE; /* default for most decoder libs */ if(GVA_global_decoder_list == NULL) { p_register_all_decoders(); } if(preferred_decoder) { /* if the caller provided a preferred_decoder name * we check that decoder as 1.st one, before checking the full decoder list */ for(dec_elem = GVA_global_decoder_list; dec_elem != NULL; dec_elem = dec_elem->next) { int l_flag; if(strcmp(preferred_decoder, dec_elem->decoder_name) == 0) { if(gap_debug) printf("GVA: check sig %s with preferred decoder:%s\n", filename, dec_elem->decoder_name); /* call the decoder specific check sig function */ l_flag = (*dec_elem->fptr_check_sig)(gvahand->filename); if (l_flag == 1) { gvahand->dec_elem = dec_elem; break; } } } } if(gvahand->dec_elem == NULL) { /* try to find a decoder that can decode the videofile */ for(dec_elem = GVA_global_decoder_list; dec_elem != NULL; dec_elem = dec_elem->next) { int l_flag; if(gap_debug) printf("GVA: check sig %s with decoder:%s\n", filename, dec_elem->decoder_name); /* call the decoder specific check sig function */ l_flag = (*dec_elem->fptr_check_sig)(gvahand->filename); if (l_flag == 1) { gvahand->dec_elem = dec_elem; break; } } } if(gvahand->dec_elem == NULL) { printf("GVA: File %s is NOT a supported Videoformat\n", filename); g_free(gvahand); return NULL; } /* call decoder specific wrapper for open_read Procedure */ dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(gap_debug) printf("GVA: p_gva_worker_open_read: before OPEN %s with decoder:%s\n", filename, dec_elem->decoder_name); (*dec_elem->fptr_open_read)(gvahand->filename, gvahand); if(gap_debug) printf("GVA: p_gva_worker_open_read: after OPEN %s with decoder:%s\n", filename, dec_elem->decoder_name); if (gvahand->decoder_handle == NULL) { printf("Open Videofile %s FAILED\n", filename); g_free(gvahand); return NULL; } /* allocate buffer for one frame (use minimal size 2x2 if no videotrack is present) */ if(gvahand) { /* allocate frame_data and row_pointers for one frame (minimal cachesize 1 == no chaching) * (calling apps may request bigger cache after successful open) */ p_build_frame_cache(gvahand, 1); } gvahand->vid_track = CLAMP(gvahand->vid_track, 0, gvahand->vtracks-1); gvahand->aud_track = CLAMP(gvahand->aud_track, 0, gvahand->atracks-1); if(gap_debug) printf("END OF p_gva_worker_open_read: vtracks:%d atracks:%d\n", (int)gvahand->vtracks, (int)gvahand->atracks ); return (gvahand); } /* end p_gva_worker_open_read */ /* ------------------------------------ * Public GVA API functions * ------------------------------------ */ t_GVA_Handle * GVA_open_read_pref(const char *filename, gint32 vid_track, gint32 aud_track ,const char *preferred_decoder ,gboolean disable_mmx ) { t_GVA_Handle *handle; if(gap_debug) printf("GVA_open_read_pref: START\n"); if((gap_debug) && (preferred_decoder)) printf("GVA_open_read_pref: preferred_decoder: %s\n", preferred_decoder); handle = p_gva_worker_open_read(filename, vid_track, aud_track ,preferred_decoder ,disable_mmx ); if(gap_debug) printf("GVA_open_read_pref: END handle:%d\n", (int)handle); return(handle); } t_GVA_Handle * GVA_open_read(const char *filename, gint32 vid_track, gint32 aud_track) { t_GVA_Handle *handle; char *l_env_preferred_decoder; if(gap_debug) printf("GVA_open_read: START\n"); l_env_preferred_decoder = g_strdup(g_getenv("GVA_PREFERRED_DECODER")); handle = p_gva_worker_open_read(filename, vid_track, aud_track ,l_env_preferred_decoder /* NULL or preferred_decoder */ ,FALSE /* disable_mmx==FALSE (use MMX if available) */ ); if(l_env_preferred_decoder) { g_free(l_env_preferred_decoder); } if(gap_debug) printf("GVA_open_read: END handle:%d\n", (int)handle); return(handle); } void GVA_close(t_GVA_Handle *gvahand) { if(gap_debug) printf("GVA_close: START handle:%d\n", (int)gvahand); p_gva_worker_close(gvahand); if(gap_debug) printf("GVA_close: END\n"); } t_GVA_RetCode GVA_get_next_frame(t_GVA_Handle *gvahand) { t_GVA_RetCode l_rc; if(gap_debug) { printf("GVA_get_next_frame: START handle:%d\n", (int)gvahand); } l_rc = p_gva_worker_get_next_frame(gvahand); if(gap_debug) { printf("GVA_get_next_frame: END rc:%d\n", (int)l_rc); } return(l_rc); } t_GVA_RetCode GVA_seek_frame(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit) { t_GVA_RetCode l_rc; if(gap_debug) { printf("GVA_seek_frame: START handle:%d, pos%.4f unit:%d\n" , (int)gvahand, (float)pos, (int)pos_unit); } l_rc = p_gva_worker_seek_frame(gvahand, pos, pos_unit); if(gap_debug) { printf("GVA_seek_frame: END rc:%d\n" , (int)l_rc); } return(l_rc); } t_GVA_RetCode GVA_seek_audio(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit) { t_GVA_RetCode l_rc; if(gap_debug) printf("GVA_seek_audio: START handle:%d\n", (int)gvahand); l_rc = p_gva_worker_seek_audio(gvahand, pos, pos_unit); if(gap_debug) printf("GVA_seek_audio: END rc:%d\n", (int)l_rc); return(l_rc); } t_GVA_RetCode GVA_get_audio(t_GVA_Handle *gvahand ,gint16 *output_i /* preallocated buffer large enough for samples * siezeof gint16 */ ,gint32 channel /* audiochannel 1 upto n */ ,gdouble samples /* number of samples to read */ ,t_GVA_AudPos mode_flag /* specify the position where to start reading audio from */ ) { t_GVA_RetCode l_rc; if(gap_debug) printf("GVA_get_audio: START handle:%d, ch:%d samples:%d mod:%d\n", (int)gvahand, (int)channel, (int)samples, (int)mode_flag); l_rc = p_gva_worker_get_audio(gvahand ,output_i ,channel ,samples ,mode_flag ); if(gap_debug) printf("GVA_get_audio: END rc:%d\n", (int)l_rc); return(l_rc); } t_GVA_RetCode GVA_count_frames(t_GVA_Handle *gvahand) { t_GVA_RetCode l_rc; if(gap_debug) printf("GVA_count_frames: START handle:%d\n", (int)gvahand); l_rc = p_gva_worker_count_frames(gvahand); if(gap_debug) printf("GVA_count_frames: END rc:%d\n", (int)l_rc); return(l_rc); } t_GVA_SeekSupport GVA_check_seek_support(t_GVA_Handle *gvahand) { t_GVA_SeekSupport l_rc; if(gap_debug) printf("GVA_check_seek_support: START handle:%d\n", (int)gvahand); l_rc = p_gva_worker_check_seek_support(gvahand); if(gap_debug) printf("GVA_check_seek_support: END rc:%d\n", (int)l_rc); return(l_rc); } t_GVA_RetCode GVA_get_video_chunk(t_GVA_Handle *gvahand , gint32 frame_nr , unsigned char *chunk , gint32 *size , gint32 max_size) { t_GVA_RetCode l_rc; if(gap_debug) printf("GVA_get_video_chunk: START handle:%d, chunk addr:%d (max_size:%d) frame_nr:%d\n" , (int)gvahand , (int)chunk , (int)max_size , (int)frame_nr ); l_rc = p_gva_worker_get_video_chunk(gvahand, frame_nr, chunk, size, max_size); if(gap_debug) printf("GVA_get_video_chunk: END rc:%d size:%d\n", (int)l_rc, (int)*size); return(l_rc); } gboolean GVA_has_video_chunk_proc(t_GVA_Handle *gvahand) { gboolean l_rc; if(gap_debug) printf("GVA_has_video_chunk_proc: START handle:%d\n", (int)gvahand); l_rc = FALSE; if(gvahand) { t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(dec_elem) { if(dec_elem->fptr_get_video_chunk != NULL) { l_rc = TRUE; } } } if(gap_debug) printf("GVA_has_video_chunk_proc: END rc:%d\n", (int)l_rc); return(l_rc); } char * GVA_get_codec_name(t_GVA_Handle *gvahand ,t_GVA_CodecType codec_type ,gint32 track_nr ) { char *codec_name; if(gap_debug) { printf("GVA_get_video_chunk: START handle:%d, codec_type:%d track_nr:%d\n" , (int)gvahand , (int)codec_type , (int)track_nr ); } codec_name = p_gva_worker_get_codec_name(gvahand, codec_type, track_nr); if(gap_debug) { printf("GVA_get_codec_name: END codec_name:"); if (codec_name) { printf("%s", codec_name); } else { printf("NULL"); } printf("\n"); } return(codec_name); } /* ------------------------------------------------------------------------- * Converter Procedures (Framebuffer <--> GIMP * ------------------------------------------------------------------------- */ /* ---------------------------------- * GVA_gimp_image_to_rowbuffer * ---------------------------------- * transfer a gimp image to GVA rowbuffer (gvahand->frame_data) * please note that the image will be * - flattened * - converted to RGB * - scaled to GVA framesize * if needed. */ t_GVA_RetCode GVA_gimp_image_to_rowbuffer(t_GVA_Handle *gvahand, gint32 image_id) { GimpPixelRgn pixel_rgn; GimpDrawable *drawable; gint32 l_layer_id; gint l_nlayers; gint32 *l_layers_list; if(gap_debug) printf("GVA_gimp_image_to_rowbuffer image_id: %d\n", (int)image_id); l_layer_id = -1; l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list != NULL) { l_layer_id = l_layers_list[0]; g_free (l_layers_list); } else { printf("GVA_gimp_image_to_rowbuffer: No Layer found, image_id:%d\n", (int)image_id); return(GVA_RET_ERROR); } drawable = gimp_drawable_get (l_layer_id); /* flatten image if needed (more layers or layer with alpha channel) */ if((l_nlayers > 1 ) || (drawable->bpp == 4) || (drawable->bpp ==2)) { if(gap_debug) printf("GVA_gimp_image_to_rowbuffer: FLATTEN Image\n"); l_layer_id = gimp_image_flatten(image_id); gimp_drawable_detach (drawable); drawable = gimp_drawable_get (l_layer_id); } /* convert TO RGB if needed */ if(gimp_image_base_type(image_id) != GIMP_RGB) { if(gap_debug) printf("GVA_gimp_image_to_rowbuffer: convert TO_RGB\n"); gimp_image_convert_rgb(image_id); } /* ensure unique imagesize for all frames */ if((gimp_image_width(image_id) != gvahand->width) || (gimp_image_height(image_id) != gvahand->height)) { if(gap_debug) printf("GVA_gimp_image_to_rowbuffer: SCALING Image\n"); gimp_image_scale(image_id, gvahand->width, gvahand->height); } /* now we have an image with one RGB layer * and copy all pixelrows to gvahand->frame_data at once. */ gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0 , drawable->width, drawable->height , FALSE /* dirty */ , FALSE /* shadow */ ); gimp_pixel_rgn_get_rect (&pixel_rgn, gvahand->frame_data , 0 , 0 , gvahand->width , gvahand->height); gimp_drawable_detach(drawable); if (gap_debug) printf("DEBUG: after copy data rows \n"); return(GVA_RET_OK); /* return the newly created layer_id (-1 on error) */ } /* end GVA_gimp_image_to_rowbuffer */ /* ------------------------------------ * p_check_image_is_alive * ------------------------------------ * return TRUE if OK (image is still valid) * return FALSE if image is NOT valid */ static gboolean p_check_image_is_alive(gint32 image_id) { gint32 *images; gint nimages; gint l_idi; gint l_found; if(image_id < 0) { return FALSE; } images = gimp_image_list(&nimages); l_idi = nimages -1; l_found = FALSE; while((l_idi >= 0) && images) { if(image_id == images[l_idi]) { l_found = TRUE; break; } l_idi--; } if(images) g_free(images); if(l_found) { return TRUE; /* OK */ } if(gap_debug) { printf("p_check_image_is_alive: image_id %d is not VALID\n", (int)image_id); } return FALSE ; /* INVALID image id */ } /* end p_check_image_is_alive */ /* ------------------------------------ * p_mix_rows * ------------------------------------ * mix 2 input pixelrows (prev_row, next_row) * to one resulting pixelrow (mixed_row) * All pixelrows must have same width and bpp */ static inline void p_mix_rows( gint32 width , gint32 bpp , gint32 row_bytewidth , gint32 mix_threshold /* 0 <= mix_threshold <= 33554432 (256*256*256*2) */ , guchar *prev_row , guchar *next_row , guchar *mixed_row ) { if((bpp <3) || (mix_threshold >= MIX_MAX_THRESHOLD)) { gint32 l_idx; /* simple mix all bytes */ for(l_idx=0; l_idx < row_bytewidth; l_idx++) { mixed_row[l_idx] = (prev_row[l_idx] + next_row[l_idx]) / 2; } } else { gint32 l_col; /* color threshold mix */ for(l_col=0; l_col < width; l_col++) { gint16 r1, g1, b1, a1; gint16 r2, g2, b2, a2; gint16 dr, db; gint32 fhue, fval; r1 = prev_row[0]; g1 = prev_row[1]; b1 = prev_row[2]; r2 = next_row[0]; g2 = next_row[1]; b2 = next_row[2]; dr = abs((r1 - g1) - (r2 - g2)); db = abs((g1 - b1) - (g2 - b2)); fval = abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2); /* brightness difference */ fhue = dr * db; /* check hue failure and brightness failure against threshold */ if((fhue + fval) < mix_threshold) { /* smooth mix */ mixed_row[0] = (r1 + r2) / 2; mixed_row[1] = (g1 + g2) / 2; mixed_row[2] = (b1 + b2) / 2; } else { /* hard, no mix */ mixed_row[0] = r1; mixed_row[1] = g1; mixed_row[2] = b1; } if(bpp == 4) { a1 = prev_row[3]; a2 = next_row[3]; mixed_row[4] = (a1 + a2) / 2; } prev_row += bpp; next_row += bpp; mixed_row += bpp; } } } /* end p_mix_rows */ /* ------------------------------------ * p_calculate_mix_threshold * ------------------------------------ */ static gint32 p_calculate_mix_threshold(gdouble threshold) { gint32 l_threshold; gint32 l_mix_threshold; /* expand threshold range from 0.0-1.0 to 0 - MIX_MAX_THRESHOLD */ threshold = CLAMP(threshold, 0.0, 1.0); l_threshold = (gdouble)MIX_MAX_THRESHOLD * (threshold * threshold * threshold); l_mix_threshold = CLAMP((gint32)l_threshold, 0, MIX_MAX_THRESHOLD); } /* ------------------------------------ * p_calculate_interpolate_flag * ------------------------------------ */ static gint32 p_calculate_interpolate_flag(gint32 deinterlace) { gint32 l_interpolate_flag; l_interpolate_flag = 0; if (deinterlace == 1) { l_interpolate_flag = 1; } return l_interpolate_flag; } /* ------------------------------------ * GVA_delace_frame * ------------------------------------ * create a deinterlaced copy of the current frame * (the one where gvahand->fc_row_pointers are referring to) * * IN: gvahand videohandle * IN: do_scale FALSE: deliver frame at original size (ignore bpp, width and height parameters) * TRUE: deliver frame at size specified by width, height, bpp * scaling is done fast in low quality * IN: deinterlace 0: no deinterlace, 1 pick odd lines, 2 pick even lines * IN: threshold 0.0 hard, 1.0 smooth interpolation at deinterlacing * threshold is ignored if do_scaing == TRUE * * return databuffer, Pixels are stored in the RGB colormdel * the data buffer must be g_free'd by the calling program */ guchar * GVA_delace_frame(t_GVA_Handle *gvahand , gint32 deinterlace , gdouble threshold ) { guchar *l_framedata_copy; guchar *l_row_ptr_dest; gint32 l_row; gint32 l_interpolate_flag; gint32 l_row_bytewidth; gint32 l_mix_threshold; if(gvahand->fc_row_pointers == NULL) { return (NULL); } l_row_bytewidth = gvahand->width * gvahand->frame_bpp; l_framedata_copy = g_malloc(l_row_bytewidth * gvahand->height); l_interpolate_flag = p_calculate_interpolate_flag(deinterlace); l_mix_threshold = p_calculate_mix_threshold(threshold); l_row_ptr_dest = l_framedata_copy; for(l_row = 0; l_row < gvahand->height; l_row++) { if ((l_row & 1) == l_interpolate_flag) { if(l_row == 0) { /* we have no prvious row, so we just copy the next row */ memcpy(l_row_ptr_dest, gvahand->fc_row_pointers[1], l_row_bytewidth); } else { if(l_row == gvahand->height -1) { /* we have no next row, so we just copy the prvious row */ memcpy(l_row_ptr_dest, gvahand->fc_row_pointers[gvahand->height -2], l_row_bytewidth); } else { /* we have both prev and next row within valid range * and can calculate an interpolated row */ p_mix_rows ( gvahand->width , gvahand->frame_bpp , l_row_bytewidth , l_mix_threshold , gvahand->fc_row_pointers[l_row -1] , gvahand->fc_row_pointers[l_row +1] , l_row_ptr_dest ); } } } else { /* copy original row */ memcpy(l_row_ptr_dest, gvahand->fc_row_pointers[l_row], l_row_bytewidth); } l_row_ptr_dest += l_row_bytewidth; } return(l_framedata_copy); } /* end GVA_delace_frame */ /* ------------------------------------ * p_gva_deinterlace_drawable * ------------------------------------ */ static void p_gva_deinterlace_drawable (GimpDrawable *drawable, gint32 deinterlace, gdouble threshold) { GimpPixelRgn srcPR, destPR; guchar *dest; guchar *dest_buffer = NULL; guchar *upper; guchar *lower; gint row, col; gint x, y; gint width, height; gint bytes; gint x2, y2; gint32 l_row_bytewidth; gint32 l_interpolate_flag; gint32 l_mix_threshold; l_interpolate_flag = p_calculate_interpolate_flag(deinterlace); l_mix_threshold = p_calculate_mix_threshold(threshold); bytes = drawable->bpp; gimp_drawable_mask_bounds (drawable->drawable_id, &x, &y, &x2, &y2); width = x2 - x; height = y2 - y; l_row_bytewidth = width * drawable->bpp; dest = g_new (guchar, l_row_bytewidth); gimp_pixel_rgn_init (&destPR, drawable, x, y, width, height, TRUE, TRUE); gimp_pixel_rgn_init (&srcPR, drawable, x, MAX (y - 1, 0), width, MIN (height + 1, drawable->height), FALSE, FALSE); /* allocate buffers for upper and lower row */ upper = g_new (guchar, l_row_bytewidth); lower = g_new (guchar, l_row_bytewidth); for (row = y; row < y + height; row++) { /* Only do interpolation if the row: * (1) Isn't one we want to keep * (2) Has both an upper and a lower row * Otherwise, just duplicate the source row */ if (((row & 1) == l_interpolate_flag) && (row - 1 >= 0) && (row + 1 < drawable->height)) { gimp_pixel_rgn_get_row (&srcPR, upper, x, row - 1, width); gimp_pixel_rgn_get_row (&srcPR, lower, x, row + 1, width); p_mix_rows ( width , drawable->bpp , l_row_bytewidth , l_mix_threshold , upper , lower , dest ); } else { /* copy current row 1:1 */ gimp_pixel_rgn_get_row (&srcPR, dest, x, row, width); } gimp_pixel_rgn_set_row (&destPR, dest, x, row, width); } /* update the deinterlaced region */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x, y, width, height); g_free (lower); g_free (upper); g_free (dest); } /* end p_gva_deinterlace_drawable */ /* ------------------------------------ * GVA_delace_drawable * ------------------------------------ * deinterlaced the specified drawable. * * IN: drawable_id the drawable to be deinterlaced. * IN: do_scale FALSE: deliver frame at original size (ignore bpp, width and height parameters) * TRUE: deliver frame at size specified by width, height, bpp * scaling is done fast in low quality * IN: deinterlace 0: no deinterlace (NOP), 1 pick odd lines, 2 pick even lines * IN: threshold 0.0 hard, 1.0 smooth interpolation at deinterlacing * threshold is ignored if do_scaing == TRUE * */ void GVA_delace_drawable(gint32 drawable_id , gint32 deinterlace , gdouble threshold ) { GimpDrawable *drawable; if (deinterlace != 0) { drawable = gimp_drawable_get(drawable_id); if (drawable) { p_gva_deinterlace_drawable (drawable, deinterlace, threshold); gimp_drawable_detach(drawable); } } } /* end GVA_delace_drawable */ /* ------------------------------------ * GVA_image_set_aspect * ------------------------------------ * if aspect_ratio is known convert the aspect * to image X and Y resolution in DPI * this allows GIMP to scale the display to correct aspect * when View option "Dot for Dot" is turned off. * Note that the resolution is just a guess based on typical * monitor resolution in DPI. * (videos usually have no DPI resoulution information, just aspect ratio) */ void GVA_image_set_aspect(t_GVA_Handle *gvahand, gint32 image_id) { if(gvahand->aspect_ratio != 0.0) { gdouble xresolution; gdouble yresolution; gdouble xresolutionMoni; gdouble yresolutionMoni; gdouble asymetric; asymetric = ((gdouble)gvahand->width / (gdouble)gvahand->height) / gvahand->aspect_ratio; gimp_get_monitor_resolution(&xresolutionMoni, &yresolutionMoni); if (yresolutionMoni > 0) { yresolution = yresolutionMoni; } else { yresolution = 72.0; } xresolution = yresolution * asymetric; /* set resolution in DPI according to aspect ratio * assuming a typical monitor resolution */ gimp_image_set_unit (image_id, GIMP_UNIT_INCH); gimp_image_set_resolution (image_id, xresolution, yresolution); if(gap_debug) { printf("API: resolution x/y %f / %f\n" , (float)xresolution , (float)yresolution ); } } } /* end GVA_image_set_aspect */ /* ------------------------------------ * GVA_frame_to_gimp_layer_2 * ------------------------------------ * transfer frame imagedata from buffer (gvahand->frame_data or fcache) * to gimp image. (gvahand->image_id) * IN/OUT: * *image_id ... pointer to image id * IN: * old_layer_id ... -1 dont care about old layer(s) of the image * (you may use -1 if the image has no layer) * delete_mode ... TRUE: delete old_layer_id * FALSE: keep old_layer_id, but set invisible * (use this to build mulitlayer images) * deinterlace ... 0 ..NO, deliver image as it is * 1 .. deinterlace using odd lines and interpolate the even lines * 2 .. deinterlace using even lines and interpolate the odd lines * threshold ... 0.0 <= threshold <= 1.0 * threshold is used only for interpolation when deinterlace != 0 * - big thresholds do smooth mix * - small thresholds keep hard edges (does not mix different colors) * - threshold 0 does not mix at all and uses only one inputcolor * RETURN: layer_id of the newly created layer, * -2 if framenumber not found in fcache * -1 on other errors * */ gint32 GVA_frame_to_gimp_layer_2(t_GVA_Handle *gvahand , gint32 *image_id , gint32 old_layer_id , gboolean delete_mode , gint32 framenumber , gint32 deinterlace , gdouble threshold ) { gchar *layername; GimpPixelRgn pixel_rgn; GimpDrawable *drawable; gint32 l_new_layer_id; gint32 l_threshold; gint32 l_mix_threshold; static gchar *odd_even_tab[8] = {"\0", "_odd", "_even", "_odd", "_even", "\0", "\0", "\0" }; if(gap_debug) { printf("GVA_frame_to_gimp_layer_2 framenumber: %d\n", (int)framenumber); } l_new_layer_id = -1; if (GVA_search_fcache(gvahand, framenumber) != GVA_RET_OK) { if(gap_debug) { printf("frame %d not found in fcache! %d\n" , (int)framenumber , (int)gvahand->current_frame_nr ); } return (-2); } /* expand threshold range from 0.0-1.0 to 0 - MIX_MAX_THRESHOLD */ threshold = CLAMP(threshold, 0.0, 1.0); l_threshold = (gdouble)MIX_MAX_THRESHOLD * (threshold * threshold * threshold); l_mix_threshold = CLAMP((gint32)l_threshold, 0, MIX_MAX_THRESHOLD); if(p_check_image_is_alive(*image_id)) { /* reuse existing image for next frame */ if((gvahand->width != gimp_image_width(*image_id)) || (gvahand->height != gimp_image_height(*image_id))) { /* resize to image to framesize */ gimp_image_resize(*image_id , gvahand->width , gvahand->height , 0 , 0); GVA_image_set_aspect(gvahand, *image_id); } } else { *image_id = gimp_image_new (gvahand->width, gvahand->height, GIMP_RGB); if (gap_debug) printf("DEBUG: after gimp_image_new\n"); GVA_image_set_aspect(gvahand, *image_id); old_layer_id = -1; } if (gimp_image_undo_is_enabled(*image_id)) { gimp_image_undo_disable(*image_id); } if(gvahand->framerate > 0) { gint delay; delay = 1000 / gvahand->framerate; layername = g_strdup_printf("Frame%05d%s (%dms)", (int)framenumber, odd_even_tab[deinterlace & 7], (int)delay); } else { layername = g_strdup_printf("Frame%05d%s", (int)framenumber, odd_even_tab[deinterlace & 7]); } if(gvahand->frame_bpp == 4) { l_new_layer_id = gimp_layer_new (*image_id , layername , gvahand->width , gvahand->height , GIMP_RGBA_IMAGE , 100.0, GIMP_NORMAL_MODE); } else { l_new_layer_id = gimp_layer_new (*image_id , layername , gvahand->width , gvahand->height , GIMP_RGB_IMAGE , 100.0, GIMP_NORMAL_MODE); } g_free(layername); drawable = gimp_drawable_get (l_new_layer_id); /* copy data rows * libmpeg3 data rows (retrieved in mode MPEG3_RGB888) * can be used 1:1 by gimp_pixel_rgn_set_rect on layertypes GIMP_RGB_IMAGE * */ if (gap_debug) { printf("DEBUG: before copy data rows gvahand->height=%d gvahand->width=%d\n" , (int)gvahand->height ,(int)gvahand->width); } /* Fill in the alpha channel (for RGBA mode) * libmpeg3 uses 0 for opaque alpha (that is full transparent in gimp terms) * * for playback it is faster to run libmpeg3 with bpp=3 * and do not use alpha channel at all. * (or add alpha channel later but only if we are building a multilayer image) */ if(gvahand->frame_bpp == 4) { gint i; if (gap_debug) printf("DEBUG: FILL In the ALPHA CHANNEL\n"); for (i=(gvahand->width * gvahand->height)-1; i>=0; i--) { gvahand->fc_frame_data[3+(i*4)] = 255; } } gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0 , drawable->width, drawable->height , TRUE /* dirty */ , FALSE /* shadow */ ); if ((deinterlace == 0) || (gvahand->height < 2)) { gimp_pixel_rgn_set_rect (&pixel_rgn, gvahand->fc_frame_data , 0 , 0 , gvahand->width , gvahand->height); } else { guchar *l_framedata_copy; l_framedata_copy = GVA_delace_frame(gvahand ,deinterlace ,threshold ); if(l_framedata_copy) { gimp_pixel_rgn_set_rect (&pixel_rgn, l_framedata_copy , 0 , 0 , gvahand->width , gvahand->height); g_free(l_framedata_copy); } } if (gap_debug) { printf("DEBUG: after copy data rows (NO SHADOW)\n"); } gimp_drawable_flush (drawable); gimp_drawable_detach(drawable); /* * gimp_drawable_merge_shadow (drawable->id, TRUE); */ /* what to do with old layer ? */ if(old_layer_id >= 0) { if(delete_mode) { gimp_image_remove_layer(*image_id, old_layer_id); } else { /* we are collecting layers in one multilayer image, * so do not delete previous added layer, but * only set invisible */ gimp_drawable_set_visible(old_layer_id, FALSE); } } /* add new layer on top of the layerstack */ gimp_image_add_layer (*image_id, l_new_layer_id, 0); gimp_drawable_set_visible(l_new_layer_id, TRUE); /* clear undo stack */ if (gimp_image_undo_is_enabled(*image_id)) { gimp_image_undo_disable(*image_id); } /* debug code to display a copy of the image */ /* * { * gint32 dup_id; * * dup_id = gimp_image_duplicate(*image_id); * printf("API: DUP_IMAGE_ID: %d\n", (int) dup_id); * gimp_display_new(dup_id); * } */ if (gap_debug) { printf("END GVA_frame_to_gimp_layer_2: return value:%d\n", (int)l_new_layer_id); } return(l_new_layer_id); /* return the newly created layer_id (-1 on error) */ } /* end GVA_frame_to_gimp_layer_2 */ /* ------------------------------------ * GVA_fcache_to_gimp_image * ------------------------------------ * copy the GVA framecache to one GIMP multilayer image * limited by min_framenumber, max_framenumber. * use limitvalue(s) -1 if you want all cached frames without limit. * * returns image_id of the new created gimp image (or -1 on errors) */ gint32 GVA_fcache_to_gimp_image(t_GVA_Handle *gvahand , gint32 min_framenumber , gint32 max_framenumber , gint32 deinterlace , gdouble threshold ) { t_GVA_Frame_Cache *fcache; t_GVA_Frame_Cache_Elem *fc_ptr; t_GVA_Frame_Cache_Elem *fc_minframe; gint32 image_id; gint32 layer_id; gboolean delete_mode; image_id = -1; layer_id = -1; delete_mode = TRUE; fcache = &gvahand->fcache; /* search the fcache element with smallest positve framenumber */ fc_minframe = NULL; if(fcache->fc_current) { fc_ptr = (t_GVA_Frame_Cache_Elem *)fcache->fc_current; while(1 == 1) { if(fc_ptr->framenumber >= 0) { if(fc_minframe) { if(fc_ptr->framenumber < fc_minframe->framenumber) { fc_minframe = fc_ptr; } } else { fc_minframe = fc_ptr; } } fc_ptr = (t_GVA_Frame_Cache_Elem *)fc_ptr->prev; if(fcache->fc_current == fc_ptr) { break; /* STOP, we are back at startpoint of the ringlist */ } if(fc_ptr == NULL) { break; /* internal error, ringlist is broken */ } } } if(fc_minframe) { fc_ptr = (t_GVA_Frame_Cache_Elem *)fc_minframe; while(1 == 1) { if((fc_ptr->framenumber >= min_framenumber) &&((fc_ptr->framenumber <= max_framenumber) || (max_framenumber < 0)) && (fc_ptr->framenumber >= 0)) { GVA_frame_to_gimp_layer_2(gvahand , &image_id , layer_id , delete_mode , fc_ptr->framenumber , deinterlace , threshold ); delete_mode = FALSE; /* keep old layers */ } /* step from fc_minframe forward in the fcache ringlist, * until we are back at fc_minframe */ fc_ptr = (t_GVA_Frame_Cache_Elem *)fc_ptr->next; if(fc_minframe == fc_ptr) { return (image_id); /* STOP, we are back at startpoint of the ringlist */ } if(fc_ptr == NULL) { return (image_id); /* internal error, ringlist is broken */ } } } return image_id; } /* end GVA_fcache_to_gimp_image */ /* ------------------------------------ * GVA_frame_to_gimp_layer * ------------------------------------ */ t_GVA_RetCode GVA_frame_to_gimp_layer(t_GVA_Handle *gvahand , gboolean delete_mode , gint32 framenumber , gint32 deinterlace , gdouble threshold ) { t_GVA_RetCode l_rc; if(gap_debug) { printf("GVA_frame_to_gimp_layer: START framenumber:%d image_id:%d layer_id: %d\n" , (int)framenumber , (int)gvahand->image_id , (int)gvahand->layer_id ); } gvahand->layer_id = GVA_frame_to_gimp_layer_2(gvahand , &gvahand->image_id , gvahand->layer_id , delete_mode , framenumber , deinterlace , threshold ); if(gvahand->layer_id < 0) { l_rc = GVA_RET_ERROR; } else { l_rc = GVA_RET_OK; } if(gap_debug) { printf("GVA_frame_to_gimp_layer: END RC:%d framenumber:%d image_id:%d layer_id: %d\n" , (int)l_rc , (int)framenumber , (int)gvahand->image_id , (int)gvahand->layer_id ); } return(l_rc); } /* end GVA_frame_to_gimp_layer */ /* ------------------------------------ * GVA_frame_to_buffer * ------------------------------------ * HINT: * for the calling program it is easier to call * GVA_fetch_frame_to_buffer * * IN: gvahand videohandle * IN: do_scale FALSE: deliver frame at original size (ignore bpp, width and height parameters) * TRUE: deliver frame at size specified by width, height, bpp * scaling is done fast in low quality * IN: framenumber The wanted framenumber * return NULL if the wanted framnumber is not in the fcache * In this case the calling program should fetch the wanted frame. * This can be done by calling: * GVA_seek_frame(gvahand, framenumber, GVA_UPOS_FRAMES); * GVA_get_next_frame(gvahand); * after successful fetch call GVA_frame_to_buffer once again. * The wanted framnumber should be found in the cache now. * IN: deinterlace 0: no deinterlace, 1 pick odd lines, 2 pick even lines * IN: threshold 0.0 hard, 1.0 smooth interpolation at deinterlacing * threshold is ignored if do_scaing == TRUE * IN/OUT: bpp accept 3 or 4 (ignored if do_scale == FALSE) * IN/OUT: width accept with >=1 and <= original video with (ignored if do_scale == FALSE) * IN/OUT: height accept height >=1 and <= original video height (ignored if do_scale == FALSE) * * return databuffer, Pixels are stored in the RGB colormdel * the data buffer must be g_free'd by the calling program */ guchar * GVA_frame_to_buffer(t_GVA_Handle *gvahand , gboolean do_scale , gint32 framenumber , gint32 deinterlace , gdouble threshold , gint32 *bpp , gint32 *width , gint32 *height ) { gint32 frame_size; guchar *frame_data; frame_data = NULL; if (GVA_search_fcache(gvahand, framenumber) != GVA_RET_OK) { if(gap_debug) printf("frame %d not found in fcache! %d\n", (int)framenumber , (int)gvahand->current_frame_nr ); return (NULL); } if(do_scale) { guchar *src_row, *src, *dest; gint row, col; gint32 deinterlace_mask; gint *arr_src_col; if(gap_debug) printf("GVA_frame_to_buffer: DO_SCALE\n"); /* for safety: width and height must be set to useful values * (dont accept bigger values than video size or values less than 1 pixel) */ if((*width < 1) || (*width > gvahand->width)) { *width = gvahand->width; } if((*height < 1) || (*height > gvahand->height)) { *height = gvahand->height; } *bpp = CLAMP(*bpp, 3, 4); frame_size = (*width) * (*bpp) * (*height); if(*bpp < 4) { /* add extra scratch byte, because the following loop * always writes 4 byte per pixel * (no check for bpp for performance reasons) */ frame_size++; } frame_data = g_malloc(frame_size); if(frame_data == NULL) { return (NULL); } if(deinterlace == 0) { deinterlace_mask = 0xffffffff; } else { /* mask is applied on row number to eliminate odd rownumbers */ deinterlace_mask = 0x7ffffffe; } /* array of column fetch indexes for quick access * to the source pixels. (The source row may be larger or smaller than pwidth) */ arr_src_col = g_new ( gint, (*width) ); /* column fetch indexes foreach preview col */ if(arr_src_col) { for ( col = 0; col < (*width); col++ ) { arr_src_col[ col ] = ( col * gvahand->width / (*width) ) * gvahand->frame_bpp; } dest = frame_data; /* copy row by row */ for ( row = 0; row < *height; row++ ) { src_row = gvahand->fc_row_pointers[(row * gvahand->height / (*height)) & deinterlace_mask]; for ( col = 0; col < (*width); col++ ) { src = &src_row[ arr_src_col[col] ]; dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; dest[3] = 255; dest += (*bpp); } } g_free(arr_src_col); } } else { *bpp = gvahand->frame_bpp; *width = gvahand->width; *height = gvahand->height; frame_size = (*width) * (*height) * (*bpp); if ((deinterlace == 0) || (gvahand->height < 2)) { if(gap_debug) printf("GVA_frame_to_buffer: MEMCPY\n"); frame_data = g_malloc(frame_size); if(frame_data == NULL) { return (NULL); } memcpy(frame_data, gvahand->fc_frame_data, frame_size); } else { frame_data = GVA_delace_frame(gvahand ,deinterlace ,threshold ); if(frame_data == NULL) { return (NULL); } } /* Fill in the alpha channel (for RGBA mode) * libmpeg3 uses 0 for opaque alpha (that is full transparent in gimp terms) * * normally the libmpeg3 decoder is used with with RGB mode (bpp==3) * and does not use alpha channel at all. */ if(*bpp == 4) { gint i; if (gap_debug) printf("DEBUG: FILL In the ALPHA CHANNEL\n"); for (i=((*width) * (*height))-1; i>=0; i--) { frame_data[3+(i*4)] = 255; } } } return(frame_data); } /* end GVA_frame_to_buffer */ /* ------------------------------------ * GVA_fetch_frame_to_buffer * ------------------------------------ * This procedure does fetch the specified framenumber from a videofile * and returns a buffer of RGB (or RGBA) encoded pixeldata. * (it does first search the API internal framecache, * then tries to read from the videofile (if not found in the framecahe) * * the returned data is a (optional downscaled) copy of the API internal frame data * and must be g_free'd by the calling program after use. * * IN: gvahand videohandle * IN: do_scale FALSE: deliver frame at original size (ignore bpp, width and height parameters) * TRUE: deliver frame at size specified by width, height, bpp * scaling is done fast in low quality * IN: framenumber The wanted framenumber * return NULL if the wanted framnumber could not be read. * IN: deinterlace 0: no deinterlace, 1 pick odd lines, 2 pick even lines * IN: threshold 0.0 hard, 1.0 smooth interpolation at deinterlacing * threshold is ignored if do_scaing == TRUE * (this parameter is ignored if deinterlace == 0) * IN/OUT: bpp accept 3 or 4 (ignored if do_scale == FALSE) * IN/OUT: width accept with >=1 and <= original video with (ignored if do_scale == FALSE) * IN/OUT: height accept height >=1 and <= original video height (ignored if do_scale == FALSE) * * return databuffer, Pixels are stored in the RGB colormdel * NULL is returned if the frame could not be fetched * (in case of ERRORS or End of File reasons) */ guchar * GVA_fetch_frame_to_buffer(t_GVA_Handle *gvahand , gboolean do_scale , gint32 framenumber , gint32 deinterlace , gdouble threshold , gint32 *bpp , gint32 *width , gint32 *height ) { guchar *frame_data; t_GVA_RetCode l_rc; /* check if the wanted framenr is available in the GVA framecache */ frame_data = GVA_frame_to_buffer(gvahand , do_scale , framenumber , deinterlace , threshold , bpp , width , height ); if(frame_data == NULL) { gint32 l_delta; gint32 l_readsteps; l_readsteps = 1; l_delta = framenumber - gvahand->current_frame_nr; l_rc = GVA_RET_OK; if((l_delta >= 1) && (l_delta <= 10)) { /* target framenumber is very near to the current_frame_nr * in this case positioning via sequential read is faster than seek */ l_readsteps = l_delta; } else { l_rc = GVA_seek_frame(gvahand, framenumber, GVA_UPOS_FRAMES); } while ((l_readsteps > 0) && (l_rc == GVA_RET_OK)) { l_rc = GVA_get_next_frame(gvahand); if(gap_debug) { printf("GVA_fetch_frame_to_buffer: l_readsteps:%d framenumber;%d curr:%d l_rc:%d\n" , (int)l_readsteps , (int)framenumber , (int)gvahand->current_frame_nr , (int)l_rc ); } l_readsteps--; } if(l_rc == GVA_RET_OK) { frame_data = GVA_frame_to_buffer(gvahand , do_scale , framenumber , deinterlace , threshold , bpp , width , height ); } } return(frame_data); } /* end GVA_fetch_frame_to_buffer */ gimp-gap-2.6.0+dfsg.orig/libgapvidapi/gap_vid_api_mpeg3toc.c0000644000175000017500000001327011212030253023612 0ustar thibautthibaut/* this file is a modified variante * of the meg3toc.c Code that came with libmpeg3-1.8 * * it is used to build the libmpeg3 * compatible "Table of content" files implicite * when using the GIMP-GAP specific GVA video API. * .TOC files are the libmpeg3 specific pendant to gvaindexes * and enable fast and exact positioning in the MPEG videofile * (but need one initial full scan to create) * * This variante of the toc file genration is used in GIMP-GAP * GUI Modules and provides Progress Feedback for the calling GUI * and has the option to STOP (cancel) TOC creation on GUI request. * * * * 2004.03.06 (hof) created */ #include "libmpeg3.h" #include "mpeg3protos.h" #include #include #include #include #include extern int gap_debug; /* ----------------------------- * p_get_total_frames_from_toc * ----------------------------- */ static gint32 p_get_total_frames_from_toc(char *toc_filename, int vid_track) { mpeg3_t *toc_handle; int l_error_return; gint32 total_frames; total_frames = 0; toc_handle = mpeg3_open(toc_filename, &l_error_return); if((toc_handle) && (l_error_return == 0)) { if(mpeg3_has_video(toc_handle)) { total_frames = mpeg3_video_frames(toc_handle, vid_track); } mpeg3_close(toc_handle); } /* end for repeat_count */ if(gap_debug) { printf("GVA: p_get_total_frames_from_toc libmpeg3 OPEN %s handle->toc_handle:%d l_error_return:%d total_frames:%d\n" , toc_filename , (int)toc_handle , (int)l_error_return , (int)total_frames ); } return (total_frames); } /* end p_get_total_frames_from_toc */ /* * Generate table of frame and sample offsets for editing. */ int GVA_create_libmpeg3_toc(int argc, char *argv[] , t_GVA_Handle *gvahand , int *ret_total_frames) { int i, j, l; char *src = 0, *dst = 0; int verbose = 0; gdouble progress_stepsize; progress_stepsize = 1.0 / (gdouble)(MAX(gvahand->total_frames, 1000)); gvahand->percentage_done = 0.05; if(gap_debug) { printf("GVA_create_libmpeg3_toc: gvahand->total_frames: %d stepsize:%.6f\n" , (int)gvahand->total_frames , (float)progress_stepsize ); } *ret_total_frames = -1; // hof: if(argc < 3) { fprintf(stderr, "Table of contents generator version %d.%d.%d\n" "Create a table of contents for a DVD or mpeg stream.\n" "Usage: mpeg3toc \n" "\n" "-v Print tracking information\n" "\n" "The path should be absolute unless you plan\n" "to always run your movie editor from the same directory\n" "as the filename. For renderfarms the filesystem prefix\n" "should be / and the movie directory mounted under the same\n" "directory on each node.\n\n" "Example: mpeg3toc -v /cdrom/video_ts/vts_01_0.ifo titanic.toc\n", mpeg3_major(), mpeg3_minor(), mpeg3_release()); exit(1); } for(i = 1; i < argc; i++) { if(!strcmp(argv[i], "-v")) { verbose = 1; } else if(argv[i][0] == '-') { fprintf(stderr, "Unrecognized command %s\n", argv[i]); exit(1); } else if(!src) { src = argv[i]; } else if(!dst) { dst = argv[i]; } else { fprintf(stderr, "Ignoring argument \"%s\"\n", argv[i]); } } if(!src) { fprintf(stderr, "source path not supplied.\n"); exit(1); } if(!dst) { fprintf(stderr, "destination path not supplied.\n"); exit(1); } int64_t total_bytes; mpeg3_t *file = mpeg3_start_toc(src, dst, &total_bytes); if(!file) { return 1;; } while(1) { int64_t bytes_processed = 0; mpeg3_do_toc(file, &bytes_processed); /* hof: handle GUI user cancel request */ { gvahand->percentage_done = CLAMP((bytes_processed / MAX(1, total_bytes)), 0.0, 1.0); gvahand->cancel_operation = (*gvahand->fptr_progress_callback)(gvahand->percentage_done, gvahand->progress_cb_user_data); if(gap_debug) { printf("MPEG3TOC: CANCEL(v):%d FPTR:%d\n" , (int)gvahand->cancel_operation , (int)gvahand->fptr_progress_callback ); } if(gvahand->cancel_operation) { mpeg3_stop_toc(file); return 1; } } if(bytes_processed >= total_bytes) break; } mpeg3_stop_toc(file); *ret_total_frames = p_get_total_frames_from_toc(dst, (int)gvahand->vid_track); return 0; } gimp-gap-2.6.0+dfsg.orig/libgapvidapi/gap_vid_api_ffmpeg.c0000644000175000017500000053414511212030253023346 0ustar thibautthibaut/* gap_vid_api_ffmpeg.c * * GAP Video read API implementation of libavformat/lbavcodec (also known as FFMPEG) * based wrappers to read various videofile formats * * 2007.11.04 update to ffmpeg svn snapshot 2007.10.31 * bugfix: selftest sometimes did not detect variable timecodes. * 2007.04.04 update to ffmpeg svn snapshot 2007.04.04, * droped support for older ffmpeg versions * 2007.03.21 support fmpeg native timecode based seek * 2007.03.12 update to ffmpeg svn snapshot 2007.03.12, * 2005.02.05 update to ffmpeg-0.4.9 (basically works now) * 2004.10.24 workaround initial frameread and reopen for detection of yuv_buff_pix_fmt * of the active codec. (works only after the 1.st frame was read) * 2004.04.12 vindex bugfix seek high framnumbers sometimes used wrong (last index) * 2004.03.07 vindex * 2004.02.29 hof fptr_progress_callback * 2003.05.09 hof created * */ /* ================================================ FFMPEG * FFMPEG (libavformat libavcodec) FFMPEG * ================================================ FFMPEG * ================================================ FFMPEG */ #ifdef ENABLE_GVA_LIBAVFORMAT #include "avformat.h" #include "stdlib.h" #include "gap_val_file.h" #include "audioconvert.h" #define READSTEPS_PROBE_TIMECODE 32 #define DEFAULT_NAT_SEEK_GOPSIZE 24 #define MAX_NAT_SEEK_GOPSIZE 8192 /* some defines to enable theme specific debug printf's * those defines are currently not configurable. */ #undef GAP_DEBUG_FF_NATIVE_SEEK #define MAX_TRIES_NATIVE_SEEK 3 #define GIMPRC_PERSISTENT_ANALYSE "video-gva-libavformat-video-analyse-persistent" #define ANALYSE_DEFAULT TRUE /* MAX_PREV_OFFSET defines how to record defered url_offest frames of previous frames for byte positions in video index * in tests the byte based seek takes us to n frames after the wanted frame. Therefore video index creation * tries to compensate this by recording the offsets of the nth pervious frame. * * tuning: values 1 upto 12 did not compensate enough. * this resulted in more than 1 SYNC LOOP when positioning vio byte position and makes video index slower. * */ #define MAX_PREV_OFFSET 14 /* ------------------------- * API READ extension FFMPEG * ------------------------- */ /* samples buffer for ca. 500 Audioframes at 48000 Hz Samplerate and 30 fps * if someone tries to get a bigger audio segment than this at once * the call will fail !! * (shall be defined >= AVCODEC_MAX_AUDIO_FRAME_SIZE (192000) */ #define GVA_SAMPLES_BUFFER_SIZE 2400000 #define GVA_FFMPEG_DECODER_NAME "libavformat" /* structure with FFMPEG specific file and codec handle pointers */ typedef struct t_GVA_ffmpeg { AVFormatContext *vid_input_context; AVFormatContext *aud_input_context; AVCodecContext *vid_codec_context; AVCodecContext *aud_codec_context; AVCodec *vcodec; AVCodec *acodec; AVStream *vid_stream; /* pointer to to vid_input_context->streams[vid_track] */ AVStream *aud_stream; /* pointer to to aud_input_context->streams[aud_track] */ AVPacket vid_pkt; /* the current packet (read from the video stream) */ AVPacket aud_pkt; /* the current packet (read from the audio stream) */ AVAudioConvert *reformat_ctx; /* for audioformat conversion */ AVFrame big_picture_rgb; AVFrame big_picture_yuv; AVPicture *picture_rgb; AVPicture *picture_yuv; enum PixelFormat yuv_buff_pix_fmt; /*UNIT8*/ guchar *yuv_buffer; /*UNIT8*/ guchar *inbuf_ptr; int inbuf_len; /*UNIT8*/ guchar *abuf_ptr; int abuf_len; guchar *output_samples_ptr; /* current write position (points somewhere into samples_buffer) */ gint bf_idx; /* 0 or 1 (index of the active samples_buffer) */ gint32 samples_buffer_size; guchar *samples_buffer[2]; /* Buffer for decoded samples from samples_base_a until read position */ gint32 samples_base[2]; /* start offset of the samples_buffers (unit is samples) */ gint32 bytes_filled[2]; /* how many bytes are filled into samples_buffer(s) */ gint32 biggest_data_size; /* the biggest uncompressed audio packet found (min 4096) */ gdouble samples_read; /* how many (decoded) samples already read into samples_buffer * since (RE)open the audio context */ gboolean dummy_read; /* FALSE: read YUV + convert to RGB, TRUE: dont convert RGB */ gboolean capture_offset; /* TRUE: capture url_offsets to vindex while reading next frame */ gint32 max_frame_len; gint32 frame_len; guint16 got_frame_length16; /* 16 lower bits of the length */ gint64 prev_url_offset[MAX_PREV_OFFSET]; gint32 prev_key_seek_nr; gdouble guess_gop_size; int vid_stream_index; int aud_stream_index; int vid_codec_id; int aud_codec_id; gboolean key_frame_detection_works; gboolean timecode_proberead_done; gint64 timecode_offset_frame1; /* dts timecode offset of the 1st frame (value -1 for not known) */ gint32 timecode_step_avg; /* average timecode step per frame (value -1 for not known) */ gint32 timecode_step_abs_min; /* absolute value of smallest detected stepsize */ gint32 timecode_steps_sum; /* average timecode step per frame (value -1 for not known) */ gint32 count_timecode_steps; gint32 timecode_steps[READSTEPS_PROBE_TIMECODE]; gint32 video_libavformat_seek_gopsize; /* gimprc parameter controls native seek 0==DISABLE */ gint32 native_timecode_seek_failcount; /* increased when expected timecode cant be found (seek after EOF is not counted) */ gint64 eof_timecode; /* timecode after the last frame */ gboolean self_test_detected_seek_bug; gint32 max_tries_native_seek; gint32 readsteps_probe_timecode; gint32 timestamp; /* videofile last modification utc time */ gboolean prefere_native_seek; /* prefere native seek if both vindex and native seek available */ gboolean all_timecodes_verified; gboolean critical_timecodesteps_found; unsigned char * chunk_ptr; gint32 chunk_len; } t_GVA_ffmpeg; static void p_ffmpeg_vid_reopen_read(t_GVA_ffmpeg *handle, t_GVA_Handle *gvahand); static void p_ffmpeg_aud_reopen_read(t_GVA_ffmpeg *handle, t_GVA_Handle *gvahand); static gboolean p_ff_open_input(char *filename, t_GVA_Handle *gvahand, t_GVA_ffmpeg* handle, gboolean vid_open); static void p_set_aspect_ratio(t_GVA_Handle *gvahand, t_GVA_ffmpeg* handle); static void p_reset_proberead_results(t_GVA_ffmpeg* handle); static gboolean p_seek_timecode_reliability_self_test(t_GVA_Handle *gvahand); static void p_detect_total_frames_via_native_seek(t_GVA_Handle *gvahand); static void p_inc_native_timecode_seek_failcount(t_GVA_Handle *gvahand); static void p_clear_inbuf_and_vid_packet(t_GVA_ffmpeg *handle); static t_GVA_RetCode p_seek_private(t_GVA_Handle *gvahand , gdouble pos , t_GVA_PosUnit pos_unit ); static t_GVA_RetCode p_seek_native_timcode_based(t_GVA_Handle *gvahand , gint32 target_frame); static int p_audio_convert_to_s16(t_GVA_ffmpeg *handle , int data_size ); static gint32 p_pick_channel( t_GVA_ffmpeg *handle , t_GVA_Handle *gvahand , gint16 *output_i , gint32 sample_idx , gint32 samples , gint32 channel ); static int p_read_audio_packets(t_GVA_ffmpeg *handle , t_GVA_Handle *gvahand , gint32 max_sample_pos); static void p_vindex_add_url_offest(t_GVA_Handle *gvahand , t_GVA_ffmpeg *handle , t_GVA_Videoindex *vindex , gint32 seek_nr , gint64 url_offset , guint16 frame_length , guint16 checksum , gint64 timecode_dts ); static guint16 p_gva_checksum(AVPicture *picture_yuv, gint32 height); static t_GVA_RetCode p_wrapper_ffmpeg_get_next_frame(t_GVA_Handle *gvahand); static FILE * p_init_timecode_log(t_GVA_Handle *copy_gvahand); static void p_timecode_check_and_log(FILE *fp_timecode_log, gint32 framenr , t_GVA_ffmpeg *handle , t_GVA_ffmpeg *master_handle , t_GVA_Handle *gvahand); static void p_set_analysefile_master_keywords(GapValKeyList *keylist , t_GVA_Handle *gvahand , gint32 count_timecode_steps); static void p_save_video_analyse_results(t_GVA_Handle *gvahand); static gboolean p_get_video_analyse_results(t_GVA_Handle *gvahand); static char* p_create_analysefile_name(t_GVA_Handle *gvahand); static gint32 p_timecode_to_frame_nr(t_GVA_ffmpeg *handle, int64_t timecode); static int64_t p_frame_nr_to_timecode(t_GVA_ffmpeg *handle, gint32 frame_nr); static void p_analyze_stepsize_pattern(gint max_idx, t_GVA_Handle *gvahand); static void p_probe_timecode_offset(t_GVA_Handle *gvahand); static t_GVA_RetCode p_wrapper_ffmpeg_seek_frame(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit); static t_GVA_RetCode p_wrapper_ffmpeg_get_next_frame(t_GVA_Handle *gvahand); static t_GVA_RetCode p_private_ffmpeg_get_next_frame(t_GVA_Handle *gvahand, gboolean do_copy_raw_chunk_data); /* ----------------------------- * p_wrapper_ffmpeg_check_sig * ----------------------------- */ static inline gboolean p_areTimecodesEqualWithTolerance(gint64 timecode1, gint64 timecode2) { #define TIMECODE_EQ_TOLERANCE 2 return (abs(timecode1 - timecode2) <= TIMECODE_EQ_TOLERANCE); } /* ----------------------------- * p_wrapper_ffmpeg_check_sig * ----------------------------- * TODO: should also check supported codec (for vid_track and aud_track but need this info as calling parameter !!) */ gboolean p_wrapper_ffmpeg_check_sig(char *filename) { AVFormatContext *ic; int err, ret; if(gap_debug) printf("p_wrapper_ffmpeg_check_sig: START filename:%s\n", filename); /* ------------ File Format ------- */ /* open the input file with generic libav function * (do not force a specific format) */ err = av_open_input_file(&ic, filename, NULL, 0, NULL); if (err < 0) { if(gap_debug) printf("p_wrapper_ffmpeg_check_sig: av_open_input_file FAILED: %d\n", (int)err); return(FALSE); } /* If not enough info to get the stream parameters, we decode the * first frames to get it. (used in mpeg case for example) */ ret = av_find_stream_info(ic); if (ret < 0) { if(gap_debug) printf("p_wrapper_ffmpeg_check_sig:%s: could not find codec parameters\n", filename); return(FALSE); } av_close_input_file(ic); if(gap_debug) printf("p_wrapper_ffmpeg_check_sig: compatible is TRUE\n"); return (TRUE); } /* end p_wrapper_ffmpeg_check_sig */ /* ----------------------------- * p_wrapper_ffmpeg_open_read * ----------------------------- * Open the fileformat * Open the needed decoder codecs (video and audio) * - set the CodecContext * - do we need AVStream vid_stream, aud_stream and howto init and use that ? * - init picture (rowpointers) * TODO: * - howto findout total_frames (and total_samples) */ void p_wrapper_ffmpeg_open_read(char *filename, t_GVA_Handle *gvahand) { t_GVA_ffmpeg* handle; AVInputFormat *iformat; if(gap_debug) printf("p_wrapper_ffmpeg_open_read: START filename:%s\n", filename); if(gvahand->filename == NULL) { gvahand->filename = g_strdup(filename); } gvahand->decoder_handle = (void *)NULL; gvahand->vtracks = 0; gvahand->atracks = 0; gvahand->frame_bpp = 3; /* RGB pixelformat */ handle = g_malloc0(sizeof(t_GVA_ffmpeg)); handle->dummy_read = FALSE; handle->capture_offset = FALSE; handle->guess_gop_size = 0; { gint ii; for(ii=0; ii < MAX_PREV_OFFSET; ii++) { handle->prev_url_offset[ii] = 0; } } handle->prev_key_seek_nr = 1; handle->max_frame_len = 0; handle->got_frame_length16 = 0; handle->vid_input_context = NULL; /* set later (if has video) */ handle->aud_input_context = NULL; /* set later (if has audio) */ handle->vid_codec_context = NULL; /* set later (if has video) */ handle->aud_codec_context = NULL; /* set later (if has audio) */ handle->vcodec = NULL; /* set later (if has video and vid_track > 0) */ handle->acodec = NULL; /* set later (if has audio and aud_track > 0) */ handle->vid_stream_index = -1; handle->aud_stream_index = -1; handle->vid_codec_id = 0; handle->aud_codec_id = 0; handle->vid_pkt.size = 0; /* start with empty packet */ handle->vid_pkt.data = NULL; /* start with empty packet */ handle->aud_pkt.size = 0; /* start with empty packet */ handle->aud_pkt.data = NULL; /* start with empty packet */ handle->samples_buffer[0] = NULL; /* set later (at 1.st audio packet read) */ handle->samples_buffer[1] = NULL; /* set later (at 1.st audio packet read) */ handle->samples_base[0] = 0; handle->samples_base[1] = 0; handle->bytes_filled[0] = 0; handle->bytes_filled[1] = 0; handle->biggest_data_size = 4096; handle->output_samples_ptr = NULL; /* current write position (points somewhere into samples_buffer) */ handle->reformat_ctx = NULL; /* context for audio conversion (only in case input is NOT SAMPLE_FMT_S16) */ handle->samples_buffer_size = 0; handle->samples_read = 0; handle->key_frame_detection_works = FALSE; /* assume a Codec with non working detection */ handle->chunk_len = 0; handle->chunk_ptr = NULL; p_reset_proberead_results(handle); handle->prefere_native_seek = FALSE; handle->all_timecodes_verified = FALSE; handle->critical_timecodesteps_found = FALSE; /* open for the VIDEO part */ if(FALSE == p_ff_open_input(filename, gvahand, handle, TRUE)) { g_free(handle); if(gap_debug) printf("p_wrapper_ffmpeg_open_read: open Videopart FAILED\n"); return; } if(gvahand->aud_track >= 0) { /* open a separate input context for the AUDIO part */ if(FALSE == p_ff_open_input(filename, gvahand, handle, FALSE)) { g_free(handle); if(gap_debug) printf("p_wrapper_ffmpeg_open_read: open Audiopart FAILED\n"); return; } } if((handle->vid_stream_index == -1) && (handle->aud_stream_index == -1)) { g_free(handle); if(gap_debug) printf("p_wrapper_ffmpeg_open_read: neither video nor audio codec found\n"); return; /* give up if both video_codec and audio_codec are not supported */ } /* set detailed decoder description */ iformat = handle->vid_input_context->iformat; if(iformat) { gchar *vcodec_name; gchar *acodec_name; t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(dec_elem) { if(dec_elem->decoder_description) { g_free(dec_elem->decoder_description); } if(handle->vcodec) { vcodec_name = g_strdup(handle->vcodec->name); } else { vcodec_name = g_strdup("** no video codec **"); } if(handle->acodec) { acodec_name = g_strdup(handle->acodec->name); } else { acodec_name = g_strdup("** no audio codec **"); } dec_elem->decoder_description = g_strdup_printf("FFMPEG Decoder (Decoder for MPEG1,MPEG4(DivX),RealVideo)\n" " (EXT: .mpg,.vob,.avi,.rm,.mpeg)\n" "active FORMAT: %s %s\n" "active CODEC(S): %s %s" , iformat->name , iformat->long_name , vcodec_name , acodec_name ); g_free(vcodec_name); g_free(acodec_name); } } handle->inbuf_len = 0; /* start with empty buffer */ handle->frame_len = 0; /* start with 0 frame length */ handle->inbuf_ptr = NULL; /* start with empty buffer, after 1.st av_read_frame: pointer to pkt.data read pos */ /* yuv_buffer big enough for all supported PixelFormats * (the vid_codec_context->pix_fmt may change later (?) * but i want to use one all purpose yuv_buffer all the time * while the video is open for performance reasons) */ handle->yuv_buffer = g_malloc0(gvahand->width * gvahand->height * 4); /* total_frames and total_aud_samples are just a guess, based on framesize and filesize * It seems that libavformat does not provide a method to get the exact value. * (maybe due to the support of streaming where the size is not yet konwn at open time) */ gvahand->total_frames = p_guess_total_frames(gvahand); gvahand->total_aud_samples = 0; if((gvahand->atracks > 0) && (handle->aud_stream_index >= 0)) { gvahand->total_aud_samples = (gint32)GVA_frame_2_samples(gvahand->framerate, gvahand->samplerate, gvahand->total_frames); } /* Picture field are filled with 'ptr' addresses */ handle->picture_rgb = (AVPicture *)&handle->big_picture_rgb; handle->picture_yuv = (AVPicture *)&handle->big_picture_yuv; /* allocate frame_data and row_pointers for one frame (minimal cachesize 1 == no chaching) * (calling apps may request bigger cache after successful open) */ p_build_frame_cache(gvahand, 1); avpicture_fill(handle->picture_rgb ,gvahand->frame_data ,PIX_FMT_RGB24 /* PIX_FMT_RGB24, PIX_FMT_RGBA32, PIX_FMT_BGRA32 */ ,gvahand->width ,gvahand->height ); /* * vid_codec_context->pix_fmt may change later, and is sometimes * not recognized until the 1.st frame has been decoded. * therefore the follwing avpicture_fill is just a 1.st guess * and must be repeated later to be sure to know the codec's native pix_fmt * But this does decode the the 1.st frame with the wrong PIX_FMT settings * - most MPEG codecs (VCD, DVD..) use the default PIX_FMT_YUV420P * and work fine without problems * - Quicktime codec (codec_id == 10) uses PIX_FMT_YUV422P ( Olympus C4040Z Digicam MJPEG .mov files) */ handle->yuv_buff_pix_fmt = handle->vid_codec_context->pix_fmt; /* PIX_FMT_YUV420P */ avpicture_fill(handle->picture_yuv ,handle->yuv_buffer ,handle->yuv_buff_pix_fmt ,gvahand->width ,gvahand->height ); gvahand->decoder_handle = (void *)handle; /* workaround: initial frameread and reopen for detection of yuv_buff_pix_fmt */ { if(gap_debug) { printf("INITIAL call p_wrapper_ffmpeg_get_next_frame\n"); } p_wrapper_ffmpeg_get_next_frame(gvahand); p_set_aspect_ratio(gvahand, handle); /* reset seek position */ p_ffmpeg_vid_reopen_read(handle, gvahand); gvahand->current_frame_nr = 0; gvahand->current_seek_nr = 1; } if(gap_debug) { printf("gvahand->width: %d gvahand->height: %d aspect_ratio:%f\n", (int)gvahand->width , (int)gvahand->height, (float)gvahand->aspect_ratio); printf("picture_rgb: data[0]: %d linesize[0]: %d\n", (int)handle->picture_rgb->data[0], (int)handle->picture_rgb->linesize[0]); printf("picture_rgb: data[1]: %d linesize[1]: %d\n", (int)handle->picture_rgb->data[1], (int)handle->picture_rgb->linesize[1]); printf("picture_rgb: data[2]: %d linesize[2]: %d\n", (int)handle->picture_rgb->data[2], (int)handle->picture_rgb->linesize[2]); printf("picture_rgb: data[3]: %d linesize[3]: %d\n", (int)handle->picture_rgb->data[3], (int)handle->picture_rgb->linesize[3]); printf("picture_yuv: data[0]: %d linesize[0]: %d\n", (int)handle->picture_yuv->data[0], (int)handle->picture_yuv->linesize[0]); printf("picture_yuv: data[1]: %d linesize[1]: %d\n", (int)handle->picture_yuv->data[1], (int)handle->picture_yuv->linesize[1]); printf("picture_yuv: data[2]: %d linesize[2]: %d\n", (int)handle->picture_yuv->data[2], (int)handle->picture_yuv->linesize[2]); printf("picture_yuv: data[3]: %d linesize[3]: %d\n", (int)handle->picture_yuv->data[3], (int)handle->picture_yuv->linesize[3]); printf("handle->yuv_buff_pix_fmt: %d\n", (int)handle->yuv_buff_pix_fmt); } if(gvahand->vindex == NULL) { gvahand->vindex = GVA_load_videoindex(gvahand->filename, gvahand->vid_track, GVA_FFMPEG_DECODER_NAME); if(gvahand->vindex) { if(gvahand->vindex->total_frames > 1) { /* we have a complete vindex and can * trust the total_frames in the vindex file */ gvahand->total_frames = gvahand->vindex->total_frames; gvahand->all_frames_counted = TRUE; } } } if(gap_debug) //####XXXXXXXXXXXXXx { if(gvahand->vindex) { if(gvahand->vindex->videoindex_filename) { printf("IDX: p_wrapper_ffmpeg_open_read: vindex->videoindex_filename %s\n" " vindex->total_frames:%d\n" , gvahand->vindex->videoindex_filename , gvahand->vindex->total_frames ); } else { printf("IDX: p_wrapper_ffmpeg_open_read: vindex->videoindex_filename is NULL\n"); } } else { printf("IDX: p_wrapper_ffmpeg_open_read: vindex is NULL\n"); } printf("p_wrapper_ffmpeg_open_read: END, OK\n"); } } /* end p_wrapper_ffmpeg_open_read */ /* ----------------------------- * p_wrapper_ffmpeg_close * ----------------------------- * TODO: * - howto close codec, codec ontext ... and whatever ... */ void p_wrapper_ffmpeg_close(t_GVA_Handle *gvahand) { t_GVA_ffmpeg *handle; if(gap_debug) printf("p_wrapper_ffmpeg_close: START\n"); handle = (t_GVA_ffmpeg *)gvahand->decoder_handle; if(handle->samples_buffer[0]) { if(gap_debug) printf("p_wrapper_ffmpeg_close: FREE audio samples_buffer\n"); g_free(handle->samples_buffer[0]); handle->samples_buffer[0] = NULL; g_free(handle->samples_buffer[1]); handle->samples_buffer[1] = NULL; } if(handle->yuv_buffer) { if(gap_debug) printf("p_wrapper_ffmpeg_close: FREE YUV_BUFFER\n"); g_free(handle->yuv_buffer); handle->yuv_buffer = NULL; } if((handle->vid_codec_context) && (handle->vcodec)) { if(gap_debug) printf("p_wrapper_ffmpeg_close: avcodec_close VIDEO_CODEC: %s\n", handle->vcodec->name); avcodec_close(handle->vid_codec_context); handle->vid_codec_context = NULL; /* ?????????? do not attempt to free handle->vid_codec_context (it points to &handle->vid_stream.codec) */ } if((handle->aud_codec_context) && (handle->acodec)) { if(gap_debug) printf("p_wrapper_ffmpeg_close: avcodec_close AUDIO_CODEC: %s\n", handle->acodec->name); avcodec_close(handle->aud_codec_context); handle->aud_codec_context = NULL; /* ??????? do not attempt to free handle->aud_codec_context (it points to &handle->aud_stream.codec) */ } /* Close a media file (but not its codecs) */ if(gap_debug) printf("p_wrapper_ffmpeg_close: av_close_input_file\n"); if(handle->vid_input_context) av_close_input_file(handle->vid_input_context); if(handle->aud_input_context) av_close_input_file(handle->aud_input_context); if(gap_debug) printf("p_wrapper_ffmpeg_close: END\n"); } /* end p_wrapper_ffmpeg_close */ /* ---------------------------------- * p_wrapper_ffmpeg_get_codec_name * ---------------------------------- * read one frame as raw data from the video_track (stream) * note that raw data is not yet decoded and contains * videofileformat specific frame header information. * this procedure is intended to 1:1 (lossless) copy of frames */ char * p_wrapper_ffmpeg_get_codec_name(t_GVA_Handle *gvahand ,t_GVA_CodecType codec_type ,gint32 track_nr ) { t_GVA_ffmpeg *handle; handle = (t_GVA_ffmpeg *)gvahand->decoder_handle; if(handle == NULL) { if(gap_debug) { printf("p_wrapper_ffmpeg_get_codec_name handle == NULL\n"); } return(NULL); } if (codec_type == GVA_VIDEO_CODEC) { if(handle->vcodec) { if(gap_debug) { printf("p_wrapper_ffmpeg_get_codec_name handle->vcodec == %s\n", handle->vcodec->name); } return(g_strdup(handle->vcodec->name)); } } if (codec_type == GVA_AUDIO_CODEC) { if(handle->acodec) { if(gap_debug) { printf("p_wrapper_ffmpeg_get_codec_name handle->acodec == %s\n", handle->acodec->name); } return(g_strdup(handle->acodec->name)); } } if(gap_debug) { printf("p_wrapper_ffmpeg_get_codec_name codec is NULL\n"); } return(NULL); } /* end p_wrapper_ffmpeg_get_codec_name */ /* ---------------------------------- * p_wrapper_ffmpeg_get_video_chunk * ---------------------------------- * read one frame as raw data from the video_track (stream) * note that raw data is not yet decoded and contains * videofileformat specific frame header information. * this procedure is intended to 1:1 (lossless) copy of frames */ t_GVA_RetCode p_wrapper_ffmpeg_get_video_chunk(t_GVA_Handle *gvahand , gint32 frame_nr , unsigned char *chunk , gint32 *size , gint32 max_size) { t_GVA_RetCode l_rc; t_GVA_ffmpeg *handle; if(frame_nr < 1) { /* illegal frame_nr (first frame starts at Nr 1 */ return(GVA_RET_ERROR); } handle = (t_GVA_ffmpeg *)gvahand->decoder_handle; if(handle == NULL) { return(GVA_RET_ERROR); } /* check if current position is before the wanted frame */ if (frame_nr != gvahand->current_seek_nr) { gdouble pos; pos = frame_nr; l_rc = p_wrapper_ffmpeg_seek_frame(gvahand, pos, GVA_UPOS_FRAMES); if (l_rc != GVA_RET_OK) { return (l_rc); } } l_rc = p_private_ffmpeg_get_next_frame(gvahand, TRUE); if(handle->chunk_len > max_size) { printf("CALLING ERROR p_wrapper_ffmpeg_get_video_chunk chunk_len:%d is greater than sepcified max_size:%d\n" ,(int)handle->chunk_len ,(int)max_size ); return(GVA_RET_ERROR); } if(handle->chunk_ptr == NULL) { printf("CALLING ERROR p_wrapper_ffmpeg_get_video_chunk fetch raw frame failed, chunk_ptr is NULL\n"); return(GVA_RET_ERROR); } if(gap_debug) { char *vcodec_name; vcodec_name = "NULL"; if(handle->vcodec) { if(handle->vcodec->name) { vcodec_name = handle->vcodec->name; } } printf("p_wrapper_ffmpeg_get_video_chunk: chunk:%d chunk_ptr:%d, chunk_len:%d vcodec_name:%s\n" ,(int)chunk ,(int)handle->chunk_ptr ,(int)handle->chunk_len ,vcodec_name ); } *size = handle->chunk_len; memcpy(chunk, handle->chunk_ptr, handle->chunk_len); return (l_rc); } /* end p_wrapper_ffmpeg_get_video_chunk */ /* ---------------------------------- * p_wrapper_ffmpeg_get_next_frame * ---------------------------------- * read one frame from the video_track (stream) * and decode the frame * when EOF reached: update total_frames and close the stream) */ static t_GVA_RetCode p_wrapper_ffmpeg_get_next_frame(t_GVA_Handle *gvahand) { p_private_ffmpeg_get_next_frame(gvahand, FALSE); } /* end p_wrapper_ffmpeg_get_next_frame*/ /* ---------------------------------- * p_url_ftell * ---------------------------------- * GIMP-GAP private variant of url_ftell procedure * (original implementation see see libacformat/aviobuf.c) * * restrictions: * only the part for input strams is supported. * (e.g. write_flag is ignored here) * includes some chacks for inplausible results. * * the internal calculation looks like this: * pos = s->pos - (s->write_flag ? 0 : (s->buf_end - s->buffer)); * return pos + (s->buf_ptr - s->buffer) * */ inline static int64_t p_url_ftell(ByteIOContext *s) { int64_t currentOffsetInStream; int64_t bytesReadInBuffer; int64_t bytesAlreadyHandledInBuffer; int64_t bufferStartOffsetInStream; if(s == NULL) { return (0); } /* ignore negative buffer size (in such cases the buffer is rather empty or not initialized properly) */ bytesReadInBuffer = MAX(0, (s->buf_end - s->buffer)); /* ignore negative buffer size (in such cases the buffer is rather empty or not initialized properly) */ bytesAlreadyHandledInBuffer = 0; if((s->buf_ptr >= s->buffer) && (s->buf_ptr <= s->buf_end)) { bytesAlreadyHandledInBuffer = MAX(0, (s->buf_ptr - s->buffer)); } else { printf(" ** ERROR current buf_ptr:%d points outside of the buffer (start: %d end:%d)\n" ,(int)s->buf_ptr ,(int)s->buffer ,(int)s->buf_end ); } /* ignore inplausible staart offsets */ bufferStartOffsetInStream = 0; if(s->pos > bytesReadInBuffer) { bufferStartOffsetInStream = s->pos - bytesReadInBuffer; } currentOffsetInStream = bufferStartOffsetInStream + bytesAlreadyHandledInBuffer; printf("P_URL_FTELL: url64:%lld pos: %lld, wr_flag:%d, buffer:%d buf_end:%d buf_ptr:%d\n" " bufferStartOffsetInStream:%lld, bytesReadInBuffer:%lld bytesAlreadyHandledInBuffer:%lld\n\n" ,currentOffsetInStream ,s->pos ,(int)s->write_flag ,(int)s->buffer ,(int)s->buf_end ,(int)s->buf_ptr ,bufferStartOffsetInStream ,bytesReadInBuffer ,bytesAlreadyHandledInBuffer ); return (currentOffsetInStream); } /* ---------------------------------- * p_private_ffmpeg_get_next_frame * ---------------------------------- * read one frame from the video_track (stream) * and decode the frame * when EOF reached: update total_frames and close the stream) * if recording of videoindex is enabled (in the handle) * then record positions of keyframes in the videoindex. * the flag do_copy_raw_chunk_data triggers copying the frame as raw data * chunk (useful for lossless video cut purpose) */ static t_GVA_RetCode p_private_ffmpeg_get_next_frame(t_GVA_Handle *gvahand, gboolean do_copy_raw_chunk_data) { t_GVA_ffmpeg *handle; int l_got_picture; int l_rc; gint64 l_curr_url_offset; gint64 l_record_url_offset; gint32 l_url_seek_nr; gint32 l_len; gint32 l_pkt_size; guint16 l_frame_len; /* 16 lower bits of the length */ guint16 l_checksum; gboolean l_potential_index_frame; gboolean l_key_frame_detected; handle = (t_GVA_ffmpeg *)gvahand->decoder_handle; /* redirect picture_rgb pointers to current fcache element */ avpicture_fill(handle->picture_rgb ,gvahand->frame_data ,PIX_FMT_RGB24 /* PIX_FMT_RGB24, PIX_FMT_RGBA32, PIX_FMT_BGRA32 */ ,gvahand->width ,gvahand->height ); l_got_picture = 0; l_rc = 0; l_len = 0; l_frame_len = 0; l_pkt_size = 0; l_record_url_offset = -1; l_curr_url_offset = -1; l_url_seek_nr = gvahand->current_seek_nr; l_key_frame_detected = FALSE; while(l_got_picture == 0) { int l_pktlen; /* if inbuf is empty we must read the next packet */ if((handle->inbuf_len < 1) || (handle->inbuf_ptr == NULL)) { /* query current position in the file url_ftell * Note that url_ftell operates on the ByteIOContext handle->vid_input_context->pb * and calculates correct file position by taking both the current (buffered) read position * and buffer position into account. */ //l_curr_url_offset = p_url_ftell(handle->vid_input_context->pb); l_curr_url_offset = url_ftell(handle->vid_input_context->pb); /* if (gap_debug) printf("p_wrapper_ffmpeg_get_next_frame: before av_read_frame\n"); */ /** * Read a packet from a media file * @param s media file handle * @param pkt is filled * @return 0 if OK. AVERROR_xxx(negative) if error. */ l_pktlen = av_read_frame(handle->vid_input_context, &handle->vid_pkt); if(l_pktlen < 0) { /* EOF reached */ if (gap_debug) { printf("p_wrapper_ffmpeg_get_next_frame: EOF reached (or read ERROR)" " (old)total_frames:%d current_frame_nr:%d all_frames_counted:%d\n" ,(int) gvahand->total_frames ,(int) gvahand->current_frame_nr ,(int) gvahand->all_frames_counted ); } l_record_url_offset = -1; if (!gvahand->all_frames_counted) { gvahand->total_frames = gvahand->current_frame_nr; gvahand->all_frames_counted = TRUE; } if(handle->aud_stream_index >= 0) { /* calculate number of audio samples * (assuming that audio track has same duration as video track) */ gvahand->total_aud_samples = (gint32)GVA_frame_2_samples(gvahand->framerate, gvahand->samplerate, gvahand->total_frames); } p_clear_inbuf_and_vid_packet(handle); l_rc = 1; break; } /* if (gap_debug) printf("vid_stream:%d pkt.stream_index #%d, pkt.size: %d\n", handle->vid_stream_index, handle->vid_pkt.stream_index, handle->vid_pkt.size); */ /* check if packet belongs to the selected video stream */ if(handle->vid_pkt.stream_index != handle->vid_stream_index) { /* discard packet */ /* if (gap_debug) printf("DISCARD Packet\n"); */ av_free_packet(&handle->vid_pkt); l_record_url_offset = -1; continue; } /* packet is part of the selected video stream, use that packet */ handle->inbuf_ptr = handle->vid_pkt.data; handle->inbuf_len = handle->vid_pkt.size; l_pkt_size = handle->vid_pkt.size; handle->frame_len += l_pkt_size; if(gap_debug) { printf("using Packet data:%d size:%d handle->frame_len:%d dts:%lld pts:%lld AV_NOPTS_VALUE:%lld\n" ,(int)handle->vid_pkt.data ,(int)handle->vid_pkt.size ,(int)handle->frame_len , handle->vid_pkt.dts , handle->vid_pkt.pts , AV_NOPTS_VALUE ); } } if (gap_debug) { printf("before avcodec_decode_video: inbuf_ptr:%d inbuf_len:%d\n", (int)handle->inbuf_ptr, (int)handle->inbuf_len); } /* --------- START potential CHUNK ----- */ /* make a copy of the raw data packages for one video frame. * (we do not yet know if the raw data chunk is complete until * avcodec_decode_video indicates a complete frame by setting the * got_picture flag to TRUE) */ if (do_copy_raw_chunk_data == TRUE) { if (handle->chunk_ptr != NULL) { g_free(handle->chunk_ptr); handle->chunk_ptr = NULL; handle->chunk_len = 0; } handle->chunk_len = handle->inbuf_len; if (handle->chunk_len > 0) { handle->chunk_ptr = g_malloc(handle->chunk_len); memcpy(handle->chunk_ptr, handle->inbuf_ptr, handle->chunk_len); if (gap_debug) { printf("copy potential raw chunk: chunk_ptr:%d chunk_len:%d\n", (int)handle->chunk_ptr, (int)handle->chunk_len); } } } /* --------- END potential CHUNK ----- */ avcodec_get_frame_defaults(&handle->big_picture_yuv); /* decode a frame. return -1 if error, otherwise return the number of * bytes used. If no frame could be decompressed, *got_picture_ptr is * zero. Otherwise, it is non zero. */ l_len = avcodec_decode_video(handle->vid_codec_context /* AVCodecContext * */ ,&handle->big_picture_yuv ,&l_got_picture ,handle->inbuf_ptr ,handle->inbuf_len ); /*if (gap_debug) printf("after avcodec_decode_video: l_len:%d got_pic:%d\n", (int)l_len, (int)l_got_picture);*/ if(handle->yuv_buff_pix_fmt != handle->vid_codec_context->pix_fmt) { if(gap_debug) { printf("$$ pix_fmt: old:%d new from codec:%d (PIX_FMT_YUV420P:%d PIX_FMT_YUV422P:%d)\n" , (int)handle->yuv_buff_pix_fmt , (int)handle->vid_codec_context->pix_fmt , (int)PIX_FMT_YUV420P , (int)PIX_FMT_YUV422P ); } handle->yuv_buff_pix_fmt = handle->vid_codec_context->pix_fmt; /* PIX_FMT_YUV420P */ avpicture_fill(handle->picture_yuv ,handle->yuv_buffer ,handle->yuv_buff_pix_fmt ,gvahand->width ,gvahand->height ); } if(l_len < 0) { printf("p_wrapper_ffmpeg_get_next_frame: avcodec_decode_video returned ERROR)\n"); l_rc = 2; break; } handle->inbuf_ptr += l_len; handle->inbuf_len -= l_len; if(l_got_picture) { l_frame_len = (l_len & 0xffff); handle->frame_len = (l_len - l_pkt_size); l_record_url_offset = l_curr_url_offset; l_key_frame_detected = ((handle->vid_pkt.flags & PKT_FLAG_KEY) != 0); if(gap_debug) { /* log information that could be relevant for redesign of VINDEX creation */ printf("GOT PICTURE current_seek_nr:%06d pp_prev_offset:%lld url_offset:%lld keyflag:%d dts:%lld flen16:%d len:%d\n" , (int)gvahand->current_seek_nr , handle->prev_url_offset[MAX_PREV_OFFSET -1] , l_record_url_offset , (handle->vid_pkt.flags & PKT_FLAG_KEY) , handle->vid_pkt.dts ,(int)l_frame_len ,(int)l_len ); } } /* length of video packet was completely processed, we can free that packet now */ if(handle->inbuf_len < 1) { /* if (gap_debug) printf("FREE Packet\n"); */ av_free_packet(&handle->vid_pkt); handle->vid_pkt.size = 0; /* set empty packet status */ handle->vid_pkt.data = NULL; /* set empty packet status */ } } /* end while packet_read and decode frame loop */ if((l_rc == 0) && (l_got_picture)) { if(gvahand->current_seek_nr > 1) { /* 1.st frame_len may contain headers (size may be too large) */ handle->max_frame_len = MAX(handle->max_frame_len, l_len); } handle->got_frame_length16 = l_frame_len; if(gap_debug) { printf("GOT PIC: current_seek_nr:%06d l_frame_len:%d got_pic:%d key:%d\n" , (int)gvahand->current_seek_nr , (int)handle->got_frame_length16 , (int)l_got_picture , (int)handle->big_picture_yuv.key_frame ); } if(handle->dummy_read == FALSE) { if (gap_debug) printf("p_wrapper_ffmpeg_get_next_frame: before img_convert\n"); /* avcodec.img_convert convert among pixel formats */ l_rc = img_convert(handle->picture_rgb , PIX_FMT_RGB24 /* dst */ ,handle->picture_yuv ,handle->yuv_buff_pix_fmt /* src */ ,gvahand->width ,gvahand->height ); /* if (gap_debug) printf("p_wrapper_ffmpeg_get_next_frame: after img_convert l_rc:%d\n", (int)l_rc); */ } #define GVA_LOW_GOP_LIMIT 24 #define GVA_HIGH_GOP_LIMIT 100 l_potential_index_frame = FALSE; if((handle->big_picture_yuv.key_frame == 1) || (l_key_frame_detected == TRUE)) { l_potential_index_frame = TRUE; handle->key_frame_detection_works = TRUE; } else { if(handle->key_frame_detection_works == FALSE) { if(l_url_seek_nr >= handle->prev_key_seek_nr + GVA_HIGH_GOP_LIMIT) { /* some codecs do not deliver key_frame information even if all frames are stored * as keyframes. * this would result in empty videoindexes for videoreads using such codecs * and seek ops would be done as sequential reads as if we had no videoindexes at all. * the GVA_HIGH_GOP_LIMIT allows creation of videoindexes * to store offesets of frames that are NOT explicite marked as keyframes. * but never use non-keyframes for codecs with working key_frame detection. * (dont set GVA_HIGH_GOP_LIMIT lower than 100) */ l_potential_index_frame = TRUE; } } } if(gap_debug) { if( (gvahand->vindex) && (handle->capture_offset) ) { printf("KeyFrame: %d works:%d\n" ,(int)handle->big_picture_yuv.key_frame ,(int)handle->key_frame_detection_works ); } } if((gvahand->vindex) && (handle->capture_offset) && (l_potential_index_frame) ) { l_checksum = p_gva_checksum(handle->picture_yuv, gvahand->height); /* the automatic GOP detection has a lower LIMIT of 24 frames * GOP values less than the limit can make the videoindex * slow, because the packet reads in libavformat are buffered, * and the index based search starting at the recorded seek offset (in the index) * may not find the wanted keyframe in the first Synchronisation Loop * if its 1.st packet starts before the recorded seek offset. * 24 frames shold be enough to catch an offest before the start of the wanted * packet. * Increasing the GVA_LOW_GOP_LIMIT would slow down the index based seek * ops. */ /* printf("GUESS_GOP: prev_key_seek_nr:%d l_url_seek_nr:%d\n" * , (int)handle->prev_key_seek_nr * , (int)l_url_seek_nr); */ /* try to guess the GOP size (but use at least GOPSIZE of 4 frames) */ if(l_url_seek_nr > handle->prev_key_seek_nr) { gdouble l_gopsize; l_gopsize = l_url_seek_nr - handle->prev_key_seek_nr; if(handle->guess_gop_size == 0) { handle->guess_gop_size = l_gopsize; } else { handle->guess_gop_size = MAX(GVA_LOW_GOP_LIMIT, ((handle->guess_gop_size + l_gopsize) / 2)); } } if (l_url_seek_nr >= handle->prev_key_seek_nr + GVA_LOW_GOP_LIMIT) { /* record the url_offset of 2 frames before. this is done because positioning to current * frame via url_fseek will typically take us to frame number +2 */ p_vindex_add_url_offest(gvahand , handle , gvahand->vindex , l_url_seek_nr , handle->prev_url_offset[MAX_PREV_OFFSET -1] , handle->got_frame_length16 , l_checksum , handle->vid_pkt.dts ); handle->prev_key_seek_nr = l_url_seek_nr; } } if(handle->capture_offset) { gint ii; /* save history of the last captured url_offsets in the handle */ for(ii = MAX_PREV_OFFSET -1; ii > 0; ii--) { handle->prev_url_offset[ii] = handle->prev_url_offset[ii -1]; } handle->prev_url_offset[0] = l_record_url_offset; } gvahand->current_frame_nr = gvahand->current_seek_nr; gvahand->current_seek_nr++; if (gap_debug) printf("p_wrapper_ffmpeg_get_next_frame: current_frame_nr :%d\n" , (int)gvahand->current_frame_nr); /* if we found more frames, increase total_frames */ gvahand->total_frames = MAX(gvahand->total_frames, gvahand->current_frame_nr); if(gap_debug) { printf("AVFORMAT: get_next_frame timecode: %lld current_frame_nr:%d\n" , handle->vid_pkt.dts , gvahand->current_frame_nr ); } return(GVA_RET_OK); } if(l_rc == 1) { return(GVA_RET_EOF); } return(GVA_RET_ERROR); } /* end p_private_ffmpeg_get_next_frame */ /* ------------------------------ * p_wrapper_ffmpeg_seek_frame * ------------------------------ */ t_GVA_RetCode p_wrapper_ffmpeg_seek_frame(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit) { t_GVA_ffmpeg* master_handle; master_handle = (t_GVA_ffmpeg*)gvahand->decoder_handle; if (master_handle->timecode_proberead_done != TRUE) { if(gvahand->vindex == NULL) { /* this video has no explicite gva index file. * try if native timecode bases seek is supported and reliable. */ p_seek_timecode_reliability_self_test(gvahand); } else { /* this video has a gva index file. * but get analyse results (if availabe) that may contains the flag * (prefere_native_seek yes) * if this flag is set to yes we use native seek and ignore the valid videoindex. */ if(gap_base_get_gimprc_gboolean_value(GIMPRC_PERSISTENT_ANALYSE, ANALYSE_DEFAULT)) { p_get_video_analyse_results(gvahand); } } } return (p_seek_private(gvahand, pos, pos_unit)); } /* end p_wrapper_ffmpeg_seek_frame */ /* ------------------------------------- * p_reset_proberead_results * ------------------------------------- */ static void p_reset_proberead_results(t_GVA_ffmpeg* handle) { handle->timecode_proberead_done = FALSE; handle->timecode_offset_frame1 = -1; handle->timecode_step_avg = -1; handle->timecode_step_abs_min = 0; handle->timecode_steps_sum = -1; handle->count_timecode_steps = 0; handle->native_timecode_seek_failcount = 0; handle->max_tries_native_seek = MAX_TRIES_NATIVE_SEEK; handle->self_test_detected_seek_bug = FALSE; handle->eof_timecode = AV_NOPTS_VALUE; handle->video_libavformat_seek_gopsize = gap_base_get_gimprc_int_value("video-libavformat-seek-gopsize", DEFAULT_NAT_SEEK_GOPSIZE, 0, MAX_NAT_SEEK_GOPSIZE); } /* end p_reset_proberead_results */ /* ------------------------------------- * p_seek_timecode_reliability_self_test * ------------------------------------- * this test analyzes the required settings * for native timebased seek. * further it tries to findout if this fast seek * method works (e.g. is able to perform frame exact positioning * that may fail for videofiles with variable frametiming * or have read errors). * Note that this check is no 100% guarantee but is able * to detetect such videos fast in most cases. * * this test also includes fast detection of total_frames (via seek). */ static gboolean p_seek_timecode_reliability_self_test(t_GVA_Handle *gvahand) { gdouble percent; gint32 bck_total_frames; t_GVA_ffmpeg* master_handle; int gap_debug_local; gboolean persitent_analyse_available; gap_debug_local = gap_debug; #ifdef GAP_DEBUG_FF_NATIVE_SEEK gap_debug_local = 1; #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ master_handle = (t_GVA_ffmpeg*)gvahand->decoder_handle; persitent_analyse_available = FALSE; if(gap_base_get_gimprc_gboolean_value(GIMPRC_PERSISTENT_ANALYSE, ANALYSE_DEFAULT)) { persitent_analyse_available = p_get_video_analyse_results(gvahand); } if(gap_debug_local) { printf("\n\n\n\n\n\n\n\n\n\n\n\n"); if (persitent_analyse_available) { printf("SKIP p_seek_timecode_reliability_self_test PERSISTENT analyse available for file:%s\n" ,gvahand->filename ); } else { printf("STARTING p_seek_timecode_reliability_self_test with probereads on file:%s\n" ,gvahand->filename ); } } if(persitent_analyse_available != TRUE) { bck_total_frames = gvahand->total_frames; gvahand->cancel_operation = FALSE; /* reset cancel flag */ p_ffmpeg_vid_reopen_read(master_handle, gvahand); p_reset_proberead_results(master_handle); gvahand->current_frame_nr = 0; gvahand->current_seek_nr = 1; p_clear_inbuf_and_vid_packet(master_handle); /* limit native seek attempts to only one loop while running the selftest */ master_handle->max_tries_native_seek = 1; /* perform some (few) sequential probe reads to analyze typical timecode * offsets and stepsize for this videfile. */ p_probe_timecode_offset(gvahand); if ((master_handle->native_timecode_seek_failcount == 0) && (master_handle->video_libavformat_seek_gopsize > 0)) { if(gap_debug_local) { printf("\nCONTINUE p_seek_timecode_reliability_self_test step: detect total_frames\n"); } p_detect_total_frames_via_native_seek(gvahand); bck_total_frames = gvahand->total_frames; } if ((master_handle->native_timecode_seek_failcount == 0) && (master_handle->video_libavformat_seek_gopsize > 0)) { if(gap_debug_local) { printf("\nCONTINUE p_seek_timecode_reliability_self_test step: perform seek tests\n"); } /* now perform some (few!) seek operations with native timecode based * method and check if this method works reliable */ for(percent = 0.9; percent > 0.1; percent-= 0.2) { gint32 framenr; t_GVA_RetCode l_rc_rd; framenr = gvahand->total_frames * percent; l_rc_rd = p_seek_native_timcode_based(gvahand, framenr); /* for releiable native seek both retcode and the * seek failcount must be OK. */ if ((master_handle->native_timecode_seek_failcount > 0) || (l_rc_rd != GVA_RET_OK)) { if (master_handle->native_timecode_seek_failcount == 0) { master_handle->self_test_detected_seek_bug = TRUE; printf("\n################################\n"); printf("# ERROR on the video: %s\n", gvahand->filename); printf("# seek does not work.\n"); printf("# possible reasons may be:\n"); printf("# - libavformat or gimp-gap api bug or\n"); printf("# - corrupted videofile\n"); printf("# only slow sequential read will deliver frames\n"); printf("#\n"); printf("# Developer note: while testing this happened only with some MPEG1 videos\n"); printf("# the bug seems to be a libavcodec/libavformat problem.\n"); printf("################################\n"); } /* disable native timecode seek in case of failures */ master_handle->video_libavformat_seek_gopsize = 0; gvahand->total_frames = bck_total_frames; break; } } } if(gap_debug_local) { printf("\n\n"); printf("\nDONE p_seek_timecode_reliability_self_test failcount:%d video_libavformat_seek_gopsize:%d" , (int)master_handle->native_timecode_seek_failcount , (int)master_handle->video_libavformat_seek_gopsize ); if (master_handle->video_libavformat_seek_gopsize > 0) { printf(" (NATIVE seek ENABLED)"); } else { printf(" (NATIVE seek ** DISABLED **)"); } printf(" for file:%s\n", gvahand->filename); printf("\n\n\n\n\n"); } if(gap_base_get_gimprc_gboolean_value(GIMPRC_PERSISTENT_ANALYSE, ANALYSE_DEFAULT)) { p_save_video_analyse_results(gvahand); persitent_analyse_available = TRUE; } master_handle->max_tries_native_seek = MAX_TRIES_NATIVE_SEEK; p_ffmpeg_vid_reopen_read(master_handle, gvahand); } return (persitent_analyse_available); } /* end p_seek_timecode_reliability_self_test */ /* ------------------------------------- * p_detect_total_frames_via_native_seek * ------------------------------------- * findout total number of frames via native seek attempts * using binary search method. * further check if timecode based seek operates reliable * (native_timecode_seek_failcount must be 0) * * unfortunately i dont found a way to check if frame read attempts * failed due to read after EOF or failed due to errors. * some (typical but not all MPEG1 encoded) vidofiles deliver errors * when frames were read after any seek operations. * In such a case detection of total_frames is not possible * and furthermore native timecode based seek operations are not reliable * and must be disabled. * * it seems that libavformat sets the current timecode * to timecode after last frame * when seeking to positions after EOF (and in case of errors after native seek). * This (undocumented ?) effect enables quick detection of the toatal_frames. */ static void p_detect_total_frames_via_native_seek(t_GVA_Handle *gvahand) { gint32 frameNrLo; gint32 frameNrHi; gint32 frameNrMed; gint32 totalGuess; gint32 lastFrameNr; gint32 totalPlausible; gint32 totalDetected; t_GVA_RetCode l_rc; t_GVA_ffmpeg* master_handle; int gap_debug_local; gap_debug_local = gap_debug; #ifdef GAP_DEBUG_FF_NATIVE_SEEK gap_debug_local = 1; #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ master_handle = (t_GVA_ffmpeg*)gvahand->decoder_handle; master_handle->eof_timecode = AV_NOPTS_VALUE; totalGuess = p_guess_total_frames(gvahand); lastFrameNr = totalGuess; totalPlausible = MAX((totalGuess / 4), 256); if(gap_debug_local) { printf("START: p_detect_total_frames_via_native_seek total_guess:%d\n" , (int)totalGuess ); } /* first loop trys to seek after EOF until seek fails * seek to 150 % until seek fails */ totalDetected = 0; frameNrLo = 1; frameNrHi = MAX(totalGuess, 256); /* start with guess value */ while(1==1) { gdouble increase; increase = (gdouble)frameNrHi * 0.5; frameNrHi = frameNrHi + increase; l_rc = p_seek_native_timcode_based(gvahand, frameNrHi); if (l_rc != GVA_RET_OK) { if ((master_handle->eof_timecode != AV_NOPTS_VALUE) && (master_handle->eof_timecode > 0)) { gdouble tolerance; /* probably already got eof_timecode from libavformat * therefore set Lo/Hi near that value to speed up the binary search. */ lastFrameNr = p_timecode_to_frame_nr(master_handle, master_handle->eof_timecode) -1; tolerance = 32; frameNrLo = MAX(1, (lastFrameNr - tolerance)); frameNrHi = lastFrameNr + tolerance; totalPlausible = frameNrLo; } break; } frameNrLo = MAX(frameNrLo, frameNrHi); } /* 2nd loop for binary search between Lo and Hi */ while(1==1) { gdouble delta; delta = (gdouble)(frameNrHi - frameNrLo) / 2.0; frameNrMed = frameNrLo + delta; if(gap_debug_local) { printf("Lo:%d Hi:%d Med:%d delta:%.3f\n" ,(int)frameNrLo ,(int)frameNrHi ,(int)frameNrMed ,(float)delta ); } if(delta < 1.0) { totalDetected = frameNrLo; gvahand->all_frames_counted = TRUE; break; } l_rc = p_seek_native_timcode_based(gvahand, frameNrMed); if (master_handle->native_timecode_seek_failcount > 0) { /* disable native timecode seek */ master_handle->video_libavformat_seek_gopsize = 0; break; } if (l_rc != GVA_RET_OK) { frameNrHi = MIN(frameNrMed, frameNrHi); } else { frameNrLo = MAX(frameNrMed, frameNrLo); } } if(totalDetected >= totalPlausible) { l_rc = p_seek_native_timcode_based(gvahand, totalDetected); if (l_rc == GVA_RET_OK) { l_rc = p_wrapper_ffmpeg_get_next_frame(gvahand); } if (l_rc != GVA_RET_OK) { totalDetected--; } gvahand->total_frames = totalDetected; gvahand->all_frames_counted = TRUE; } else { /* disable native timecode seek * we typically get here for video files * where libavformat reads after seek always fail. */ master_handle->video_libavformat_seek_gopsize = 0; gvahand->total_frames = lastFrameNr; gvahand->all_frames_counted = FALSE; } if(gap_debug_local) { printf("END: p_detect_total_frames_via_native_seek plausiblity limit:%d detected:%d total_frames:%d \n" , (int)totalPlausible , (int)totalDetected , (int)gvahand->total_frames ); } } /* end p_detect_total_frames_via_native_seek */ /* ------------------------------------ * p_inc_native_timecode_seek_failcount * ------------------------------------ */ static void p_inc_native_timecode_seek_failcount(t_GVA_Handle *gvahand) { t_GVA_ffmpeg* master_handle; master_handle = (t_GVA_ffmpeg*)gvahand->decoder_handle; if (master_handle->native_timecode_seek_failcount <= 0) { printf("\n##############################\n"); printf("# WARNING video %s probably has variable frame timing\n" , gvahand->filename ); printf("# positioning to exact framenumber is not guaranteed\n"); printf("# you may create a videoindex to enable positioning to exact frame numbers\n"); printf("##############################\n"); } master_handle->native_timecode_seek_failcount++; } /* end p_inc_native_timecode_seek_failcount */ /* ------------------------------------ * p_clear_inbuf_and_vid_packet * ------------------------------------ */ static void p_clear_inbuf_and_vid_packet(t_GVA_ffmpeg *handle) { av_free_packet(&handle->vid_pkt); handle->vid_pkt.size = 0; /* set empty packet status */ handle->vid_pkt.data = NULL; /* set empty packet status */ handle->inbuf_len = 0; handle->inbuf_ptr = NULL; } /* end p_clear_inbuf_and_vid_packet */ /* ------------------------------ * p_seek_private * ------------------------------ * this procedure seeks to specified position. * one of 3 alternative methods will be used. * - Native timebased seek via av_seek_frame * This method is fastest, but may not be available for some videofile formats. * This method may deliver * wrong results in case the video has unrelible timecode, * or has frames with individual duration, or streams with * different framerates. * Note that GAP usually works framenumber oriented, therefore * native timebased seeking may delvier wrong results, depending on the videofile. * native seek by timestamps can be generally disabled by setting gimprc parameter * (video-libavformat-seek-gopsize "0") * Note that native seek will also be disabled automatically, if the self test * detects that native seek does not work properly on the current video. * * - The videoindex is an external solution outside libavformat * and enables seek in the videofile in case where native seek is not available. * The videoindex is slower than native but much faster than sequential reads. * a videoindex has stored offsets of the keyframes * that were optional created by the count_frames procedure. * The videoindex based seek modifies the libavformat internal straem seek position * by an explicte call seek call (either to byte position or to timecode target) * The index also has information about the (compressed) frame length and a checksum. * In the inner Sync Loop(s) we try to find exactly the frame that is described in the index. * The outer Loop (l_nloops) repeats the sync loop attempt by using a lower seek offset * from the previous video index entry and uses more read operations (l_synctries) * trying to find the target frame. (This is necessary because byte oriented * seek operations do not work exact and may position the video stream * AFTER the target frame. * * The postioning to last Group of pictures is done * by sequential read (l_readsteps). it should contain at least one keyframe (I-frame) * that enables clean decoding of the following P and B frames * * video index table inner (synctries) and outer loop * * |-------------------------------------------| * | [10] seek_nr:000100 offset: len16: DTS: | * |-------------------------------------------| * * * (only in case 1st attempt failed * to seek the video stream * to exact target position) * |-------------------------------------------| l_nloops = 2 * | [11] seek_nr:000110 offset: len16: DTS: | | 1 l_synctries * |-------------------------------------------| | 2 * | 3 * | 4 * | 5 * | 6 * | 7 * | 8 * | 9 * |-------------------------------------------| l_nloops = 1 | 10 * l_idx_target ------> | [12] seek_nr:000120 offset: len16: DTS: | | 1 l_synctries | 11 * |-------------------------------------------| | 2 | 12 * | 3 | 13 * | 4 | 14 * | 5 | 15 * | 6 | 16 * | 7 | 17 * | 8 | 18 * |-------------------------------------------| | 9 | 19 * l_idx_too_far -----> | [13] seek_nr:000130 offset: len16: DTS: | V 10 V 20 * |-------------------------------------------| * * * - the fallback method emulates * seek by pos-1 sequential read ops. * seek backwards must always reopen to reset stream position to start. * this is very slow, creating a videoindex is recommanded for GUI-based applications * * seek operation to the start (the first few frames) always use sequential read * * */ #define GVA_IDX_SYNC_STEPSIZE 1 #define GVA_FRAME_NEAR_START 24 static t_GVA_RetCode p_seek_private(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit) { t_GVA_ffmpeg *handle; t_GVA_RetCode l_rc_rd; gint32 l_frame_pos; gint32 l_url_frame_pos; gint32 l_readsteps; gint32 l_summary_read_ops; gdouble l_progress_step; gboolean l_vindex_is_usable; t_GVA_Videoindex *vindex; handle = (t_GVA_ffmpeg *)gvahand->decoder_handle; vindex = gvahand->vindex; gvahand->cancel_operation = FALSE; /* reset cancel flag */ switch(pos_unit) { case GVA_UPOS_FRAMES: l_frame_pos = (gint32)pos; break; case GVA_UPOS_SECS: l_frame_pos = (gint32)round(pos * gvahand->framerate); break; case GVA_UPOS_PRECENTAGE: /* is not reliable until all_frames_counted == TRUE */ l_frame_pos = (gint32)GVA_percent_2_frame(gvahand->total_frames, pos); break; default: l_frame_pos = (gint32)pos; break; } if(gvahand->all_frames_counted) { /* in case total number of frames is exactly known * constraint seek position */ l_frame_pos = MIN(l_frame_pos, gvahand->total_frames); } gvahand->percentage_done = 0.0; if(gap_debug) { printf("p_wrapper_ffmpeg_seek_frame: start: l_frame_pos: %d cur_seek:%d cur_frame:%d (prefere_native:%d gopsize:%d) video:%s\n" , (int)l_frame_pos , (int)gvahand->current_seek_nr , (int)gvahand->current_frame_nr , (int)handle->prefere_native_seek , (int)handle->video_libavformat_seek_gopsize , gvahand->filename ); } handle->dummy_read = TRUE; l_url_frame_pos = 0; l_vindex_is_usable = FALSE; l_summary_read_ops = 0; if(l_frame_pos > GVA_FRAME_NEAR_START) { /* check if we have a usable video index */ if(vindex != NULL) { if(vindex->tabsize_used > 0) { gint32 l_max_seek; /* seek to frames above this numer via video index will be slow */ l_max_seek = vindex->ofs_tab[vindex->tabsize_used-1].seek_nr + (2 * vindex->stepsize); if(l_frame_pos <= l_max_seek) { l_vindex_is_usable = TRUE; if(gap_debug) { printf("VINDEX flag l_vindex_is_usable is TRUE l_max_seek:%d (vindex->tabsize_used:%d)\n" , (int)l_max_seek , (int)vindex->tabsize_used ); } } else { if(gap_debug) { p_debug_print_videoindex(vindex); } printf("WARNING VINDEX flag l_vindex_is_usable is FALSE, the video Index is NOT COMPLETE ! for video:%s\n" " l_frame_pos:%d l_max_seek:%d (vindex->tabsize_used:%d) total_frames:%d\n" , gvahand->filename , (int)l_frame_pos , (int)l_max_seek , (int)vindex->tabsize_used , (int)gvahand->total_frames ); } } } /* check conditions and try native timecode based seek if conditions permit native seek. */ if((l_vindex_is_usable != TRUE) || (handle->prefere_native_seek)) { /* try native av_seek_frame if enabled by gimprc configuration * (native seek is disabled if video_libavformat_seek_gopsize == 0) */ if (handle->video_libavformat_seek_gopsize > 0) { l_rc_rd = p_seek_native_timcode_based(gvahand, l_frame_pos); if(l_rc_rd == GVA_RET_OK) { if(gap_debug) { printf("NATIVE SEEK performed for videofile:%s\n" , gvahand->filename ); } return (l_rc_rd); } } } } /* use video index where possible */ if((vindex != NULL) && (l_frame_pos > GVA_FRAME_NEAR_START)) { gint64 seek_pos; gint32 l_idx; if(gap_debug) { //p_debug_print_videoindex(vindex); printf("VIDEO INDEX is available for videofile:%s vindex->tabsize_used:%d\n" , gvahand->filename , (int)vindex->tabsize_used ); } if(vindex->tabsize_used < 1) { printf("SEEK: index is >>> EMPTY <<<: vindex->tabsize_used: %d cannot use index!\n", (int)vindex->tabsize_used); } else { l_idx = ((l_frame_pos -2) / vindex->stepsize); /* make sure that table access limited to used tablesize * (this allows usage of incomplete indexes) * Note that the last index entry is not used, * because positioning after the last keyframe does not work properly */ if(l_idx > vindex->tabsize_used -1) { if(gap_debug) { printf("SEEK: overflow l_idx: %d limit:%d\n" , (int)l_idx , (int) vindex->tabsize_used -1 ); } l_idx = vindex->tabsize_used -1; } /* lower index adjustment (dont start seek with positions much smaller than l_frame_pos) */ if(l_idx > 0) { gint32 l_pos_min; l_pos_min = l_frame_pos - (MAX(64, (2* vindex->stepsize))); while(vindex->ofs_tab[l_idx].seek_nr < l_pos_min) { l_idx++; if(l_idx > vindex->tabsize_used -1) { l_idx = vindex->tabsize_used -1; printf("WARNING: videoindex is NOT complete ! Seek to frame numers > seek_nr:%d will be VERY SLOW!\n" , (int)vindex->ofs_tab[l_idx].seek_nr ); break; } if(gap_debug) { printf("SEEK: lower idx adjustment l_idx: %d l_pos_min:%d seek_nr[%d]:%d\n" , (int)l_idx , (int)l_pos_min , (int)vindex->ofs_tab[l_idx].seek_nr , (int)l_idx ); } } } /* upper index adjustment (dont start seek with positions already graeter than l_frame_pos)*/ if(l_idx > 0) { while(vindex->ofs_tab[l_idx].seek_nr >= l_frame_pos) { l_idx--; if(gap_debug) { printf("SEEK: upper idx adjustment l_idx: %d l_frame_pos:%d seek_nr[%d]:%d\n\n" , (int)l_idx , (int)l_frame_pos , (int)vindex->ofs_tab[l_idx].seek_nr , (int)l_idx ); } if(l_idx < 1) { break; } } } if(l_idx > 0) { gint32 l_idx_target; gint32 l_idx_too_far; /* next index position after the target * when this position is reached we are already too far * and must retry with a lower position at next attempt */ gboolean l_target_found; l_target_found = FALSE; l_idx_target = l_idx; l_idx_too_far = l_idx_target + 1; if (l_idx_too_far > vindex->tabsize_used -1) { l_idx_too_far = -1; /* mark as invalid */ } l_readsteps = l_frame_pos - gvahand->current_seek_nr; if((l_readsteps > vindex->stepsize) || (l_readsteps < 0)) { gint32 l_nloops; /* number of seek attempts with different recorded videoindex entries * (outer loop) */ gint32 l_synctries; /* number of frame read attempts until * the frame read from video stream matches * the ident data of the recorded frame in the videoindex[l_idx] * (inner loop counter) */ l_nloops = 1; while((l_idx >= 0) && (l_nloops < 12)) { gboolean l_dts_timecode_usable; l_dts_timecode_usable = FALSE; if((vindex->ofs_tab[l_idx].timecode_dts != AV_NOPTS_VALUE) && (l_nloops == 1) && (vindex->ofs_tab[l_idx_target].timecode_dts != AV_NOPTS_VALUE) && (vindex->ofs_tab[0].timecode_dts != AV_NOPTS_VALUE)) { l_dts_timecode_usable = TRUE; } if(gap_debug) { printf("SEEK: USING_INDEX: ofs_tab[%d]: ofs64: %lld seek_nr:%d flen:%d chk:%d dts:%lld DTS_USABLE:%d NLOOPS:%d\n" , (int)l_idx , vindex->ofs_tab[l_idx].uni.offset_gint64 , (int)vindex->ofs_tab[l_idx].seek_nr , (int)vindex->ofs_tab[l_idx].frame_length , (int)vindex->ofs_tab[l_idx].checksum , vindex->ofs_tab[l_idx].timecode_dts , l_dts_timecode_usable , (int)l_nloops ); } l_synctries = 4 + MAX_PREV_OFFSET + (vindex->stepsize * GVA_IDX_SYNC_STEPSIZE * l_nloops); /* SYNC READ loop * seek to offest found in the index table * then read until we are at the KEYFRAME that matches * in length and checksum with the one from the index table * * Note that Byte offest based seek is not frame exact. Seek may take us * to positions after the wanted framenumber. * (therefore we make more attempts l_nloops > 1 with previous index entries) * * Timecode based seek shall take us to the wanted frame already in the 1st attempt * but will fail (probably in all attempts) when the video has corrupted timecodes. * therefore switch seek strategy fo byte offset based seek in further attempts (l_nloops != 1) * * for some videofiles dts timecodes are available but not for all frames. * for those videos seek via dts does NOT work. * such videos are marked with AV_NOPTS_VALUE in entry at index 0 * (vindex->ofs_tab[0].timecode_dts == AV_NOPTS_VALUE) * */ p_ffmpeg_vid_reopen_read(handle, gvahand); if(l_dts_timecode_usable) { int ret_av_seek_frame; l_synctries = 1; if(gap_debug) { printf("USING DTS timecode based av_seek_frame\n"); } /* timecode based seek */ ret_av_seek_frame = av_seek_frame(handle->vid_input_context, handle->vid_stream_index , vindex->ofs_tab[l_idx].timecode_dts, AVSEEK_FLAG_BACKWARD); } else { int ret_av_seek_frame; /* seek based on url_fseek (for support of old video indexes without timecode) */ seek_pos = vindex->ofs_tab[l_idx].uni.offset_gint64; // url_fseek(handle->vid_input_context->pb, seek_pos, SEEK_SET); /* byte position based seek AVSEEK_FLAG_BACKWARD AVSEEK_FLAG_ANY*/ ret_av_seek_frame = av_seek_frame(handle->vid_input_context, handle->vid_stream_index ,seek_pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_BYTE); } p_clear_inbuf_and_vid_packet(handle); gvahand->current_seek_nr = vindex->ofs_tab[vindex->tabsize_used].uni.offset_gint64; while(l_synctries > 0) { gboolean l_potentialCanditate; l_potentialCanditate = FALSE; l_rc_rd = p_wrapper_ffmpeg_get_next_frame(gvahand); l_summary_read_ops++; if(l_rc_rd != GVA_RET_OK) { l_synctries = -1; if(gap_debug) { printf("EOF or ERROR while SEEK_SYNC_LOOP\n"); } break; } // // printf("SEEK_SYNC_LOOP: idx_frame_len:%d got_frame_length16:%d Key:%d dts:%lld\n" // , (int)vindex->ofs_tab[l_idx_target].frame_length // , (int)handle->got_frame_length16 // , (int)handle->big_picture_yuv.key_frame // , handle->vid_pkt.dts // ); if(l_dts_timecode_usable == TRUE) { /* handling for index format with usable timecode * for videos where DTS timecodes are consistent * the 1st seek attempt shall take us already to the wanted position. * (an additional length check would fail in this situation due to the buggy * length information) */ if(TRUE == p_areTimecodesEqualWithTolerance(vindex->ofs_tab[l_idx_target].timecode_dts, handle->vid_pkt.dts)) { l_potentialCanditate = TRUE; } } else { /* handling for index without usable timecode */ if(vindex->ofs_tab[l_idx_target].frame_length == handle->got_frame_length16) { l_potentialCanditate = TRUE; } } if (l_potentialCanditate == TRUE) { guint16 l_checksum; l_checksum = p_gva_checksum(handle->picture_yuv, gvahand->height); if(l_checksum == vindex->ofs_tab[l_idx_target].checksum) { /* we have found the wanted (key) frame */ l_target_found = TRUE; break; } else if ((vindex->ofs_tab[l_idx_target].timecode_dts != AV_NOPTS_VALUE) && (TRUE == p_areTimecodesEqualWithTolerance(vindex->ofs_tab[l_idx_target].timecode_dts, handle->vid_pkt.dts))) { /* ignore the checksum missmatch when DTS timecode is matching */ if(gap_debug) { printf("SEEK_SYNC_LOOP: CHKSUM_MISSMATCH: CHECKSUM[%d]:%d l_checksum:%d but DTS equal:%lld \n" , (int)l_idx_target , (int)vindex->ofs_tab[l_idx_target].checksum , (int)l_checksum , handle->vid_pkt.dts ); } l_target_found = TRUE; break; } else { /* checksum missmatch is non critical in most cases. * a) there may be frames where the packed length is equal to the * wanted frame (NOT CRITICAL) * b) after seek to a non-keyframe and subsequent reads * the resulting frame may be the wanted frame but is corrupted * (due to some missing delta information that was not yet read) * in this case the frame delivers wrong checksum. (CRITICAL) * this code assumes case a) and * continues searching for an exactly matching frame * but also respects case b) in the next outer loop attempt. * (with l_nloops == 2 where we start from a lower seek position) * this shall increase the chance to perfectly decode the frame * and deliver the correct checksum. */ if(gap_debug) { printf("SEEK_SYNC_LOOP: CHKSUM_MISSMATCH: CHECKSUM[%d]:%d l_checksum:%d\n" , (int)l_idx_target , (int)vindex->ofs_tab[l_idx_target].checksum , (int)l_checksum ); } } } else { if (l_idx_too_far > 0) /* check for valid index */ { /* Check if we are already AFTER the wanted position */ if(vindex->ofs_tab[l_idx_too_far].frame_length == handle->got_frame_length16) { guint16 l_checksum; l_checksum = p_gva_checksum(handle->picture_yuv, gvahand->height); if(l_checksum == vindex->ofs_tab[l_idx_too_far].checksum) { l_synctries = -1; if(gap_debug) { printf("SEEK_SYNC_LOOP position is already after wanted target\n"); } break; } } } } l_synctries--; } /* end while */ if(l_target_found != TRUE) { /* index sync search failed, try with previous index in the table */ if(l_idx < GVA_IDX_SYNC_STEPSIZE) { /* index sync search failed, must search slow from start */ p_ffmpeg_vid_reopen_read(handle, gvahand); gvahand->current_seek_nr = 1; l_url_frame_pos = 0; } } else { /* index sync search had success */ l_url_frame_pos = 1 + vindex->ofs_tab[l_idx_target].seek_nr; if(gap_debug) { printf("SEEK: url_fseek seek_pos: %d l_idx_target:%d l_url_frame_pos:%d\n" , (int)seek_pos , (int)l_idx_target , (int)l_url_frame_pos ); } gvahand->current_seek_nr = l_url_frame_pos; l_readsteps = l_frame_pos - gvahand->current_seek_nr; if(gap_debug) { printf("SEEK: sync loop success remaining l_readsteps: %d\n", (int)l_readsteps); } break; /* OK, escape from outer loop, we are now at read position of the wanted keyframe */ } if(l_dts_timecode_usable == TRUE) { /* if seek via dts timecode failed, switch to byte offset based seek * but this must be restarted with the same index [l_idx] * (we must not decrement l_idx because timecode based seek has only checked one frame. * if the wanted frame is in the search range of current l_idx it will never be found * if we advance at this point, which results in very slow sequential search afterwards) */ l_dts_timecode_usable = FALSE; } else { /* try another search with previous index table entry */ l_idx -= GVA_IDX_SYNC_STEPSIZE; } l_nloops++; } /* end outer loop (l_nloops) */ if (l_target_found != TRUE) { p_ffmpeg_vid_reopen_read(handle, gvahand); gvahand->current_seek_nr = 1; l_url_frame_pos = 0; if(gap_debug) { printf("SEEK: target frame not found, fallback to slow sequential read from begin\n"); } } } } } } /* fallback to sequential read */ if(l_url_frame_pos == 0) { /* emulate seek with N steps of read ops */ if((l_frame_pos < gvahand->current_seek_nr) /* position backwards ? */ || (gvahand->current_seek_nr < 0)) /* inplausible current position ? */ { /* reopen and read from start */ p_ffmpeg_vid_reopen_read(handle, gvahand); l_readsteps = l_frame_pos -1; } else { /* continue read from current position */ l_readsteps = l_frame_pos - gvahand->current_seek_nr; } } if(gap_debug) { printf("p_wrapper_ffmpeg_seek_frame: l_readsteps: %d\n", (int)l_readsteps); } l_progress_step = 1.0 / MAX((gdouble)l_readsteps, 1.0); l_rc_rd = GVA_RET_OK; while((l_readsteps > 0) && (l_rc_rd == GVA_RET_OK)) { l_rc_rd = p_wrapper_ffmpeg_get_next_frame(gvahand); l_summary_read_ops++; gvahand->percentage_done = CLAMP(gvahand->percentage_done + l_progress_step, 0.0, 1.0); if(gvahand->do_gimp_progress) { gimp_progress_update (gvahand->percentage_done); } if(gvahand->fptr_progress_callback) { gvahand->cancel_operation = (*gvahand->fptr_progress_callback)(gvahand->percentage_done, gvahand->progress_cb_user_data); } l_readsteps--; if(gvahand->cancel_operation) { l_rc_rd = GVA_RET_ERROR; /* cancel by user request reults in seek error */ gvahand->cancel_operation = FALSE; /* reset cancel flag */ } } handle->dummy_read = FALSE; if(l_rc_rd == GVA_RET_OK) { if(gap_debug) { printf("p_wrapper_ffmpeg_seek_frame: SEEK OK: l_frame_pos: %d cur_seek:%d cur_frame:%d l_summary_read_ops:%d video:%s\n" , (int)l_frame_pos , (int)gvahand->current_seek_nr , (int)gvahand->current_frame_nr , (int)l_summary_read_ops , gvahand->filename ); } gvahand->current_seek_nr = (gint32)l_frame_pos; return(GVA_RET_OK); } if(l_rc_rd == GVA_RET_EOF) { return(GVA_RET_EOF); } return(GVA_RET_ERROR); } /* end p_seek_private */ /* ------------------------------ * p_seek_native_timcode_based * ------------------------------ * positioning of the video stream before target_frame position. * * the native timecode based seek operates on * timecode steps sample pattern that will be measured * by some initial probereads (p_probe_timecode_offset). * * Most Videofiles have either constant timing (stepsize equal for all frames) * or use a repeating pattern of individual stepsizes within a group of pictures. * In both cases this procedure can calculate the correct timecode that * is required for frame exact postioning. * * Some videos use variable timecode all over the video. For such videos * where no typical pattern can be detected, the native timecodebased seek * is not possible. * Some videoformats do not allow seek at all. * (all attempts to read a frame after seek operations fail for * those videofiles) * * * returns GVA_RET_OK if positionig was successful * GVA_RET_ERROR if positioning failed * note: this procedure reopens the handle after errors * to allow clean sequential reads afterwards. * futher results are stored in the decoder specific handle (part of gvahand) * handle->video_libavformat_seek_gopsize * (is automatically increased when necessary) * handle->eof_timecode * (is set when detected the 1st time) * handle->handle->native_timecode_seek_failcount * (is increased when variable frametiming is detected * or when frame could be read but timcode overflow occured * at the last try with the highest pre_read setting) */ static t_GVA_RetCode p_seek_native_timcode_based(t_GVA_Handle *gvahand, gint32 target_frame) { t_GVA_ffmpeg *handle; t_GVA_RetCode l_retcode; t_GVA_RetCode l_rc_rd; gint32 l_readsteps; gdouble l_progress_step; gint32 l_pre_read_frames; gint l_tries; gboolean l_retry; #define NATIVE_SEEK_GOP_INCREASE 24 #define NATIVE_SEEK_EXTRA_PREREADS_NEAR_END 22 handle = (t_GVA_ffmpeg *)gvahand->decoder_handle; l_retcode = GVA_RET_ERROR; if (handle->video_libavformat_seek_gopsize <= 0) { return(l_retcode); } l_retry = TRUE; for(l_tries=0; l_tries < handle->max_tries_native_seek; l_tries++) { if (l_retry != TRUE) { return(l_retcode); } l_pre_read_frames = MAX(4, (handle->video_libavformat_seek_gopsize + (l_tries * NATIVE_SEEK_GOP_INCREASE)) ); #ifdef GAP_DEBUG_FF_NATIVE_SEEK { printf("TRY (%d) native seek with l_pre_read_frames:%d total_frames:%d target:%d\n" ,(int)l_tries ,(int)l_pre_read_frames ,(int)gvahand->total_frames ,(int)target_frame ); } #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ if (target_frame > l_pre_read_frames) { int ret_av_seek_frame; int jj; int64_t l_seek_timecode; gint32 seek_fnr; gint32 seek_fnr2; ret_av_seek_frame = -1; p_probe_timecode_offset(gvahand); /* determine seek timecode. * this is done in 3 attempts and selects the smallest l_seek_timecode. * (videos that have negative timecode steps * may pick a timecode too high when using only one attempt. * this can lead to seek after the wanted position or after EOF) * example: * video timcode sequence with negative stepsizes may look like this: * seek_fnr:000557; seek_timecode:49306; * seek_fnr:000558; seek_timecode:45557; * seek_fnr:000559; seek_timecode:45558; * * in this situation it is required to pick seek_timecode:45557; */ seek_fnr = target_frame - l_pre_read_frames; l_seek_timecode = p_frame_nr_to_timecode(handle, seek_fnr); seek_fnr2 = seek_fnr; for(jj=0; jj < 2; jj++) { int64_t l_seek_timecode2; seek_fnr2++; l_seek_timecode2 = p_frame_nr_to_timecode(handle, seek_fnr2); if(l_seek_timecode2 < l_seek_timecode) { seek_fnr = seek_fnr2; l_seek_timecode = l_seek_timecode2; } } /* SEEK to preread position */ gvahand->current_frame_nr = 0; gvahand->current_seek_nr = 1; if(1==1 /*l_tries == 0*/) { /* seek variant based on stream specific dts timecode */ /* seek is done some (configurable number) frames less than wanted frame position. * it shall deliver position of nearest key frame * after seek, have to read/decode some few frames until * wanted frame is reached * in some rare cases (some older mpeg files) libavformat positioning may take us * to non-keyframes (even with AVSEEK_FLAG_BACKWARD set). * therefore read/decode some frames (l_pre_read_frames) shall ensure that * a keyframe is included, and enable proper decoding of the subsequent frames. */ ret_av_seek_frame = av_seek_frame(handle->vid_input_context, handle->vid_stream_index , l_seek_timecode, AVSEEK_FLAG_BACKWARD); } else { /* seek variant based on global (not stream specific) pts timecode */ int64_t target_pts; gdouble secs; target_pts = av_rescale_q(l_seek_timecode, handle->vid_stream->time_base, AV_TIME_BASE_Q); ret_av_seek_frame = av_seek_frame(handle->vid_input_context, -1 , target_pts, AVSEEK_FLAG_BACKWARD); #ifdef GAP_DEBUG_FF_NATIVE_SEEK printf("PTS-SEEK: framerate:%.3f target_pts:%lld l_seek_timecode:%lld seek_fnr:%d\n" , gvahand->framerate , target_pts , l_seek_timecode , (int)seek_fnr ); #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ } #ifdef GAP_DEBUG_FF_NATIVE_SEEK if(1==0) { int64_t seek_target; int64_t target_pts; int64_t microsecs_start; gdouble secs; gdouble dframes; gint32 seek_fnr; seek_fnr = target_frame - l_pre_read_frames; secs = (gdouble)seek_fnr / gvahand->framerate; target_pts = secs * AV_TIME_BASE; microsecs_start = handle->vid_input_context->start_time * handle->vid_stream->time_base.num / handle->vid_stream->time_base.den; seek_target= av_rescale_q(target_pts, AV_TIME_BASE_Q, handle->vid_stream->time_base); dframes = handle->vid_input_context->duration / (gdouble)AV_TIME_BASE * gvahand->framerate; printf("VINFOt: framerate:%.3f target_pts:%lld seek_target:%lld mstart:%lld seek_timecode:%lld seek_fnr:%d\n" , gvahand->framerate , target_pts , seek_target , microsecs_start , l_seek_timecode , (int)seek_fnr ); } if(gap_debug) { printf("AVFORMAT NATIVE-SEEK: av_seek_frame retcode: %d seek_timecode:%lld seek_frame:%ld (target frame_pos:%ld)\n" , ret_av_seek_frame , l_seek_timecode , (long)(target_frame - l_pre_read_frames) , (long)target_frame ); } #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ /* clear inbuf and packet *(must remove old content after seek to enable clean reads) */ p_clear_inbuf_and_vid_packet(handle); if (ret_av_seek_frame < 0) { printf("** ERROR AVFORMAT: av_seek_frame failed retcode: %d \n" , ret_av_seek_frame); } else { int64_t l_wanted_timecode; /* timecode one frame before target */ int64_t l_want_2_timecode; /* timecode 2 frames before target */ int64_t l_want_3_timecode; /* timecode 3 frames before target */ int64_t l_overflow_timecode; /* timecode 2 frames after target */ int64_t l_very_small_absdiff; gint l_ii; gint l_read_err_count; int64_t l_prev_timecode; int64_t l_pprev_timecode; gchar l_debug_msg[500]; l_wanted_timecode = p_frame_nr_to_timecode(handle, target_frame -1); l_want_2_timecode = p_frame_nr_to_timecode(handle, target_frame -2); l_want_3_timecode = p_frame_nr_to_timecode(handle, target_frame -3); l_overflow_timecode = MAX(l_wanted_timecode, p_frame_nr_to_timecode(handle, target_frame)); l_overflow_timecode = MAX(l_overflow_timecode, p_frame_nr_to_timecode(handle, target_frame +1)); l_overflow_timecode = MAX(l_overflow_timecode, p_frame_nr_to_timecode(handle, target_frame +2)); l_very_small_absdiff = CLAMP((handle->timecode_step_abs_min / 200), 0, 10); l_prev_timecode = AV_NOPTS_VALUE; l_pprev_timecode = AV_NOPTS_VALUE; l_read_err_count = 0; l_progress_step = 1.0 / MAX((gdouble)l_pre_read_frames, 1.0); gvahand->percentage_done = 0.0; /* native seek has (hopefully) set stream position to the nearest keyframe * (before the wanted frame) * ??? For some video formats the native seek may set position AFTER the wanted * frame in such a case it is worth to start a retry with larger * l_pre_read_frames value. * now read/decode frames until wanted timecode position -1 is reached * Note: use pkt->dts because pkt->pts can be AV_NOPTS_VALUE if the video format * has B frames, so it is better to rely on pkt->dts */ for (l_ii=0; l_ii <= MAX_NAT_SEEK_GOPSIZE; l_ii++) { int64_t l_curr_timecode; t_GVA_RetCode l_rc_timeread; #ifdef GAP_DEBUG_FF_NATIVE_SEEK if(gap_debug) { printf(" [%d.%02d] START progress/cancel handler\n" , l_tries , l_ii ); fflush(stdout); } #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ /* progress and cancel handling */ gvahand->percentage_done = CLAMP(gvahand->percentage_done + l_progress_step, 0.0, 1.0); if((l_ii % 3) == 0) { if(gvahand->do_gimp_progress) { gimp_progress_update (gvahand->percentage_done); } if((gvahand->fptr_progress_callback) && (gvahand->progress_cb_user_data)) { gvahand->cancel_operation = (*gvahand->fptr_progress_callback)(gvahand->percentage_done, gvahand->progress_cb_user_data); } } if(gvahand->cancel_operation) { l_retcode = GVA_RET_ERROR; /* cancel by user request reults in seek error */ l_retry = FALSE; /* no more attempts due to cancel */ gvahand->cancel_operation = FALSE; /* reset cancel flag */ break; } #ifdef GAP_DEBUG_FF_NATIVE_SEEK if(gap_debug) { printf(" [%d.%02d] END progress/cancel handler\n" , l_tries , l_ii ); fflush(stdout); } #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ /* make a guess to set current_seek_nr while doing timebased frame serach loop */ gvahand->current_seek_nr = (gint32)target_frame -1; /* READ FRAME from video stream at current position */ handle->dummy_read = TRUE; #ifdef GAP_DEBUG_FF_NATIVE_SEEK if(gap_debug) { gint64 url_pos; url_pos = url_ftell(handle->vid_input_context->pb); printf(" [%d.%02d] START nat-seek READ FRAME url_pos:%lld\n" , l_tries , l_ii , url_pos ); fflush(stdout); } #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ l_rc_timeread = p_wrapper_ffmpeg_get_next_frame(gvahand); l_curr_timecode = handle->vid_pkt.dts; #ifdef GAP_DEBUG_FF_NATIVE_SEEK { gint64 url_pos; url_pos = url_ftell(handle->vid_input_context->pb); printf(" [%d.%02d] END nat-seek READ FRAME url_pos:%lld curr_timecode:%lld rc:%d\n" , l_tries , l_ii , url_pos , l_curr_timecode , l_rc_timeread ); fflush(stdout); } #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ handle->dummy_read = FALSE; if(l_rc_timeread != GVA_RET_OK) { gint32 l_fnr; l_fnr = p_timecode_to_frame_nr(handle, l_curr_timecode); if(handle->eof_timecode == AV_NOPTS_VALUE) { handle->eof_timecode = l_curr_timecode; } l_read_err_count++; #ifdef GAP_DEBUG_FF_NATIVE_SEEK printf("** ERROR AVFORMAT: (%d) errcount:%d timbased seek failed to read frame after native seek rc:%d\n" " * target_frame:%d cur_timecode:%lld, l_fnr:%d, total_frames:%d, all_counted:%d\n" , (int)l_ii , (int)l_read_err_count , (int)l_rc_timeread , (int)target_frame , l_curr_timecode , (int)l_fnr , (int)gvahand->total_frames , (int)gvahand->all_frames_counted ); #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ if (1==1) /* (l_read_err_count > 1) */ { l_retry = FALSE; } else { l_pprev_timecode = l_prev_timecode; l_prev_timecode = AV_NOPTS_VALUE; } break; } l_debug_msg[0] = "\n"; l_debug_msg[1] = "\0"; #ifdef GAP_DEBUG_FF_NATIVE_SEEK { g_snprintf(&l_debug_msg[0], sizeof(l_debug_msg) , "AVFORMAT: try(%d) readcount(%d) debug read frame timecode: %lld " "(wanted framenr:%d timecode:%lld)\n" , l_tries , l_ii , l_curr_timecode , target_frame -1 , l_wanted_timecode ); } #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ /* tolerant check if wanted timecode is reached * it is sufficient if 2 out of the last 3 timecodes read do match. */ { gint match_count; gint must_match; gchar debug_match_string[4]; int64_t l_curr_absdiff; int64_t l_prev_absdiff; int64_t l_pprev_absdiff; match_count = 0; must_match = 2; debug_match_string[0] = '-'; debug_match_string[1] = '-'; debug_match_string[2] = '-'; debug_match_string[3] = '\0'; l_curr_absdiff = llabs(l_curr_timecode - l_wanted_timecode); l_prev_absdiff = llabs(l_prev_timecode - l_want_2_timecode); l_pprev_absdiff = llabs(l_pprev_timecode - l_want_3_timecode); if (l_curr_absdiff <= l_very_small_absdiff) { debug_match_string[0] = 'x'; match_count++; } if (l_prev_absdiff <= l_very_small_absdiff) { debug_match_string[1] = 'x'; match_count++; } if (l_pprev_absdiff <= l_very_small_absdiff) { debug_match_string[2] = 'x'; match_count++; } #ifdef GAP_DEBUG_FF_NATIVE_SEEK { printf(" match_string:[%s]\n" , debug_match_string ); fflush(stdout); } #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ if(match_count >= must_match) { /* set attributes of gvahand to refelect wanted seek position reached. */ gvahand->current_seek_nr = target_frame; gvahand->current_frame_nr = target_frame -1; /* if this is not the first try ( l_tries > 0) * increase video_libavformat_seek_gopsize * to the value where we had success with. * (the next seek operation may be successful * in the first attempt based on this value) */ handle->video_libavformat_seek_gopsize += (l_tries * NATIVE_SEEK_GOP_INCREASE); #ifdef GAP_DEBUG_FF_NATIVE_SEEK { printf("%sABSDIFF: match_string:[%s] curr_absdiff: %lld prev_absdiff:%lld pprev_absdiff:%lld very_small:%d\n\n" , l_debug_msg , debug_match_string , l_curr_absdiff , l_prev_absdiff , l_pprev_absdiff , l_very_small_absdiff ); printf("p_wrapper_ffmpeg_seek_frame: NATIVE SEEK OK: target_frame: %d cur_seek:%d cur_frame:%d seek_gopsize:%d\n" , (int)target_frame , (int)gvahand->current_seek_nr , (int)gvahand->current_frame_nr , (int)handle->video_libavformat_seek_gopsize ); } #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ return (GVA_RET_OK); } } /* END of tolerant check if wanted timecode is reached */ /* timecode overflow check */ if ((l_curr_timecode != AV_NOPTS_VALUE) && (l_curr_timecode > l_overflow_timecode)) { /* if the video has variable timing it is possible that * the wanted timecode can not be found, in such a case we get an overflow * when reading frames with higher timecode than the wanted timecode. * (check for overflow compares timecode greater than 2 frames after the * wanted frame, because some videos have time code step patterns * that include negative stepsizes) * * The overflow may also happen on seek attempts after the last * frame of the video. */ if (l_tries >= handle->max_tries_native_seek -1) { l_retry = FALSE; p_inc_native_timecode_seek_failcount(gvahand); } if(gap_debug) { printf("%s** Timecode OVERFLOW: curr: %lld oflow:%lld prev:%lld pprev:%lld (wanted:%lld)\n" , l_debug_msg , l_curr_timecode , l_overflow_timecode , l_prev_timecode , l_pprev_timecode , l_wanted_timecode ); } l_retcode = GVA_RET_ERROR; break; } l_pprev_timecode = l_prev_timecode; l_prev_timecode = l_curr_timecode; } } if (l_retry != TRUE) { printf("** AVFORMAT: native seek failed (seek behind EOF, Seek Error, or Read error)\n"); } #ifdef GAP_DEBUG_FF_NATIVE_SEEK { printf("** now reopening (reset seek position for next try or alternative seek)\n"); } #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ p_ffmpeg_vid_reopen_read(handle, gvahand); handle = (t_GVA_ffmpeg *)gvahand->decoder_handle; gvahand->current_frame_nr = 0; gvahand->current_seek_nr = 1; } } /* end for tries loop */ return (l_retcode); } /* end p_seek_native_timcode_based */ /* ------------------------------ * p_wrapper_ffmpeg_seek_audio * ------------------------------ * this procedure just sets the current_sample position * for access of the samples_buffer */ t_GVA_RetCode p_wrapper_ffmpeg_seek_audio(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit) { t_GVA_ffmpeg *handle; gint32 l_sample_pos; gint32 l_frame_pos; handle = (t_GVA_ffmpeg *)gvahand->decoder_handle; switch(pos_unit) { case GVA_UPOS_FRAMES: l_sample_pos = (gint32)GVA_frame_2_samples(gvahand->framerate, gvahand->samplerate, pos -1.0); break; case GVA_UPOS_SECS: l_sample_pos = (gint32)round(pos / MAX(gvahand->samplerate, 1.0)); break; case GVA_UPOS_PRECENTAGE: l_frame_pos= (gint32)GVA_percent_2_frame(gvahand->total_frames, pos); l_sample_pos = (gint32)GVA_frame_2_samples(gvahand->framerate, gvahand->samplerate, l_frame_pos -1); break; default: l_sample_pos = 0; break; } if(gap_debug) printf("p_wrapper_ffmpeg_seek_audio: l_sample_pos:%d\n", (int)l_sample_pos); gvahand->current_sample = (gint32)l_sample_pos; return(GVA_RET_OK); } /* end p_wrapper_ffmpeg_seek_audio */ /* ------------------------------ * p_wrapper_ffmpeg_get_audio * ------------------------------ */ t_GVA_RetCode p_wrapper_ffmpeg_get_audio(t_GVA_Handle *gvahand ,gint16 *output_i ,gint32 channel ,gdouble samples ,t_GVA_AudPos mode_flag ) { t_GVA_ffmpeg *handle; int l_rc; gint32 l_sample_idx; gint32 l_low_sample_idx; gint32 l_samples_picked; handle = (t_GVA_ffmpeg *)gvahand->decoder_handle; if(mode_flag == GVA_AMOD_FRAME) { p_wrapper_ffmpeg_seek_audio(gvahand , (gdouble) gvahand->current_frame_nr , GVA_UPOS_FRAMES ); } if(mode_flag == GVA_AMOD_REREAD) { l_sample_idx = gvahand->reread_sample_pos; } else { gvahand->reread_sample_pos = gvahand->current_sample; /* store current position for reread operations */ l_sample_idx = gvahand->current_sample; } if(gap_debug) printf("p_wrapper_ffmpeg_get_audio samples: %d l_sample_idx:%d\n", (int)samples, (int)l_sample_idx); l_low_sample_idx = 0; if (handle->samples_base[0] > 0) { l_low_sample_idx = handle->samples_base[0]; } if ((handle->samples_base[1] > 0) && (handle->samples_base[1] < l_low_sample_idx)) { l_low_sample_idx = handle->samples_base[1]; } if(l_sample_idx < l_low_sample_idx) { /* the requested sample_idx is to old * (is not chached in the sample_buffers any more) * we have to reset audio read, and restart reading from the begin */ p_ffmpeg_aud_reopen_read(handle, gvahand); } /* read and decode audio packets into sample_buffer */ l_rc = p_read_audio_packets(handle, gvahand, (gdouble)(l_sample_idx + samples)); /* copy desired range number of samples for the desired channel * from sample_buffer to output_i (16bit) sampledata */ l_samples_picked = p_pick_channel( handle , gvahand , output_i , l_sample_idx , samples , channel ); if(l_rc == 0) { if(mode_flag != GVA_AMOD_REREAD) { gvahand->current_sample += l_samples_picked; /* advance current audio read position */ } return(GVA_RET_OK); } if(l_rc == 1) { return(GVA_RET_EOF); } return(GVA_RET_ERROR); } /* end p_wrapper_ffmpeg_get_audio */ /* ---------------------------------- * p_wrapper_ffmpeg_count_frames * ---------------------------------- * (re)open a separated handle for counting * to ensure that stream positions are not affected by the count. * This procedure optionally creates a videoindex * for faster seek access */ t_GVA_RetCode p_wrapper_ffmpeg_count_frames(t_GVA_Handle *gvahand) { t_GVA_ffmpeg* master_handle; t_GVA_ffmpeg* handle; t_GVA_RetCode l_rc; t_GVA_Handle *copy_gvahand; gint32 l_total_frames; t_GVA_Videoindex *vindex; gboolean persitent_analyse_available; if(gap_debug) { printf("p_wrapper_ffmpeg_count_frames: START\n"); } gvahand->percentage_done = 0.0; persitent_analyse_available = FALSE; if(gap_base_get_gimprc_gboolean_value(GIMPRC_PERSISTENT_ANALYSE, ANALYSE_DEFAULT)) { persitent_analyse_available = p_seek_timecode_reliability_self_test(gvahand); gvahand->percentage_done = 0.0; } if(gvahand->vindex == NULL) { gvahand->vindex = GVA_load_videoindex(gvahand->filename, gvahand->vid_track, GVA_FFMPEG_DECODER_NAME); } if(gvahand->vindex) { if((gvahand->vindex->total_frames > 0) && (gvahand->vindex->track == gvahand->vid_track)) { /* we already have a valid videoindex that contains the real total number */ if(gap_debug) { printf("p_wrapper_ffmpeg_count_frames: have already valid vindex\n"); } gvahand->total_frames = gvahand->vindex->total_frames; gvahand->all_frames_counted = TRUE; return(GVA_RET_OK); } /* throw away existing videoindex (because it is unusable) */ if(gap_debug) { printf("p_wrapper_ffmpeg_count_frames: throw away existing videoindex\n"); } GVA_free_videoindex(&gvahand->vindex); } vindex = NULL; if(gvahand->create_vindex) { gvahand->vindex = GVA_new_videoindex(); vindex = gvahand->vindex; if(vindex) { vindex->tabtype = GVA_IDX_TT_GINT64; vindex->ofs_tab = g_new(t_GVA_IndexElem, GVA_VIDINDEXTAB_BLOCK_SIZE); vindex->track = gvahand->vid_track; if(vindex->ofs_tab) { vindex->tabsize_allocated = GVA_VIDINDEXTAB_BLOCK_SIZE; } } } copy_gvahand = g_malloc0(sizeof(t_GVA_Handle)); if(gap_debug) { printf("p_wrapper_ffmpeg_count_frames: ## before open ## handle:%s\n", gvahand->filename); } p_wrapper_ffmpeg_open_read(gvahand->filename ,copy_gvahand ); if(gap_debug) { printf("p_wrapper_ffmpeg_count_frames: after p_wrapper_ffmpeg_open_read\n"); } copy_gvahand->current_frame_nr = 0; copy_gvahand->current_seek_nr = 1; copy_gvahand->vindex = vindex; handle = (t_GVA_ffmpeg*)copy_gvahand->decoder_handle; master_handle = (t_GVA_ffmpeg*)gvahand->decoder_handle; if(handle) { /* TIMCODE LOG INIT */ FILE *fp_timecode_log; fp_timecode_log = p_init_timecode_log(gvahand); if(vindex) { handle->capture_offset = TRUE; } handle->dummy_read = TRUE; /* percentage_done is just a guess, because we dont know * the exact total_frames number before. */ if(gvahand->all_frames_counted) { l_total_frames = gvahand->total_frames; } else { /* we need a guess to update the percentage_done used for progress indication) */ l_total_frames = p_guess_total_frames(gvahand); } if(gap_debug) { printf("p_wrapper_ffmpeg_count_frames: begin Counting\n"); } gvahand->frame_counter = 0; while(!gvahand->cancel_operation) { /* READ FRAME */ l_rc = p_wrapper_ffmpeg_get_next_frame(copy_gvahand); if(l_rc != GVA_RET_OK) { break; /* eof, or fetch error */ } gvahand->frame_counter++; l_total_frames = MAX(l_total_frames, gvahand->frame_counter); /* TIMCODE check and LOG WHILE COUNTING */ p_timecode_check_and_log(fp_timecode_log, gvahand->frame_counter, handle, master_handle, gvahand); if(gvahand->all_frames_counted) { gvahand->percentage_done = CLAMP(((gdouble)gvahand->frame_counter / (gdouble)l_total_frames), 0.0, 1.0); } else { /* assume we have 5 % frames more to go than total_frames */ gvahand->percentage_done = CLAMP(((gdouble)gvahand->frame_counter / MAX(((gdouble)l_total_frames * 1.05),1)), 0.0, 1.0); gvahand->total_frames = l_total_frames; } if(gvahand->do_gimp_progress) { gimp_progress_update (gvahand->percentage_done); } if(gvahand->fptr_progress_callback) { gvahand->cancel_operation = (*gvahand->fptr_progress_callback)(gvahand->percentage_done, gvahand->progress_cb_user_data); } } if(gap_debug) { printf("p_wrapper_ffmpeg_count_frames: stop Counting\n"); } vindex->stepsize = handle->guess_gop_size; handle->capture_offset = FALSE; /* the copy_gvahand has used reference to the orinal gvahand->vindex * this reference must be set NULL before the close is done * (otherwise p_wrapper_ffmpeg_close would free the vindex) */ copy_gvahand->vindex = NULL; /* close the extra handle (that was opened for counting only) */ p_wrapper_ffmpeg_close(copy_gvahand); /* TIMCODE LOG FINALLY */ if (fp_timecode_log) { fclose(fp_timecode_log); } } g_free(copy_gvahand); gvahand->percentage_done = 0.0; if(vindex) { if(gap_debug) { printf("p_wrapper_ffmpeg_count_frames: before GVA_save_videoindex\n"); printf("p_wrapper_ffmpeg_count_frames: gvahand->filename:%s\n", gvahand->filename); } vindex->total_frames = gvahand->frame_counter; if(gvahand->cancel_operation) { /* because of cancel the total_frames is still unknown * (vindex->total_frames == 0 is the indicator for incomplete index) */ vindex->total_frames = 0; } if(gap_debug) { printf("p_wrapper_ffmpeg_count_frames: before GVA_save_videoindex\n"); } GVA_save_videoindex(vindex, gvahand->filename, GVA_FFMPEG_DECODER_NAME); if(gap_debug) { GVA_debug_print_videoindex(gvahand); } } if(!gvahand->cancel_operation) { gvahand->total_frames = gvahand->frame_counter; gvahand->all_frames_counted = TRUE; master_handle->all_timecodes_verified = TRUE; } else { gvahand->total_frames = MAX(gvahand->total_frames, gvahand->frame_counter); gvahand->cancel_operation = FALSE; /* reset cancel flag */ if(gap_debug) { printf("p_wrapper_ffmpeg_count_frames: RETURN ERROR\n"); } return(GVA_RET_ERROR); } if ((master_handle->critical_timecodesteps_found == FALSE) && (master_handle->all_timecodes_verified == TRUE)) { // TODO: the video index creator plug-in may offer // an option wheter prefere_native_seek set to TRUE or stay FALSE // when all timecodesteps are verified as OK. // on the other hand the faster native seek is to prefere // at this point, where the full frame scan has verified all timecodes. master_handle->prefere_native_seek = TRUE; } if(gap_debug) { printf("VINDEX done, critical_timecodesteps_found:%d\n" " master_handle->all_timecodes_verified %d\n" " master_handle->prefere_native_seek %d\n" " gvahand->frame_counter: %d\n" " gvahand->all_frames_counted: %d\n" " gvahand->cancel_operation: %d\n" " gvahand->total_frames: %d\n" , (int)master_handle->critical_timecodesteps_found , (int)master_handle->all_timecodes_verified , (int)master_handle->prefere_native_seek , (int)gvahand->frame_counter , (int)gvahand->all_frames_counted , (int)gvahand->cancel_operation , (int)gvahand->total_frames ); } if ((master_handle->critical_timecodesteps_found) || (master_handle->all_timecodes_verified)) { if(persitent_analyse_available) { /* update analyse result file */ p_save_video_analyse_results(gvahand); } } if(gap_debug) { printf("p_wrapper_ffmpeg_count_frames: RETURN OK\n"); } return(GVA_RET_OK); } /* end p_wrapper_ffmpeg_count_frames */ /* ---------------------------------- * p_wrapper_ffmpeg_seek_support * ---------------------------------- * NOTE: if native seek is disabled via gimprc setting "video-libavformat-seek-gopsize" 0 * the self test is not performed (seek bugs are not detected in that case) */ t_GVA_SeekSupport p_wrapper_ffmpeg_seek_support(t_GVA_Handle *gvahand) { t_GVA_ffmpeg* master_handle; master_handle = (t_GVA_ffmpeg*)gvahand->decoder_handle; if ((master_handle->timecode_proberead_done != TRUE) && (master_handle->video_libavformat_seek_gopsize > 0)) { p_seek_timecode_reliability_self_test(gvahand); } if (master_handle->self_test_detected_seek_bug == TRUE) { return(GVA_SEEKSUPP_NONE); } if (master_handle->video_libavformat_seek_gopsize > 0) { return(GVA_SEEKSUPP_NATIVE); } return(GVA_SEEKSUPP_VINDEX); } /* end p_wrapper_ffmpeg_seek_support */ /* ----------------------------- * p_ffmpeg_new_dec_elem * ----------------------------- * create a new decoder element and init with * functionpointers referencing the QUICKTIME * specific Procedures */ t_GVA_DecoderElem * p_ffmpeg_new_dec_elem(void) { t_GVA_DecoderElem *dec_elem; dec_elem = g_malloc0(sizeof(t_GVA_DecoderElem)); if(dec_elem) { dec_elem->decoder_name = g_strdup(GVA_FFMPEG_DECODER_NAME); dec_elem->decoder_description = g_strdup("FFMPEG Decoder (Decoder for MPEG1,MPEG4(DivX),RealVideo) (EXT: .mpg,.vob,.avi,.rm,.mpeg)"); dec_elem->fptr_check_sig = &p_wrapper_ffmpeg_check_sig; dec_elem->fptr_open_read = &p_wrapper_ffmpeg_open_read; dec_elem->fptr_close = &p_wrapper_ffmpeg_close; dec_elem->fptr_get_next_frame = &p_wrapper_ffmpeg_get_next_frame; dec_elem->fptr_seek_frame = &p_wrapper_ffmpeg_seek_frame; dec_elem->fptr_seek_audio = &p_wrapper_ffmpeg_seek_audio; dec_elem->fptr_get_audio = &p_wrapper_ffmpeg_get_audio; dec_elem->fptr_count_frames = &p_wrapper_ffmpeg_count_frames; dec_elem->fptr_seek_support = &p_wrapper_ffmpeg_seek_support; dec_elem->fptr_get_video_chunk = &p_wrapper_ffmpeg_get_video_chunk; dec_elem->fptr_get_codec_name = &p_wrapper_ffmpeg_get_codec_name; dec_elem->next = NULL; } return (dec_elem); } /* end p_ffmpeg_new_dec_elem */ /* =================================== * private (static) helper PROCEDURES * =================================== * =================================== */ static void p_debug_codec_list(void) { AVCodec *codec; for(codec = av_codec_next(NULL); codec != NULL; codec = av_codec_next(codec)) { printf("\n-------------------------\n"); printf("name: %s\n", codec->name); printf("type: %d\n", codec->type); printf("id: %d\n", codec->id); printf("priv_data_size: %d\n", codec->priv_data_size); printf("capabilities: %d\n", codec->capabilities); printf("init fptr: %d\n", (int)codec->init); printf("encode fptr: %d\n", (int)codec->encode); printf("close fptr: %d\n", (int)codec->close); printf("decode fptr: %d\n", (int)codec->decode); } } /* ----------------------------- * p_ffmpeg_init * ----------------------------- */ static void p_ffmpeg_init(void) { if(gap_debug) printf("p_ffmpeg_init: before av_register_all \n"); /** * Initialize libavcodec and register all the codecs and formats. * (does avcodec_init(), avcodec_register_all, protocols etc.... */ av_register_all(); if(gap_debug) { p_debug_codec_list(); } } /* end p_ffmpeg_init */ /* ----------------------------- * p_ff_open_input * ----------------------------- * open input context and codec for video or audio * depending on the input parameter vid_open. * * IN: filename (videofile to open for read) * INOUT: gvahand * INOUT: handle * IN: vid_open TRUE: open stream for video only * FALSE: open stream for audio only */ static gboolean p_ff_open_input(char *filename, t_GVA_Handle *gvahand, t_GVA_ffmpeg* handle, gboolean vid_open) { AVCodecContext *acc; AVFormatContext *ic; AVInputFormat *iformat; int err, ii, ret; AVRational rfps; if(gap_debug) printf("p_ff_open_input: START vid_open:%d\n", (int)vid_open); /* open the input file with generic libav function * Opens a media file as input. The codec are not opened. * Only the file header (if present) is read. */ err = av_open_input_file(&ic, filename, NULL, 0, NULL); if (err < 0) { if(gap_debug) printf("p_ff_open_input: av_open_input_file FAILED: %d\n", (int)err); return(FALSE); } iformat = ic->iformat; if(gap_debug) { printf("ic: iformat: %d\n", (int)iformat); if(iformat) { printf("iformat name: %s\n", iformat->name); printf("iformat long_name: %s\n", iformat->long_name); printf("iformat FPTR read_seek: %d\n", (int)iformat->read_seek); } } /* If not enough info to get the stream parameters, we decode the * first frames to get it. (used in mpeg case for example) */ ret = av_find_stream_info(ic); if (ret < 0) { if(gap_debug) printf("p_ff_open_input:%s: could not find codec parameters\n", filename); return(FALSE); } /* -------------------------- * check all input streams * and pick up infos of the desired streams * (specified by vid_track aud_track) */ gvahand->vtracks = 0; gvahand->atracks = 0; for(ii=0; ii < ic->nb_streams; ii++) { acc = ic->streams[ii]->codec; switch(acc->codec_type) { case CODEC_TYPE_AUDIO: gvahand->atracks++; /* count all audiostraems as audiotrack */ if(gap_debug) printf("\nInput Audio channels: %d\n", acc->channels); if((gvahand->atracks == gvahand->aud_track) || (gvahand->atracks == 1)) { if(!vid_open) { handle->aud_stream_index = ii; handle->aud_codec_id = acc->codec_id; handle->aud_codec_context = acc; handle->aud_stream = ic->streams[ii]; } gvahand->audio_cannels = acc->channels; gvahand->samplerate = acc->sample_rate; } break; case CODEC_TYPE_VIDEO: gvahand->vtracks++; /* count all videostraems as videotrack */ if((gvahand->vtracks == gvahand->vid_track) || (gvahand->vtracks == 1)) { if(vid_open) { handle->vid_stream_index = ii; handle->vid_codec_id = acc->codec_id; handle->vid_codec_context = acc; handle->vid_stream = ic->streams[ii]; } gvahand->height = acc->height; gvahand->width = acc->width; /* Aspect Ratio handling */ p_set_aspect_ratio(gvahand, handle); rfps = ic->streams[ii]->r_frame_rate; acc->strict_std_compliance = FF_COMPLIANCE_NORMAL; acc->workaround_bugs = FF_BUG_AUTODETECT; acc->error_recognition = FF_ER_COMPLIANT; acc->error_concealment = FF_EC_DEBLOCK | FF_EC_GUESS_MVS; acc->idct_algo= 0; /* * if(acc->codec->capabilities & CODEC_CAP_TRUNCATED) * acc->flags|= CODEC_FLAG_TRUNCATED; */ if(/*acc->codec_id==CODEC_ID_MPEG4 || */acc->codec_id==CODEC_ID_MPEG1VIDEO) { acc->flags|= CODEC_FLAG_TRUNCATED; } if(FALSE) { if ((acc->time_base.den != rfps.den) || (acc->time_base.num != rfps.num)) { printf("\nSeems stream %d codec frame rate differs from container frame rate: %2.2f (%d/%d) -> %2.2f (%d/%d)\n" ,ii , (float)acc->time_base.den / acc->time_base.num , acc->time_base.den , acc->time_base.num , (float)rfps.den / rfps.num , rfps.den , rfps.num ); } } /* update the current frame rate to match the stream frame rate */ gvahand->framerate = (gdouble)acc->time_base.den / (gdouble)acc->time_base.num; } break; default: break; /* av_abort(); */ } } /* open video codec (if needed) */ if((gvahand->vtracks > 0) && (vid_open)) { if(handle->vid_codec_context) { handle->vcodec = avcodec_find_decoder(handle->vid_codec_id); } if(handle->vcodec) { /* open codec */ if (avcodec_open(handle->vid_codec_context, handle->vcodec) < 0) { printf("Error while opening video codec %s\n", handle->vcodec->name); return(FALSE); } if(gap_debug) printf("p_wrapper_ffmpeg_open_read: open video codec : %s OK\n", handle->vcodec->name); } else { handle->vid_stream_index = -1; printf("cant decode video (no compatible codec found)\n"); /* return(FALSE); */ } if(gap_debug) { if(handle->vid_codec_context) printf("(2) CodecPointer AVCodecContext->codec : %d\n", (int)handle->vid_codec_context->codec); if(handle->vid_codec_context->codec) printf("(2) Codec FunctionPointer AVCodecContext->codec->decode : %d\n", (int)handle->vid_codec_context->codec->decode); } } /* open audio codec (if needed) */ if((gvahand->atracks > 0) && (!vid_open)) { if(handle->aud_codec_context) { handle->acodec = avcodec_find_decoder(handle->aud_codec_id); } if(handle->acodec) { if (avcodec_open(handle->aud_codec_context, handle->acodec) < 0) { printf("** Error while opening audio codec %s\n", handle->acodec->name); return(FALSE); } if(gap_debug) printf("p_wrapper_ffmpeg_open_read: open audio codec : %s OK\n", handle->acodec->name); } else { printf("cant decode audio (no compatible codec found)\n"); handle->aud_stream_index = -1; /* return(FALSE); */ } if(gap_debug) { if(handle->aud_codec_context) printf("(3) CodecPointer AVCodecContext->codec : %d\n", (int)handle->aud_codec_context->codec); if(handle->aud_codec_context->codec) printf("(3) Codec FunctionPointer AVCodecContext->codec->decode : %d\n", (int)handle->aud_codec_context->codec->decode); } } if(vid_open) { handle->vid_input_context = ic; if(gap_debug) printf("p_ff_open_input: END vid_input_context:%d\n", (int)handle->vid_input_context); } else { handle->aud_input_context = ic; if(gap_debug) printf("p_ff_open_input: END aud_input_context:%d\n", (int)handle->aud_input_context); } return(TRUE); } /* end p_ff_open_input */ /* ------------------------- * p_set_aspect_ratio * ------------------------- * set the gvahand->aspect_ratio variable to aspect ratio * typical values are * 1.777777 For 16:9 video * 1.333333 For 4:3 video * * Note that the gvahand->aspect_ratio variable describes the ratio * for the full image (and not the ratio of a single pixel) * * (code is based on example ffplay.c) */ static void p_set_aspect_ratio(t_GVA_Handle *gvahand, t_GVA_ffmpeg* handle) { AVStream *video_st; video_st = handle->vid_stream; gvahand->aspect_ratio = 0.0; if (video_st->sample_aspect_ratio.num) { gvahand->aspect_ratio = av_q2d(video_st->sample_aspect_ratio); } else if (video_st->codec->sample_aspect_ratio.num) { gvahand->aspect_ratio = av_q2d(video_st->codec->sample_aspect_ratio); } if (gvahand->aspect_ratio <= 0.0) { gvahand->aspect_ratio = 1.0; } if(gvahand->aspect_ratio != 0.0) { gvahand->aspect_ratio *= (gdouble)video_st->codec->width / video_st->codec->height; } #if 0 if(gap_debug) { printf("#if 0 dtg_active_format=%d\n", video_st->codec->dtg_active_format); } /* dtg_active_format: aspect information may be available in some cases. * MPEG2(additional aspect ratio * information only used in DVB MPEG-2 transport streams) * 0 if not set. */ switch(video_st->codec->dtg_active_format) { case FF_DTG_AFD_4_3: gvahand->aspect_ratio = 4.0 / 3.0; break; case FF_DTG_AFD_16_9: gvahand->aspect_ratio = 16.0 / 9.0; break; case FF_DTG_AFD_14_9: gvahand->aspect_ratio = 14.0 / 9.0; break; case FF_DTG_AFD_4_3_SP_14_9: gvahand->aspect_ratio = 14.0 / 9.0; break; case FF_DTG_AFD_16_9_SP_14_9: gvahand->aspect_ratio = 14.0 / 9.0; break; case FF_DTG_AFD_SP_4_3: gvahand->aspect_ratio = 4.0 / 3.0; break; case FF_DTG_AFD_SAME: default: break; } #endif if(gap_debug) { printf("FF ASPECT: dtg_active_format:%d num:%d den:%d\n" ,(int)video_st->codec->dtg_active_format ,(int)video_st->codec->sample_aspect_ratio.num ,(int)video_st->codec->sample_aspect_ratio.den ); printf("FF ASPECT: dtected aspect_ratio: %f\n" ,(float)gvahand->aspect_ratio ); } } /* end p_set_aspect_ratio */ /* ------------------------------ * p_ffmpeg_vid_reopen_read * ------------------------------ * internal procedure to reset read position * reopen the video context of a videofile for read * (that is already open for read) * the audio context (if there is one) is not affected ! */ static void p_ffmpeg_vid_reopen_read(t_GVA_ffmpeg *handle, t_GVA_Handle *gvahand) { if(gap_debug) printf("p_ffmpeg_vid_reopen_read: REOPEN\n"); /* CLOSE the video codec */ if((handle->vid_codec_context) && (handle->vcodec)) { avcodec_close(handle->vid_codec_context); handle->vid_codec_context = NULL; } /* Close a media file (just the video context) */ if(handle->vid_input_context) { av_close_input_file(handle->vid_input_context); handle->vid_input_context = NULL; } if(handle->vid_pkt.data != NULL) { av_free_packet(&handle->vid_pkt); } { gint ii; for(ii=0; ii < MAX_PREV_OFFSET; ii++) { handle->prev_url_offset[ii] = 0; } } handle->vid_pkt.size = 0; /* REstart with empty packet */ handle->vid_pkt.data = NULL; /* REstart with empty packet */ handle->inbuf_len = 0; /* start with empty buffer */ handle->frame_len = 0; /* start with 0 frame length */ handle->inbuf_ptr = NULL; /* start with empty buffer, after 1.st av_read_frame: pointer to pkt.data read pos */ /* RE-open for the VIDEO part */ p_ff_open_input(gvahand->filename, gvahand, handle, TRUE); if(gap_debug) { printf("++## pix_fmt: keep:%d ignore from codec:%d (PIX_FMT_YUV420P:%d PIX_FMT_YUV422P:%d)\n" , (int)handle->yuv_buff_pix_fmt , (int)handle->vid_codec_context->pix_fmt , (int)PIX_FMT_YUV420P , (int)PIX_FMT_YUV422P ); } } /* end p_ffmpeg_vid_reopen_read */ /* ------------------------------ * p_ffmpeg_aud_reopen_read * ------------------------------ * internal procedure to reset read position * reopen the audio context of a videofile for read * (that is already open for read) * the video context (if there is one) is not affected ! */ static void p_ffmpeg_aud_reopen_read(t_GVA_ffmpeg *handle, t_GVA_Handle *gvahand) { if(gap_debug) printf("p_ffmpeg_aud_reopen_read: REOPEN\n"); /* CLOSE the audio codec */ if((handle->aud_codec_context) && (handle->acodec)) { avcodec_close(handle->aud_codec_context); handle->aud_codec_context = NULL; } /* Close a media file (just the video context) */ if(handle->aud_input_context) { av_close_input_file(handle->aud_input_context); handle->aud_input_context = NULL; } handle->vid_pkt.size = 0; /* REstart with empty packet */ handle->vid_pkt.data = NULL; /* REstart with empty packet */ handle->inbuf_len = 0; /* start with empty buffer */ handle->inbuf_ptr = NULL; /* start with empty buffer, after 1.st av_read_frame: pointer to pkt.data read pos */ handle->samples_read = 0.0; handle->bf_idx = 0; handle->samples_base[0] = 0; handle->samples_base[1] = 0; handle->bytes_filled[0] = 0; handle->bytes_filled[1] = 0; handle->output_samples_ptr = handle->samples_buffer[0]; /* RE-open for the AUDIO part */ p_ff_open_input(gvahand->filename, gvahand, handle, FALSE); } /* end p_ffmpeg_aud_reopen_read */ /* ------------------------------ * p_audio_convert_to_s16 * ------------------------------ * * convert audio samples in specified data_length at handle->output_samples_ptr * to signed 16 bit little endian audio format. * The original content of handle->output_samples_ptr is replaced by the conversion result * that may also change data length. * * return converted_data_size */ static int p_audio_convert_to_s16(t_GVA_ffmpeg *handle , int data_size ) { guchar *audio_convert_in_buffer; AVCodecContext *dec; int converted_data_size; dec = handle->aud_codec_context; converted_data_size = 0; if (handle->reformat_ctx == NULL) { handle->reformat_ctx = av_audio_convert_alloc(SAMPLE_FMT_S16, 1, dec->sample_fmt, 1, NULL, 0); if (!handle->reformat_ctx) { printf("ERROR: Cannot convert %s sample format to %s sample format\n", avcodec_get_sample_fmt_name(dec->sample_fmt), avcodec_get_sample_fmt_name(SAMPLE_FMT_S16)); return (converted_data_size); } } audio_convert_in_buffer = g_malloc(data_size); if (audio_convert_in_buffer != NULL) { /* copy samples in a new buffer to be used as input for the conversion */ memcpy(audio_convert_in_buffer, handle->output_samples_ptr, data_size); /* convert and write converted samples back to handle->output_samples_ptr */ if (handle->reformat_ctx) { const void *ibuf[6]= {audio_convert_in_buffer}; void *obuf[6]= {handle->output_samples_ptr}; int istride[6]= {av_get_bits_per_sample_format(dec->sample_fmt)/8}; int ostride[6]= {2}; int len= data_size/istride[0]; converted_data_size = len * ostride[0]; if (av_audio_convert(handle->reformat_ctx, obuf, ostride, ibuf, istride, len) < 0) { printf("av_audio_convert() failed\n"); converted_data_size = 0; } } g_free(audio_convert_in_buffer); } return (converted_data_size); } /* end p_audio_convert_to_s16 */ /* ------------------------------ * p_pick_channel * ------------------------------ * copy 16bit samples from samples_buffer[0/1] to output_i buffer * only the samples from the requested channel are copied. * copy starts at sample_idx and affects the given number of samples. * NOTE: the samples_buffer must have been filled up * at least until the needed position (sample_idx + samples) before * this routine is called. * there will be no size checks !! * output_i must be large enogh to hold samples * 2 bytes. */ static gint32 p_pick_channel( t_GVA_ffmpeg *handle , t_GVA_Handle *gvahand , gint16 *output_i , gint32 sample_idx , gint32 samples , gint32 channel ) { guchar *this_peek_ptr; guchar *prev_peek_ptr; guchar *poke_ptr; gint bytes_per_sample; gint32 ii; gint32 l_samples; gint32 l_this_samples; gint32 l_prev_samples; gint32 peek_idx; gint32 l_samples_picked; gint32 this_idx; gint32 prev_idx; l_samples_picked = 0; bytes_per_sample = 2 * gvahand->audio_cannels; this_idx = handle->bf_idx ; prev_idx = (this_idx + 1) & 1; this_peek_ptr = NULL; prev_peek_ptr = NULL; l_prev_samples = 0; l_this_samples = 0; l_samples = samples; if((samples + sample_idx) > handle->samples_read) { /* copy only as much as was read before. * (normally we dont get in here, * but if we did not read enough (? at EOF) l_samples gets 0 or negative * and prevents copying uninitiated data */ l_this_samples = (gint32) (handle->samples_read - sample_idx); if(gap_debug) printf("p_pick_channel(2): l_this_samples:%d\n", (int)l_this_samples); } if(sample_idx >= handle->samples_base[this_idx]) { /* start sample is available in the current samples_buffer * (there is no need to check the prev buffer) */ peek_idx = ((sample_idx - handle->samples_base[this_idx]) * bytes_per_sample) + (2* (channel -1)); this_peek_ptr = handle->samples_buffer[this_idx]; this_peek_ptr += peek_idx; l_this_samples = l_samples; } else { if(sample_idx >= handle->samples_base[prev_idx]) { gint32 l_avail_samples; /* start sample is available in the prev samples_buffer * but the requested number of samples may be spread * from the other buffer to this (current) buffer * (there may be a need to read from both buffers) */ peek_idx = ((sample_idx - handle->samples_base[prev_idx]) * bytes_per_sample) + (2* (channel -1)); prev_peek_ptr = handle->samples_buffer[prev_idx]; prev_peek_ptr += peek_idx; l_avail_samples = (handle->bytes_filled[prev_idx] - peek_idx) / bytes_per_sample; if(l_samples <= l_avail_samples) { l_prev_samples = l_samples; /* peek everything from the prev buffer */ } else { l_prev_samples = l_avail_samples; l_this_samples = l_samples - l_avail_samples; /* peek the rest from this buffer */ this_peek_ptr = handle->samples_buffer[this_idx]; } } else { printf("** ERROR could not fetch %d samples at once (max Buffersize is: %d)\n" , (int)samples , (int)GVA_SAMPLES_BUFFER_SIZE / 2 ); return(0); } } poke_ptr = (guchar *)output_i; if(gap_debug) { printf("p_pick_channel(1): sample_idx:%d ch:%d bytes_p_s:%d sam_read:%d peek_idx:%d prev_peek_ptr:%d this_peek_ptr:%d poke_ptr:%d\n" ,(int)sample_idx ,(int)channel ,(int)bytes_per_sample ,(int)handle->samples_read ,(int)peek_idx ,(int)prev_peek_ptr ,(int)this_peek_ptr ,(int)poke_ptr ); printf("p_pick_channel(2): samples:%d prev_samples:%d this_samples:%d\n" ,(int)samples ,(int)l_prev_samples ,(int)l_this_samples ); } /* we may peek the start from the prev buffer */ for(ii=0; ii < l_prev_samples; ii++) { /* if(ii%60 == 0) printf("\n%12d:", (int)peek_ptr); */ /* printf("%02x%02x ", (int)peek_ptr[0] ,(int)peek_ptr[1]); */ *poke_ptr = prev_peek_ptr[0]; poke_ptr++; *poke_ptr = prev_peek_ptr[1]; poke_ptr++; prev_peek_ptr += bytes_per_sample; l_samples_picked++; } /* then we can peek the rest from the this (current) buffer */ for(ii=0; ii < l_this_samples; ii++) { /* if(ii%60 == 0) printf("\n%12d:", (int)peek_ptr); */ /* printf("%02x%02x ", (int)peek_ptr[0] ,(int)peek_ptr[1]); */ *poke_ptr = this_peek_ptr[0]; poke_ptr++; *poke_ptr = this_peek_ptr[1]; poke_ptr++; this_peek_ptr += bytes_per_sample; l_samples_picked++; } if(gap_debug) { printf("p_pick_channel END: l_samples_picked:%d l_samples:%d prev_peek_ptr:%d this_peek_ptr:%d poke_ptr%d\n" ,(int)l_samples_picked ,(int)l_samples ,(int)prev_peek_ptr ,(int)this_peek_ptr ,(int)poke_ptr ); } return(l_samples_picked); } /* end p_pick_channel */ /* ------------------------------ * p_read_audio_packets * ------------------------------ * IN: max_sample_pos is the position of the last audiosample * that is needed. * this procedure does write to samples_buffer[0] and/or samples_buffer[1] * by reading and decoding audio packets as long as the samples_buffer [0/1] * are filled up to max_sample_pos (or eof is reached) */ static int p_read_audio_packets( t_GVA_ffmpeg *handle, t_GVA_Handle *gvahand, gint32 max_sample_pos) { int data_size; int l_rc; l_rc = 0; if(handle->samples_buffer[0] == NULL) { /* allocate 2 buffers, each is large enough to hold at least one uncompressed * audiopacket. those buffers are then filled with uncomressed 16bit audiosamples. * each time one of the buffers is full, the write pointer output_samples_ptr * switches to the other buffer */ handle->samples_buffer_size = GVA_SAMPLES_BUFFER_SIZE * gvahand->audio_cannels * 2; handle->samples_buffer[0] = g_malloc0(handle->samples_buffer_size); handle->samples_buffer[1] = g_malloc0(handle->samples_buffer_size); handle->samples_read = 0.0; handle->bf_idx = 0; handle->samples_base[0] = 0; handle->samples_base[1] = 0; handle->bytes_filled[0] = 0; handle->bytes_filled[1] = 0; handle->biggest_data_size = 4096; gvahand->current_sample = 0.0; gvahand->reread_sample_pos = 0.0; handle->output_samples_ptr = handle->samples_buffer[0]; } if (gap_debug) { printf("p_read_audio_packets: before WHILE max_sample_pos: %d\n", (int)max_sample_pos); printf("p_read_audio_packets: before WHILE samples_read: %d\n", (int)handle->samples_read); } while(handle->samples_read < max_sample_pos) { int l_len; int l_pktlen; /* if abuf is empty we must read the next packet */ if((handle->abuf_len < 1) || (handle->abuf_ptr == NULL)) { /*if (gap_debug) printf("p_read_audio_packets: before av_read_frame aud_input_context:%d\n", (int)handle->aud_input_context);*/ /** * Read a packet from a media file * @param s media file handle * @param pkt is filled * @return 0 if OK. AVERROR_xxx if error. */ l_pktlen = av_read_frame(handle->aud_input_context, &handle->aud_pkt); if(l_pktlen < 0) { /* EOF reached */ if (gap_debug) printf("p_read_audio_packets: EOF reached (or read ERROR)\n"); gvahand->total_aud_samples = handle->samples_read; gvahand->all_samples_counted = TRUE; l_rc = 1; break; } /*if (gap_debug) printf("aud_stream:%d pkt.stream_index #%d, pkt.size: %d samples_read:%d\n", handle->aud_stream_index, handle->aud_pkt.stream_index, handle->aud_pkt.size, (int)handle->samples_read);*/ /* check if packet belongs to the selected audio stream */ if(handle->aud_pkt.stream_index != handle->aud_stream_index) { /* discard packet */ /* if (gap_debug) printf("DISCARD Packet\n"); */ av_free_packet(&handle->aud_pkt); continue; } /* if (gap_debug) printf("using Packet\n"); */ /* packet is part of the selected video stream, use that packet */ handle->abuf_ptr = handle->aud_pkt.data; handle->abuf_len = handle->aud_pkt.size; } /* if (gap_debug) printf("before avcodec_decode_audio2: abuf_ptr:%d abuf_len:%d\n", (int)handle->abuf_ptr, (int)handle->abuf_len); */ /* decode a frame. return -1 if error, otherwise return the number of * bytes used. If no audio frame could be decompressed, data_size is * zero or negative. */ data_size = handle->samples_buffer_size; l_len = avcodec_decode_audio2(handle->aud_codec_context /* AVCodecContext * */ ,(int16_t *)handle->output_samples_ptr ,&data_size ,handle->abuf_ptr ,handle->abuf_len ); if (gap_debug) { printf("after avcodec_decode_audio2: l_len:%d data_size:%d samples_read:%d \n" " sample_fmt:%d %s (expect:%d SAMPLE_FMT_S16)\n" , (int)l_len , (int)data_size , (int)handle->samples_read , (int)handle->aud_codec_context->sample_fmt , avcodec_get_sample_fmt_name(handle->aud_codec_context->sample_fmt) , (int)SAMPLE_FMT_S16 ); } if(l_len < 0) { printf("p_read_audio_packets: avcodec_decode_audio2 returned ERROR)\n" "abuf_len:%d AVCODEC_MAX_AUDIO_FRAME_SIZE:%d samples_buffer_size:%d data_size:%d\n" , (int)handle->abuf_len , (int)AVCODEC_MAX_AUDIO_FRAME_SIZE , (int)handle->samples_buffer_size , (int)data_size ); l_rc = 2; break; } /* Some bug in mpeg audio decoder gives */ /* data_size < 0, it seems they are overflows */ if (data_size > 0) { gint bytes_per_sample; int converted_data_size; if (handle->aud_codec_context->sample_fmt != SAMPLE_FMT_S16) { /* convert audio */ converted_data_size = p_audio_convert_to_s16(handle , data_size ); if(converted_data_size <= 0) { l_rc = 2; break; } } else { converted_data_size = data_size; } /* debug code block: count not null bytes in the decoded data block */ if(gap_debug) { gint32 ii; gint32 l_sum; l_sum = 0; for(ii=0; ii < converted_data_size; ii++) { /* if(ii%60 == 0) printf("\n%012d:", (int)&handle->output_samples_ptr[ii]); */ /* printf("%02x", (int)handle->output_samples_ptr[ii]); */ if(handle->output_samples_ptr[ii] != 0) { l_sum++; } } printf("\nSUM of NOT NULL bytes: %d output_samples_ptr:%d\n", (int)l_sum, (int)handle->output_samples_ptr); } /* check for the biggest uncompressed packet size */ if (converted_data_size > handle->biggest_data_size) { handle->biggest_data_size = converted_data_size; } /* add the decoded packet size to one of the samples_buffers * and advance write position */ bytes_per_sample = MAX((2 * gvahand->audio_cannels), 1); handle->bytes_filled[handle->bf_idx] += converted_data_size; handle->samples_read += (converted_data_size / bytes_per_sample); /* check if we have enough space in the current samples_buffer (for the next packet) */ if(handle->bytes_filled[handle->bf_idx] + handle->biggest_data_size > GVA_SAMPLES_BUFFER_SIZE) { /* no more space in the current samples_buffer, * switch write pointer to the other buffer * (reset this other buffer now, and overwrite at next packet read) */ handle->bf_idx = (handle->bf_idx +1) & 1; if(gap_debug) printf("WRITE SWITCH samples_buffer to %d\n", (int)handle->bf_idx); handle->output_samples_ptr = handle->samples_buffer[handle->bf_idx]; handle->samples_base[handle->bf_idx] = handle->samples_read; handle->bytes_filled[handle->bf_idx] = 0; } else { /* enouch space, continue writing to the same buffer */ handle->output_samples_ptr += converted_data_size; } /* if more samples found then update total_aud_samples (that was just a guess) */ gvahand->total_aud_samples = MAX(handle->samples_read, gvahand->total_aud_samples); } handle->abuf_ptr += l_len; handle->abuf_len -= l_len; /* length of audio packet was completely processed, we can free that packet now */ if(handle->abuf_len < 1) { /* if (gap_debug) printf("FREE Packet\n"); */ av_free_packet(&handle->aud_pkt); handle->aud_pkt.size = 0; /* set empty packet status */ handle->aud_pkt.data = NULL; /* set empty packet status */ } } /* end while packet_read and decode audio frame loop */ return(l_rc); } /* end p_read_audio_packets */ /* ---------------------------------- * p_vindex_add_url_offest * ---------------------------------- * add one entry to the videoindex. */ static void p_vindex_add_url_offest(t_GVA_Handle *gvahand , t_GVA_ffmpeg *handle , t_GVA_Videoindex *vindex , gint32 seek_nr , gint64 url_offset , guint16 frame_length , guint16 checksum , gint64 timecode_dts ) { static gint64 s_last_seek_nr; if(vindex->tabsize_used > 0) { if(seek_nr <= s_last_seek_nr) { return; } } s_last_seek_nr = seek_nr; if(vindex->tabsize_used >= vindex->tabsize_allocated -1) { t_GVA_IndexElem *redim_ofs_tab; t_GVA_IndexElem *old_ofs_tab; gint32 new_size; /* on overflow redim the table by adding GVA_VIDINDEXTAB_BLOCK_SIZE elements */ new_size = vindex->tabsize_allocated + GVA_VIDINDEXTAB_BLOCK_SIZE; redim_ofs_tab = g_new(t_GVA_IndexElem, new_size); if(redim_ofs_tab) { if(gap_debug) { printf("p_vindex_add_url_offest: REDIM:vindex->tabsize_allocated %d NEW:%d\n" , (int)vindex->tabsize_allocated , (int)new_size ); } old_ofs_tab = vindex->ofs_tab; memcpy(redim_ofs_tab, old_ofs_tab, (vindex->tabsize_allocated * sizeof(t_GVA_IndexElem))); vindex->ofs_tab = redim_ofs_tab; g_free(old_ofs_tab); vindex->tabsize_allocated = new_size; } } if(vindex->tabsize_used < vindex->tabsize_allocated -1) { vindex->ofs_tab[vindex->tabsize_used].uni.offset_gint64 = url_offset; vindex->ofs_tab[vindex->tabsize_used].seek_nr = seek_nr; vindex->ofs_tab[vindex->tabsize_used].frame_length = frame_length; vindex->ofs_tab[vindex->tabsize_used].checksum = checksum; vindex->ofs_tab[vindex->tabsize_used].timecode_dts = timecode_dts; if(gap_debug) { printf("p_vindex_add_url_offest: ofs_tab[%d]: ofs64: %lld seek_nr:%d flen:%d chk:%d dts:%lld\n" , (int)vindex->tabsize_used , vindex->ofs_tab[vindex->tabsize_used].uni.offset_gint64 , (int)vindex->ofs_tab[vindex->tabsize_used].seek_nr , (int)vindex->ofs_tab[vindex->tabsize_used].frame_length , (int)vindex->ofs_tab[vindex->tabsize_used].checksum , vindex->ofs_tab[vindex->tabsize_used].timecode_dts ); } vindex->tabsize_used++; } if(timecode_dts == AV_NOPTS_VALUE) { /* at this point we detected that seek based on DTS timecode is not reliable for this video * therefore store AV_NOPTS_VALUE at index [0] to disables timecode based seek in the video index. */ vindex->ofs_tab[0].timecode_dts = AV_NOPTS_VALUE; } } /* end p_vindex_add_url_offest */ /* ----------------------------- * p_gva_checksum * ----------------------------- * for performance reasons the checksum * counts only odd rows of the middle column */ static guint16 p_gva_checksum(AVPicture *picture_yuv, gint height) { guint16 l_checksum; gint ii; l_checksum = 0; for(ii=0;ii<4;ii++) { if(picture_yuv->linesize[ii] > 0) { guchar *buf; gint row; buf = picture_yuv->data[ii]; buf += picture_yuv->linesize[ii] / 2; for(row=0; row < height; row+=2) { l_checksum += *buf; buf += picture_yuv->linesize[ii]; } } } return (l_checksum); } /* end p_gva_checksum */ /* ---------------------------------- * p_init_timecode_log * ---------------------------------- * if configured via gimprc parameter video-libavformat-timecodelog != 0 * for writing timecode log * then open the logfile for writing and return filpointer to the logfile. * ELSE return NULL pointer. */ static FILE * p_init_timecode_log(t_GVA_Handle *gvahand) { FILE *fp_timecode_log; gint32 gimprc_timecode_log; gchar *timecode_logfile_name; gimprc_timecode_log = gap_base_get_gimprc_int_value("video-libavformat-timecodelog", 0, 0, 1); fp_timecode_log = NULL; timecode_logfile_name = g_strdup("\0"); if (gimprc_timecode_log != 0) { char *timecode_logfile_name; char *vindex_file; t_GVA_DecoderElem *dec_elem; /* probe read required for calculation of expected timecodes in the log */ p_probe_timecode_offset(gvahand); dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; vindex_file = GVA_build_videoindex_filename(gvahand->filename ,gvahand->vid_track +1 ,dec_elem->decoder_name ); timecode_logfile_name = g_strdup_printf("%s.timelog", vindex_file); g_free(vindex_file); printf("TIMECODE log for video: %s\n ==> will be created as file: %s\n" , gvahand->filename , timecode_logfile_name ); fp_timecode_log = g_fopen(timecode_logfile_name, "w"); if(fp_timecode_log) { t_GVA_ffmpeg *master_handle; master_handle = (t_GVA_ffmpeg *)gvahand->decoder_handle; fprintf(fp_timecode_log, "# TIMECODE log for video: %s\n" , gvahand->filename ); fprintf(fp_timecode_log, "# READSTEPS_PROBE_TIMECODE = %d\n" , READSTEPS_PROBE_TIMECODE ); fprintf(fp_timecode_log, "# timecode offset for frame1: %lld\n" , master_handle->timecode_offset_frame1 ); fprintf(fp_timecode_log, "# count_timecode_steps:%d stepsizes summary:%d\n" , (int)master_handle->count_timecode_steps , (int)master_handle->timecode_steps_sum ); fprintf(fp_timecode_log, "#\n"); } g_free(timecode_logfile_name); } return (fp_timecode_log); } /* end p_init_timecode_log */ /* ---------------------------------- * p_timecode_check_and_log * ---------------------------------- * write log entry for current frame to timecode log file. * the master_handle is used read only * (for converting framenr to timecode based on * proberead statistical data) */ static void p_timecode_check_and_log(FILE *fp_timecode_log, gint32 framenr, t_GVA_ffmpeg *handle, t_GVA_ffmpeg *master_handle , t_GVA_Handle *gvahand) { static const char *ok_string = ""; static const char *err_string = "; # CRITICAL exp - dts difference > 10"; static int64_t old_pts = AV_NOPTS_VALUE; static int64_t old_dts = 0; const char *remark_ptr; int64_t expected_dts; int64_t diff_dts; expected_dts = p_frame_nr_to_timecode(master_handle, framenr); if (abs(expected_dts - handle->vid_pkt.dts) > 10) { master_handle->critical_timecodesteps_found = TRUE; handle->critical_timecodesteps_found = TRUE; gvahand->critical_timecodesteps_found = TRUE; remark_ptr = err_string; } else { remark_ptr = ok_string; } if (fp_timecode_log == NULL) { return; } fprintf(fp_timecode_log, "num:%06d; exp:%lld; dts:%lld; dts-olddts:%lld; exp-dts:%lld" , framenr , expected_dts , handle->vid_pkt.dts , handle->vid_pkt.dts - old_dts , expected_dts - handle->vid_pkt.dts ); old_dts = handle->vid_pkt.dts; if(handle->vid_pkt.pts != AV_NOPTS_VALUE) { fprintf(fp_timecode_log, "; pts:%lld; exp-pts:%lld; pts-dts:%lld" , handle->vid_pkt.pts , expected_dts - handle->vid_pkt.pts , handle->vid_pkt.pts - handle->vid_pkt.dts ); if (old_pts != AV_NOPTS_VALUE) { fprintf(fp_timecode_log, "; pts-oldpts:%lld" , handle->vid_pkt.pts - old_pts ); } old_pts = handle->vid_pkt.pts; } else { fprintf(fp_timecode_log, "; pts:NOPTS_VAL" ); } fprintf(fp_timecode_log, "%s\n" , remark_ptr ); } /* end p_timecode_check_and_log */ /* ---------------------------------- * p_set_analysefile_master_keywords * ---------------------------------- */ static void p_set_analysefile_master_keywords(GapValKeyList *keylist , t_GVA_Handle *gvahand, gint32 count_timecode_steps) { t_GVA_ffmpeg *master_handle; master_handle = (t_GVA_ffmpeg *)gvahand->decoder_handle; int ii; gap_val_set_keyword(keylist, "(READSTEPS_PROBE_TIMECODE ", &master_handle->readsteps_probe_timecode, GAP_VAL_GINT32, 0, "\0"); gap_val_set_keyword(keylist, "(timestamp ", &master_handle->timestamp, GAP_VAL_GINT32, 0, "\0"); gap_val_set_keyword(keylist, "(video_libavformat_seek_gopsize ", &master_handle->video_libavformat_seek_gopsize, GAP_VAL_GINT32, 0, "\0"); gap_val_set_keyword(keylist, "(self_test_detected_seek_bug ", &master_handle->self_test_detected_seek_bug, GAP_VAL_GBOOLEAN, 0, "\0"); gap_val_set_keyword(keylist, "(timecode_proberead_done ", &master_handle->timecode_proberead_done, GAP_VAL_GBOOLEAN, 0, "\0"); gap_val_set_keyword(keylist, "(all_frames_counted ", &gvahand->all_frames_counted, GAP_VAL_GBOOLEAN, 0, "\0"); gap_val_set_keyword(keylist, "(total_frames ", &gvahand->total_frames, GAP_VAL_GINT32, 0, "\0"); gap_val_set_keyword(keylist, "(eof_timecode ", &master_handle->eof_timecode, GAP_VAL_GINT64, 0, "\0"); gap_val_set_keyword(keylist, "(timecode_step_avg ", &master_handle->timecode_step_avg, GAP_VAL_GINT32, 0, "\0"); gap_val_set_keyword(keylist, "(timecode_step_abs_min ", &master_handle->timecode_step_abs_min, GAP_VAL_GINT32, 0, "\0"); gap_val_set_keyword(keylist, "(timecode_offset_frame1 ", &master_handle->timecode_offset_frame1, GAP_VAL_GINT64, 0, "\0"); gap_val_set_keyword(keylist, "(timecode_steps_sum ", &master_handle->timecode_steps_sum, GAP_VAL_GINT32, 0, "\0"); gap_val_set_keyword(keylist, "(count_timecode_steps ", &master_handle->count_timecode_steps, GAP_VAL_GINT32, 0, "\0"); gap_val_set_keyword(keylist, "(prefere_native_seek ", &master_handle->prefere_native_seek, GAP_VAL_GBOOLEAN, 0, "\0"); gap_val_set_keyword(keylist, "(all_timecodes_verified ", &master_handle->all_timecodes_verified, GAP_VAL_GBOOLEAN, 0, "\0"); gap_val_set_keyword(keylist, "(critical_timecodesteps_found ", &master_handle->critical_timecodesteps_found, GAP_VAL_GBOOLEAN, 0, "\0"); for (ii=0; ii < count_timecode_steps; ii++) { char l_keyword[100]; g_snprintf(&l_keyword[0], sizeof(l_keyword), "(timecode_steps[%d] ", ii); gap_val_set_keyword(keylist, &l_keyword[0], &master_handle->timecode_steps[ii], GAP_VAL_GINT32, 0, "\0"); } } /* end p_set_analysefile_master_keywords */ /* ---------------------------- * p_save_video_analyse_results * ---------------------------- */ static void p_save_video_analyse_results(t_GVA_Handle *gvahand) { GapValKeyList *keylist; t_GVA_ffmpeg *master_handle; FILE *fp_analyse; gint ii; char *analysefile_name; master_handle = (t_GVA_ffmpeg *)gvahand->decoder_handle; analysefile_name = p_create_analysefile_name(gvahand); /* current videofile timestamp */ master_handle->timestamp = gap_file_get_mtime(gvahand->filename); master_handle->readsteps_probe_timecode = READSTEPS_PROBE_TIMECODE; fp_analyse = g_fopen(analysefile_name, "w"); if(fp_analyse) { /* overwrite file with header block (containing general comments on the video) */ fprintf(fp_analyse, "GVA_SEEK_SUPPORT_"); if (master_handle->self_test_detected_seek_bug == TRUE) { fprintf(fp_analyse, "NONE"); } else if (master_handle->video_libavformat_seek_gopsize > 0) { fprintf(fp_analyse, "NATIVE"); } else { fprintf(fp_analyse, "VINDEX"); } fprintf(fp_analyse, "\n"); fprintf(fp_analyse, "# GAP-FFMPEG video analyse results for file: %s\n" , gvahand->filename ); { int64_t duration; int64_t duration3; int64_t stt; duration = master_handle->vid_input_context->duration; duration3 = av_rescale_q(duration, AV_TIME_BASE_Q, master_handle->vid_stream->time_base); stt = master_handle->vid_input_context->start_time; /* scale stat_time from global AV_TIME_BASE to stream specific timecode */ stt = av_rescale_q(stt, AV_TIME_BASE_Q, master_handle->vid_stream->time_base); fprintf(fp_analyse , "# VINFOs:\n" "# vid_stream->time_base num:%d den:%d\n" "# vid_input_context->start_time:%lld\n" "# vid_input_context->duration:%lld\n" "# (start+duration converted to frames:%d)\n" "# (eof_timecode converted to frames:%d)\n" "# (video-libavformat-seek-gopsize config:%d actual:%d)\n" , master_handle->vid_stream->time_base.num , master_handle->vid_stream->time_base.den , master_handle->vid_input_context->start_time , master_handle->vid_input_context->duration , p_timecode_to_frame_nr(master_handle, stt+duration3) , p_timecode_to_frame_nr(master_handle, master_handle->eof_timecode) , gap_base_get_gimprc_int_value("video-libavformat-seek-gopsize", DEFAULT_NAT_SEEK_GOPSIZE, 0, MAX_NAT_SEEK_GOPSIZE) , master_handle->video_libavformat_seek_gopsize ); } fclose(fp_analyse); keylist = gap_val_new_keylist(); /* setup key/value descriptions */ p_set_analysefile_master_keywords(keylist, gvahand, master_handle->count_timecode_steps); /* save key/value data */ gap_val_rewrite_file(keylist, analysefile_name , NULL /* const char *hdr_text */ , ")" /* const char *term_str */ ); gap_val_free_keylist(keylist); } g_free(analysefile_name); } /* end p_save_video_analyse_results */ /* ---------------------------- * p_get_video_analyse_results * ---------------------------- * return * TRUE persitent analyse results are availabe (caller can skip the selftest) * FALSE persitent analyse results are NOT availabe or no longer valid * (the caller must perform the selftest) */ static gboolean p_get_video_analyse_results(t_GVA_Handle *gvahand) { #define UNDEFINED_TIMECODE_STEP_VALUE -44444444 int scanned_items; int min_expected_items; GapValKeyList *keylist; t_GVA_ffmpeg *master_handle; char *analysefile_name; gint32 curr_mtime; gint ii; gboolean ret; analysefile_name = p_create_analysefile_name(gvahand); master_handle = (t_GVA_ffmpeg *)gvahand->decoder_handle; keylist = gap_val_new_keylist(); p_set_analysefile_master_keywords(keylist, gvahand, READSTEPS_PROBE_TIMECODE); /* init structures with some non-plausible values * (will be overwritten on sucessful fetch) */ for(ii=0; ii < READSTEPS_PROBE_TIMECODE; ii++) { master_handle->timecode_steps[ii] = UNDEFINED_TIMECODE_STEP_VALUE; } min_expected_items = 10; master_handle->count_timecode_steps = -1; scanned_items = gap_val_scann_filevalues(keylist, analysefile_name); gap_val_free_keylist(keylist); curr_mtime = gap_file_get_mtime(gvahand->filename); ret = TRUE; /* check if we got plausible values from persitent storage that are still valid */ if ((scanned_items < min_expected_items) || (master_handle->count_timecode_steps <= 0) || (master_handle->count_timecode_steps > READSTEPS_PROBE_TIMECODE) || (p_equal_mtime(master_handle->timestamp, curr_mtime) != TRUE)) { /* perform analyse */ ret = FALSE; } if (ret == TRUE) { if (master_handle->timecode_steps[master_handle->count_timecode_steps -1] == UNDEFINED_TIMECODE_STEP_VALUE) { ret = FALSE; } } if(gap_debug) { printf("p_get_video_analyse_results:\n"); printf(" analysefile:%s" " min_expected_items:%d scanned_items:%d\n" " master_handle->timestamp:%d curr_mtime:%d\n" ,analysefile_name ,(int)min_expected_items ,(int)scanned_items ,(int)master_handle->timestamp ,(int)curr_mtime ); } g_free(analysefile_name); return (ret); } /* end p_get_video_analyse_results */ /* ---------------------------- * p_create_analysefile_name * ---------------------------- * the caller is responsible to g_free the returned string */ static char* p_create_analysefile_name(t_GVA_Handle *gvahand) { char *vindex_name; vindex_name = p_build_gvaidx_filename(gvahand->filename , gvahand->vid_track , GVA_FFMPEG_DECODER_NAME , "analyze"); return (vindex_name); } /* end p_create_analysefile_name */ /* ------------------------------ * p_timecode_to_frame_nr * ------------------------------ */ static gint32 p_timecode_to_frame_nr(t_GVA_ffmpeg *handle, int64_t timecode) { int64_t framenr; int64_t l_timecode; int64_t l_group_timecode; framenr = 0; l_group_timecode = 0; l_timecode = timecode - handle->timecode_offset_frame1; if (handle->timecode_steps_sum > 0) { int ii; framenr = l_timecode / (int64_t)handle->timecode_steps_sum; l_group_timecode = framenr * (int64_t)handle->timecode_steps_sum; framenr *= handle->count_timecode_steps; l_timecode -= l_group_timecode; for(ii=0; ii < handle->count_timecode_steps; ii++) { if (l_timecode > 0) { framenr++; l_timecode -= handle->timecode_steps[ii]; } } } framenr++; if(gap_debug) { printf("p_timecode_to_frame_nr: framenr:%lld timecode:%lld offset_frame1:%lld\n" , framenr , timecode , handle->timecode_offset_frame1 ); } return (framenr); } /* end p_timecode_to_frame_nr */ /* ------------------------------ * p_frame_nr_to_timecode * ------------------------------ */ static int64_t p_frame_nr_to_timecode(t_GVA_ffmpeg *handle, gint32 frame_nr) { int64_t timecode; if ((handle->count_timecode_steps <= 1) || (frame_nr <= 1)) { /* videofile with constant frametiming */ timecode = (handle->timecode_offset_frame1 + ((int64_t)(frame_nr -1) * handle->timecode_steps[0]) ); } else { int64_t frame_groups; int64_t frame_idx; int ii; /* videofile with varying frametiming pattern (as detected by proberead) * a typical example uses alternating frametiming of 3003, 4505 * with a pattern size value of 2 (handle->count_timecode_steps == 2) * * frame_nr timecode remarks * 1. 100000 timecode_offset_frame1 * 2. 103003 (+3003) * 3. 107508 (+4505) * 4. 110511 (+3003) * 5. 115016 (+4505) */ frame_groups = (frame_nr -2) / handle->count_timecode_steps; frame_idx = (frame_nr -2) % handle->count_timecode_steps; timecode = handle->timecode_offset_frame1 + (frame_groups * (int64_t)handle->timecode_steps_sum); for(ii=0; ii <= frame_idx; ii++) { timecode += handle->timecode_steps[ii]; } } if(gap_debug) { printf("FRAMENR %ld to TIMECODE:%lld offset for frame1:%lld step[0]:%d steps:%d steps_sum:%d\n" , frame_nr , timecode , handle->timecode_offset_frame1 , (int)handle->timecode_steps[0] , (int)handle->count_timecode_steps , (int)handle->timecode_steps_sum ); } return(timecode); } /* end p_frame_nr_to_timecode */ /* ------------------------------ * p_analyze_stepsize_pattern * ------------------------------ * try to findout repeating stepsize pattern, * based on the timecode_steps[] array that must be already filled * up to max_idx elements. * Result: set the count_timecode_steps * */ static void p_analyze_stepsize_pattern(gint max_idx, t_GVA_Handle *gvahand) { gint ii; gint jj; t_GVA_ffmpeg *master_handle; int gap_debug_local; gap_debug_local = gap_debug; #ifdef GAP_DEBUG_FF_NATIVE_SEEK gap_debug_local = 1; #endif /* GAP_DEBUG_FF_NATIVE_SEEK */ master_handle = (t_GVA_ffmpeg *)gvahand->decoder_handle; master_handle->count_timecode_steps = 1; ii=1; while(ii < max_idx) { if(gap_debug) { printf("loop ii:%d\n", ii); } for(jj=0; jj < ii; jj++) { if ((ii + jj) >= max_idx) { break; } if(master_handle->timecode_steps[jj] != master_handle->timecode_steps[ii + jj]) { master_handle->count_timecode_steps = ii + 1; if(gap_debug) { printf("ii:%d steps[jj: %d]:%d steps[ii+jj: %d]:%d\n" ,ii ,jj ,master_handle->timecode_steps[jj] ,ii+jj ,master_handle->timecode_steps[ii + jj] ); } break; } } if((jj == ii) || (jj+ii == max_idx)) { ii += jj; } else { ii++; } } if (master_handle->count_timecode_steps == max_idx) { printf("WARNING: p_analyze_stepsize_pattern video:%s has individual frame timing\n" , gvahand->filename ); printf(" native timecode based seek will not find exact position by frame number\n"); } master_handle->timecode_steps_sum = 0; for(ii=0; ii < master_handle->count_timecode_steps; ii++) { master_handle->timecode_steps_sum += master_handle->timecode_steps[ii]; } if(gap_debug_local) { printf("PROBEREAD: p_analyze_stepsize_pattern video:%s max_idx.%d count_timecode_steps:%d sum:%d\n" , gvahand->filename , max_idx , master_handle->count_timecode_steps , master_handle->timecode_steps_sum ); } } /* end p_analyze_stepsize_pattern */ /* ------------------------------ * p_probe_timecode_offset * ------------------------------ * if timecode offset for the 1st frame and typical stepsize(s) are not yet known * determine those values by probe reading some video frames (at least 2). * * Note that duration of frames may not be constant for all videofiles. * for videos with very individual frame durations it is not possible * to calculate correct timecode for a given frame number. * Typically most (DVD) videos use individual frame timing * in cyclic pattern manner. This probe read analyzes the type of pattern * and enables correct frame to timestamp conversion * based on the measured resulting array timecode_steps[] * (this is required for exact positioning via native seek operations) * * this procedure opens its own copy handle for the probe read * (the stream position of the orignal gvahand are not affected) * but writes the results of the probe read to the attributes * of the master handle. */ static void p_probe_timecode_offset(t_GVA_Handle *master_gvahand) { t_GVA_ffmpeg *master_handle; master_handle = (t_GVA_ffmpeg *)master_gvahand->decoder_handle; if (master_handle->timecode_proberead_done != TRUE) { gint l_readsteps; t_GVA_RetCode l_rc_rd; t_GVA_Handle *copy_gvahand; t_GVA_ffmpeg *copy_handle; gdouble avg_fstepsize; int64_t prev_timecode; gint32 l_countValidTimecodes; l_countValidTimecodes = 0; master_handle->timecode_proberead_done = TRUE; master_handle->timecode_step_abs_min = 99999999; /* calculate average timecode step per frame via framerate */ avg_fstepsize = 100000.0 / master_gvahand->framerate; master_handle->timecode_steps[0] = avg_fstepsize; if(gap_debug) { printf("p_probe_timecode_offset: %d Probe Reads to detect timecode offset\n" , READSTEPS_PROBE_TIMECODE ); } /* open an extra handle for the probe read */ copy_gvahand = g_malloc0(sizeof(t_GVA_Handle)); p_wrapper_ffmpeg_open_read(master_gvahand->filename , copy_gvahand ); copy_handle = (t_GVA_ffmpeg *)copy_gvahand->decoder_handle; copy_gvahand->current_frame_nr = 0; copy_gvahand->current_seek_nr = 1; copy_gvahand->vindex = NULL; copy_handle->dummy_read = TRUE; l_rc_rd = p_wrapper_ffmpeg_get_next_frame(copy_gvahand); master_handle->timecode_offset_frame1 = copy_handle->vid_pkt.dts; prev_timecode = copy_handle->vid_pkt.dts; l_readsteps = 0; while(l_readsteps < READSTEPS_PROBE_TIMECODE) { l_rc_rd = p_wrapper_ffmpeg_get_next_frame(copy_gvahand); if (l_rc_rd != GVA_RET_OK) { break; } if (copy_handle->vid_pkt.dts != AV_NOPTS_VALUE) { l_countValidTimecodes++; } master_handle->timecode_steps[l_readsteps] = copy_handle->vid_pkt.dts - prev_timecode; master_handle->timecode_step_abs_min = MIN(abs(master_handle->timecode_steps[l_readsteps]) , master_handle->timecode_step_abs_min); l_readsteps++; master_handle->timecode_step_avg = (copy_handle->vid_pkt.dts - master_handle->timecode_offset_frame1) / l_readsteps; if(gap_debug) { printf("p_probe_timecode_offset: step: (%d) timecode offset: %lld, stepsize:%ld (avg_measured: %ld avg: %.3f)\n" , (int)l_readsteps , master_handle->timecode_offset_frame1 , master_handle->timecode_steps[l_readsteps -1] , master_handle->timecode_step_avg , (float)avg_fstepsize ); } prev_timecode = copy_handle->vid_pkt.dts; } /* close the extra handle (that was opened for counting only) */ p_wrapper_ffmpeg_close(copy_gvahand); if (l_countValidTimecodes > 0) { p_analyze_stepsize_pattern(l_readsteps, master_gvahand); } else { /* some older ffmpeg versions did always deliver valid dts timecodes, * even if not present in the video. * but unfortunately recent ffmpeg snapshots deliver AV_NOPTS_VALUE as dts * for such videos. In this case native seek must be disabled. */ master_handle->timecode_steps_sum = 0; master_handle->count_timecode_steps = 1; master_handle->video_libavformat_seek_gopsize = 0; /* DISABLE natvie seek */ master_handle->prefere_native_seek = FALSE; printf("WARNING: p_probe_timecode_offset no valid timecode found in video:%s\n" , master_gvahand->filename ); printf(" native timecode based seek not possible\n"); } } } /* end p_probe_timecode_offset */ #endif /* ENABLE_GVA_LIBAVFORMAT */ gimp-gap-2.6.0+dfsg.orig/libgapvidapi/example.c0000644000175000017500000000563211212030253021205 0ustar thibautthibaut void p_example_read_video(char *videofile, gdouble skip_seconds, gint32 nframes) { t_GVA_Handle* gvahand; gint32 vid_track; gint32 aud_track; vid_track = 1; aud_track = 1; gvahand = GVA_open_read(videofile, vid_track, aud_track); if(gvahand) { t_GVA_RetCode l_rc; gint32 framenumber; GimpRunMode runmode; /* print informations about the videofile */ printf("Videofile : %s\n", videofile); printf(" framesize : %d x %d\n", (int)gvahand->width, (int)gvahand->width ); printf(" # of frames : %d\n", (int)gvahand->total_frames ); printf(" framerate : %f (f/sec)\n", (float)gvahand->framerate ); printf("Decoder Name : %s\n", gvahand->dec_elem->decoder_name); runmode = GIMP_RUN_INTERACTIVE; if (skip_seconds > 0.0) { /* skip the the trailer (time in seconds) */ l_rc = GVA_seek_frame(gvahand, skip_seconds, GVA_UPOS_SECS); } /* read nframes from the video */ for(framenumber=1; framenumber <= nframes; framenumber++) { gboolean delete_mode = TRUE; gint32 deinterlace; /* 0.. NO deinterlace, 1..odd rows, 2..even rows */ gdouble threshold; /* 0.0 <= threshold <= 1.0 */ char *framename; deinterlace = 1; /* threshold for interpolated rows (only used if deinterlace != 0) * - big thresholds 1.0 do smooth mix interpolation * - small thresholds keep hard edges (does not mix different colors) * - threshold 0.0 does not interpolate at all and just makes a copy of the previous row */ threshold = 1.0; /* fetch one frame to buffer gvahand->frame_data * (and proceed position to next frame) */ l_rc = GVA_get_next_frame(gvahand); if(l_rc == GVA_RET_OK) { /* convert fetched frame from buffer to gimp image gvahand->image_id * by creating a new layer gvahand->layer_id * delete_mode TRUE does first delete gvahand->layer_id * (delete_mode FALSE would not delete the layer and the layerstack would * grow upto full nframes Layers in the last turn of the loop) */ l_rc = GVA_frame_to_gimp_layer(gvahand, delete_mode, framenumber, deinterlace, threshold); /* save the extracted frames using gimp_file_save * (the fileformat is selected automatically by the extension) */ framename = g_strdup_printf("frame_%04d.jpg"); printf ("saving: %s\n", framename); gimp_file_save(runmode, gvahand->image_id, gvahand->layer_id, framename, framename); g_free(framename); /* foreach following frame use the same save settings (same jpeg quality) * as given by the User in the 1.st INTERACTIVE Run */ runmode = GIMP_RUN_WITH_LAST_VALS; } } GVA_close(gvahand); } } /* end p_example_read_video */ gimp-gap-2.6.0+dfsg.orig/libgapvidapi/gap_vid_api_quicktime.c0000644000175000017500000003171611212030253024071 0ustar thibautthibaut/* gap_vid_api_quicktime.c * * GAP Video read API implementation of quicktime * based wrappers to read various videofile formats * * 2003.05.09 hof created * */ /* ================================================ QUICKTIME * quicktime QUICKTIME * ================================================ QUICKTIME * ================================================ QUICKTIME */ #ifdef ENABLE_GVA_LIBQUICKTIME #include "quicktime.h" gboolean p_wrapper_quicktime_check_sig(char *filename) { /* quicktime_check_sig returns 1 if the file is a quicktime file */ return (1 == quicktime_check_sig(filename)); } /* ----------------------------- * p_wrapper_quicktime_open_read * ----------------------------- */ void p_wrapper_quicktime_open_read(char *filename, t_GVA_Handle *gvahand) { quicktime_t* handle; gint repeat_count; if(gap_debug) printf("p_wrapper_quicktime_open_read: START filename: %s\n", filename); /* workaround: * sometimes open succeeds, but quicktime4linux does not recognize any video or audio channel * dont know whats wrong here. * as workaround this API tries repeart the open for 3 times (only if no tracks can be found) */ for(repeat_count = 0; repeat_count < 3; repeat_count++) { handle = quicktime_open(filename , TRUE /* int rd */ , FALSE /* int wr */ ); gvahand->decoder_handle = (void *)handle; if(gvahand->decoder_handle) { gvahand->frame_bpp = 3; if(quicktime_has_video(handle)) { gvahand->vtracks = quicktime_video_tracks(handle); gvahand->vid_track = CLAMP(gvahand->vid_track, 0, gvahand->vtracks -1); gvahand->total_frames = quicktime_video_length(handle, (int)gvahand->vid_track); gvahand->framerate = quicktime_frame_rate(handle, (int)gvahand->vid_track); gvahand->width = quicktime_video_width(handle, (int)gvahand->vid_track); gvahand->height = quicktime_video_height(handle, (int)gvahand->vid_track); } else { gvahand->total_frames = 0; gvahand->framerate = 1.0; gvahand->width = 0; gvahand->height = 0; } if(quicktime_has_audio(handle)) { gvahand->atracks = quicktime_audio_tracks(handle); gvahand->aud_track = CLAMP(gvahand->aud_track, 0, gvahand->atracks -1); gvahand->samplerate = quicktime_sample_rate(handle, (int)gvahand->aud_track); gvahand->audio_cannels = quicktime_track_channels(handle, (int)gvahand->aud_track); gvahand->total_aud_samples = quicktime_audio_length(handle, (int)gvahand->aud_track); gvahand->audio_playtime_sec = (gdouble)gvahand->total_aud_samples / (gdouble)gvahand->samplerate; } if((gvahand->atracks > 0) || (gvahand->vtracks > 0)) { break; /* OK video and /or audio found */ } else { if(gap_debug) printf("quicktime Open problems attempt:%d\n", (int)repeat_count); quicktime_close(handle); /* workaround: close and try open another time */ quicktime_check_sig(filename); gvahand->decoder_handle = NULL; } } } /* end for repeat_count */ } /* end p_wrapper_quicktime_open_read */ /* ----------------------------- * p_wrapper_quicktime_close * ----------------------------- */ void p_wrapper_quicktime_close(t_GVA_Handle *gvahand) { quicktime_close((quicktime_t *)gvahand->decoder_handle); } /* ---------------------------------- * p_wrapper_quicktime_get_next_frame * ---------------------------------- * TODO: * - how to call CODEC on the buffers * - Quicktime ? are internal CODECS applied automatc ? */ t_GVA_RetCode p_wrapper_quicktime_get_next_frame(t_GVA_Handle *gvahand) { quicktime_t *handle; int l_rc; handle = (quicktime_t *)gvahand->decoder_handle; /* Decode or the frame into a frame buffer. */ /* All the frame buffers passed to these functions are unsigned char */ /* rows with 3 bytes per pixel. The byte order per 3 byte pixel is */ /* RGB. */ l_rc = quicktime_decode_video(handle ,gvahand->row_pointers ,(int)gvahand->vid_track ); if(l_rc == 0) { gvahand->current_frame_nr = gvahand->current_seek_nr; gvahand->current_seek_nr++; return(GVA_RET_OK); } if(l_rc == 1) { return(GVA_RET_EOF); } return(GVA_RET_ERROR); } /* end p_wrapper_quicktime_get_next_frame */ /* ------------------------------ * p_wrapper_quicktime_seek_frame * ------------------------------ */ t_GVA_RetCode p_wrapper_quicktime_seek_frame(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit) { quicktime_t *handle; int l_rc; longest l_frame_pos; handle = (quicktime_t *)gvahand->decoder_handle; switch(pos_unit) { case GVA_UPOS_FRAMES: l_frame_pos = (longest)pos; break; case GVA_UPOS_SECS: l_frame_pos = (longest)round(pos * gvahand->framerate); break; case GVA_UPOS_PRECENTAGE: l_frame_pos = (longest)GVA_percent_2_frame(gvahand->total_frames, pos); break; default: l_frame_pos = (longest)pos; break; } l_rc = quicktime_set_video_position(handle ,l_frame_pos ,(int)gvahand->vid_track ); if(l_rc == 0) { gvahand->current_seek_nr = (gint32)l_frame_pos; return(GVA_RET_OK); } if(l_rc == 1) { return(GVA_RET_EOF); } return(GVA_RET_ERROR); } /* end p_wrapper_quicktime_seek_frame */ /* ------------------------------ * p_wrapper_quicktime_seek_audio * ------------------------------ * TODO: - Retocde evaluation (what is OK, EOF or ERROR ?) */ t_GVA_RetCode p_wrapper_quicktime_seek_audio(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit) { quicktime_t *handle; int l_rc; longest l_sample_pos; gint32 l_frame_pos; handle = (quicktime_t *)gvahand->decoder_handle; switch(pos_unit) { case GVA_UPOS_FRAMES: l_sample_pos = (longest)GVA_frame_2_samples(gvahand->framerate, gvahand->samplerate, pos); break; case GVA_UPOS_SECS: l_sample_pos = (longest)round(pos / MAX(gvahand->samplerate, 1.0)); break; case GVA_UPOS_PRECENTAGE: l_frame_pos= (longest)GVA_percent_2_frame(gvahand->total_frames, pos); l_sample_pos = (longest)GVA_frame_2_samples(gvahand->framerate, gvahand->samplerate, l_frame_pos); break; default: l_sample_pos = 0; break; } l_rc = quicktime_set_audio_position(handle ,l_sample_pos ,(int)gvahand->aud_track ); if(l_rc == 0) { gvahand->current_sample = (gint32)l_sample_pos; return(GVA_RET_OK); } if(l_rc == 1) { return(GVA_RET_EOF); } return(GVA_RET_ERROR); } /* end p_wrapper_quicktime_seek_audio */ /* ------------------------------ * p_wrapper_quicktime_get_audio * ------------------------------ */ t_GVA_RetCode p_wrapper_quicktime_get_audio(t_GVA_Handle *gvahand ,gint16 *output_i ,gint32 channel ,gdouble samples ,t_GVA_AudPos mode_flag ) { quicktime_t *handle; int l_rc; handle = (quicktime_t *)gvahand->decoder_handle; if(mode_flag == GVA_AMOD_FRAME) { p_wrapper_quicktime_seek_audio(gvahand , (gdouble) gvahand->current_frame_nr , GVA_UPOS_FRAMES ); } if(mode_flag == GVA_AMOD_REREAD) { printf("p_wrapper_quicktime_get_audio: GVA_AMOD_REREAD not implemented\n"); } /* TODO: * howto specify desired AUDIO TRACK ?? gvahand->aud_track * (are channel numbers unique or local to audio track ???) */ l_rc = quicktime_decode_audio(handle ,(int16_t *)output_i ,NULL /* float *output_f */ ,(long)samples ,(int)channel ); if(l_rc == 0) { gvahand->current_sample += samples; /* keep track of current sample position */ return(GVA_RET_OK); } if(l_rc == 1) { return(GVA_RET_EOF); } return(GVA_RET_ERROR); } /* end p_wrapper_quicktime_get_audio */ /* ---------------------------------- * p_wrapper_quicktime_count_frames * ---------------------------------- * (re)open a separated handle for counting * to ensure that stream positions are not affected by the count. */ t_GVA_RetCode p_wrapper_quicktime_count_frames(t_GVA_Handle *gvahand) { quicktime_t* handle; int l_rc; t_GVA_Handle copy_gvahand; gdouble l_progress_step; gvahand->percentage_done = 0.0; /* WORKAROUND: * a) quicktime does not really need count because total_frames seems to be exact value * b) this implementatation does not work, because quicktime_decode_video always * returnes wit retcode == 0 and gives us no chance to stop at EOF * this are 2 reasons to do not cont at all. */ return(GVA_RET_OK); copy_gvahand.frame_data = NULL; copy_gvahand.row_pointers = NULL; copy_gvahand.width = gvahand->width; copy_gvahand.height = gvahand->height; copy_gvahand.frame_bpp = gvahand->frame_bpp; /* allocate frame_data and row_pointers for one frame (minimal cachesize 1 == no chaching) */ p_build_frame_cache(©_gvahand, 1); handle = quicktime_open(gvahand->filename , TRUE /* int rd */ , FALSE /* int wr */ ); /* percentage_done is just a guess, because we dont know * the exact total_frames number before. * (we assume that there may be 11 frames more) */ l_progress_step = 1.0 / (gdouble)(gvahand->total_frames + 11.0); gvahand->frame_counter = 0; while(!gvahand->cancel_operation) { /* read one frame (we use the comressed chunk * because this is a dummy read to count frames only) * quicktime_read_frame DID not work (always returned 905) */ /* l_rc = quicktime_read_frame(handle * , dummy_buffer * , gvahand->vid_track * ); */ l_rc = quicktime_decode_video(handle ,copy_gvahand.row_pointers ,(int)gvahand->vid_track ); if (gap_debug) printf("quicktime_read_frame: l_rc == %d\n", (int)l_rc); if(l_rc != 0) { break; /* eof, or fetch error */ } gvahand->frame_counter++; gvahand->percentage_done = CLAMP(gvahand->percentage_done + l_progress_step, 0.0, 1.0); if(gvahand->fptr_progress_callback) { gvahand->cancel_operation = (*gvahand->fptr_progress_callback)(gvahand->percentage_done, gvahand->progress_cb_user_data); } } /* close the extra handle (that was opened for counting only) */ quicktime_close(handle); p_drop_frame_cache(©_gvahand); gvahand->percentage_done = 0.0; if(!gvahand->cancel_operation) { gvahand->total_frames = gvahand->frame_counter; gvahand->all_frames_counted = TRUE; } else { gvahand->total_frames = MAX(gvahand->total_frames, gvahand->frame_counter); gvahand->cancel_operation = FALSE; /* reset cancel flag */ return(GVA_RET_ERROR); } return(GVA_RET_OK); } /* end p_wrapper_quicktime_count_frames */ /* ----------------------------- * p_quicktime_new_dec_elem * ----------------------------- * create a new decoder element and init with * functionpointers referencing the QUICKTIME * specific Procedures */ t_GVA_DecoderElem * p_quicktime_new_dec_elem(void) { t_GVA_DecoderElem *dec_elem; dec_elem = g_malloc0(sizeof(t_GVA_DecoderElem)); if(dec_elem) { dec_elem->decoder_name = g_strdup("quicktime4linux"); dec_elem->decoder_description = g_strdup("Quicktime Decoder (CODECS: JPEG,PNG,MJPG) (EXT: .mov)"); dec_elem->fptr_check_sig = &p_wrapper_quicktime_check_sig; dec_elem->fptr_open_read = &p_wrapper_quicktime_open_read; dec_elem->fptr_close = &p_wrapper_quicktime_close; dec_elem->fptr_get_next_frame = &p_wrapper_quicktime_get_next_frame; dec_elem->fptr_seek_frame = &p_wrapper_quicktime_seek_frame; dec_elem->fptr_seek_audio = &p_wrapper_quicktime_seek_audio; dec_elem->fptr_get_audio = &p_wrapper_quicktime_get_audio; dec_elem->fptr_count_frames = &p_wrapper_quicktime_count_frames; dec_elem->fptr_seek_support = NULL; dec_elem->fptr_get_video_chunk = NULL; /* &p_wrapper_quicktime_get_video_chunk; */ dec_elem->next = NULL; } return (dec_elem); } /* end p_quicktime_new_dec_elem */ #endif /* ENABLE_GVA_LIBQUICKTIME */ gimp-gap-2.6.0+dfsg.orig/libgapvidapi/gap_vid_api.h0000644000175000017500000004365511212030253022030 0ustar thibautthibaut/* gap_vid_api.h * * ------------------------ * API READ movie frames * ------------------------ */ /* ------------------------------------------------ * 2003.05.09 * * This API (GAP Video Api) provides basic READ functions to access * Videoframes of some sopported Videoformats. * * 2004.09.25 (hof) added GVA_util_check_mpg_frame_type * 2004.04.25 (hof) integration into gimp-gap * 2004.03.06 (hof) videoindex * 2004.02.28 (hof) added procedures GVA_frame_to_buffer, GVA_delace_frame */ #ifndef GAP_VID_API_H #define GAP_VID_API_H #include #include #include "gap/gap_image.h" #define GVA_MPGFRAME_UNKNOWN -1 #define GVA_MPGFRAME_I_TYPE 1 #define GVA_MPGFRAME_P_TYPE 2 #define GVA_MPGFRAME_B_TYPE 3 #define GVA_MPGHDR_PICTURE_START_CODE 0x00000100 #define GVA_MPGHDR_GOP_START_CODE 0x000001b8 /* ----------------------- * TYPES * ----------------------- */ typedef enum t_GVA_AudPos { GVA_AMOD_FRAME /* start audio reads from current frame pos */ ,GVA_AMOD_CUR_AUDIO /* start audio reads from current audio pos */ ,GVA_AMOD_REREAD /* start from same pos as last audioread */ } t_GVA_AudPos; typedef enum t_GVA_PosUnit { GVA_UPOS_FRAMES ,GVA_UPOS_SECS ,GVA_UPOS_PRECENTAGE /* 0.0 upto 1.0 */ } t_GVA_PosUnit; typedef enum t_GVA_RetCode { GVA_RET_OK = 0 ,GVA_RET_EOF = 1 ,GVA_RET_ERROR = 2 } t_GVA_RetCode; typedef enum t_GVA_SeekSupport { GVA_SEEKSUPP_NONE = 0 /* no fast random positioning possible for this video * (with the current decoder) * The caller still can use GVA_seek * but in this case seek will be emulated via * very slow sequential read loop. */ , GVA_SEEKSUPP_VINDEX = 1 /* creating a video index will provide random positioning */ , GVA_SEEKSUPP_NATIVE = 2 /* random positioning supported even without creating a video index */ } t_GVA_SeekSupport; #define GVA_MAX_FCACHE_SIZE 1000 /* * Frame Cache schema with at cachesize of 5 elements * * +----+ +----+ +----+ +----+ +----+ * +----|prev|<----|prev|<----|prev|<----|prev|<----|prev|<----+ * | +->|next|---->|next|---->|next|---->|next|---->|next|---+ | * | | |frm_| |frm_| | | | | | | | | * | | |data| |data| | | | | | | | | * | | +----+ +----+ +----+ +----+ +----+ | | * | | | | | | | | | * | | ##### ##### +---+ +---+ +---+ | | * | | ##### ##### | | | | | | | | * | | ##### ##### | | | | | | | | * | | ##### ##### +---+ +---+ +---+ | | * | | | | * | +-------------------------------------------------------+ | * +-----------------------------------------------------------+ * * The Frame cache is a list, linked to a ring. * all elements and frame_data pointers are created at open time, * the ringpointers are updated when the calling program * changes max_frame_cache. * * gvahand->frame_data and gvahand->row_pointers * are pointers to the current framecache, and are * advanced before each read_next_frame call. * */ typedef struct t_GVA_Frame_Cache_Elem { gint32 id; /* element identifier */ gint32 framenumber; /* -1 is the mark for unused elements */ guchar *frame_data; /* uncompressed framedata */ guchar **row_pointers; /* array of pointers to each row of the frame_data */ void *prev; void *next; } t_GVA_Frame_Cache_Elem; typedef struct t_GVA_Frame_Cache { t_GVA_Frame_Cache_Elem *fc_current; /* pointer to 1.st element of frame chache list */ gint32 frame_cache_size; /* number of frames in the cache */ gint32 max_fcache_id; gboolean fcache_locked; /* TRUE whilw SEEK_FRAME and GET_NEXT_FRAME operations in progress */ } t_GVA_Frame_Cache; typedef gboolean (*t_GVA_progress_callback_fptr)(gdouble progress, gpointer user_data); /* ----------------- * vindex stuff * ----------------- */ #define GVA_VIDINDEXTAB_BLOCK_SIZE 500 #define GVA_VIDINDEXTAB_DEFAULT_STEPSIZE 100 typedef struct t_GVA_VideoindexHdr { char key_identifier[15]; char key_type[5]; char val_type[10]; char key_step[5]; char val_step[10]; char key_size[5]; char val_size[10]; char key_trak[5]; char val_trak[5]; char key_ftot[5]; char val_ftot[10]; char key_deco[5]; char val_deco[15]; char key_mtim[5]; char val_mtim[15]; char key_flen[5]; char val_flen[10]; } t_GVA_VideoindexHdr; typedef enum { GVA_IDX_TT_WITHOUT_TIMECODE_GINT64 /* only used in old format */ ,GVA_IDX_TT_WITHOUT_TIMECODE_GDOUBLE /* only used in old format */ ,GVA_IDX_TT_GINT64 ,GVA_IDX_TT_GDOUBLE ,GVA_IDX_TT_UNDEFINED } t_GVA_IndexTabType; typedef union { gint64 offset_gint64; gdouble offset_gdouble; } t_GVA_UnionElem; typedef struct t_GVA_IndexElemWithoutTimecode /* old format */ { gint32 seek_nr; guint16 frame_length; guint16 checksum; t_GVA_UnionElem uni; } t_GVA_IndexElemWithoutTimecode; typedef struct t_GVA_IndexElem { gint32 seek_nr; guint16 frame_length; guint16 checksum; t_GVA_UnionElem uni; gint64 timecode_dts; } t_GVA_IndexElem; typedef struct t_GVA_Videoindex /* nick: vindex */ { t_GVA_VideoindexHdr hdr; t_GVA_IndexTabType tabtype; char *videoindex_filename; char *videofile_uri; char *tocfile; gint32 stepsize; gint32 tabsize_used; gint32 tabsize_allocated; gint32 track; gint32 total_frames; gint32 mtime; t_GVA_IndexElem *ofs_tab; } t_GVA_Videoindex; /* ------------------------------------ * GVA HANDLE Stucture * ------------------------------------ */ typedef struct t_GVA_Handle /* nickname: gvahand */ { gboolean cancel_operation; /* */ gboolean dirty_seek; /* libmpeg3: FALSE: use native seek, TRUE: use gopseek workaround */ gboolean emulate_seek; /* emulate seek ops by dummy read ops (for slow and exact positioning) */ gboolean create_vindex; /* TRUE: allow the fptr_count_frames procedure to create a videoindex file */ t_GVA_Videoindex *vindex; gint32 mtime; gboolean disable_mmx; gboolean do_gimp_progress; /* WARNING: dont try to set this TRUE if you call the API from a thread !! */ gboolean all_frames_counted; /* TRUE: counted all frames, total_frames is an exact value * FALSE: total_frames may not tell the exact value. */ gboolean all_samples_counted; gint32 frame_counter; gpointer progress_cb_user_data; t_GVA_progress_callback_fptr fptr_progress_callback; /* if != NULL: The API calls this user procedure with current progress * if the procedure returns TRUE * the API does cancel current seek operations immediate. */ /* PUBLIC information (read only outside the API) */ gint32 total_frames; /* 0 no video */ gdouble framerate; /* frames per sec */ gint32 current_frame_nr; /* nr of the image in the internal frame_data buffer * (0 at open, 1 after reading 1.st frame) * will not be updated at seek operations */ gint32 current_seek_nr; /* 1 at open, 2 after reading 1.st frame * is updated on seek and read_next operations */ gdouble current_sample; /* 1 at open. Position of current audiosample * is updated on seek and read_next operations */ gdouble reread_sample_pos; /* last audioread pos (used in avlib ffmpeg only) */ gint32 width; /* width of the videoframes */ gint32 height; /* height of the videoframes */ gdouble aspect_ratio; /* 0 for unknown, or aspect_ratio width/heigth */ gint32 vtracks; /* number of videotracks in the videofile */ gint32 atracks; /* number of audiotracks in the videofile */ gdouble audio_playtime_sec; /* 0 if no audio */ gint32 total_aud_samples; /* number of audio samples */ gint32 samplerate; /* audio samples per sec */ gint32 audio_cannels; /* number of channel (in the selected aud_track) */ gboolean critical_timecodesteps_found; gdouble percentage_done; /* 0.0 <= percentage_done <= 1.0 */ /* Image and frame buffer */ gint32 image_id; /* -1 if there is no image */ gint32 layer_id; /* frame buffer */ guchar *frame_data; /* the frame data buffer (colormodel RGBA or RGB is decoder dependent) */ guchar **row_pointers; /* array of pointers to each row of the frame_data */ gint32 frame_bpp; /* dont change this, is set by the decoder (Byte per pixel of frame_data buffer, delivered by decoder 4 or 3) */ t_GVA_Frame_Cache fcache; /* Frame Cache structure */ /* frame cache buffer(use GVA_search_fcache to set the fc_xxx pointers) */ guchar *fc_frame_data; /* cached frame data buffer */ guchar **fc_row_pointers; /* array of pointers to each row */ /* PRIVATE members (dont change this outside the API !) */ void *dec_elem; /* t_GVA_DecoderElem * a Decoder that can handle the videofile */ void *decoder_handle; gint32 vid_track; gint32 aud_track; char *filename; gboolean gva_thread_save; } t_GVA_Handle; typedef enum { GVA_VIDEO_CODEC ,GVA_AUDIO_CODEC } t_GVA_CodecType; /* Function Typedefs */ typedef gboolean (*t_check_sig_fptr)(char *filename); typedef void (*t_open_read_fptr)(char *filename, t_GVA_Handle *gvahand); typedef void (*t_close_fptr)(t_GVA_Handle *gvahand); typedef t_GVA_RetCode (*t_get_next_frame_fptr)(t_GVA_Handle *gvahand); typedef t_GVA_RetCode (*t_seek_frame_fptr)(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit); typedef t_GVA_RetCode (*t_seek_audio_fptr)(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit); typedef t_GVA_RetCode (*t_get_audio_fptr)(t_GVA_Handle *gvahand ,gint16 *output_i ,gint32 channel ,gdouble samples ,t_GVA_AudPos mode_flag ); typedef t_GVA_RetCode (*t_count_frames_fptr)(t_GVA_Handle *gvahand); typedef t_GVA_SeekSupport (*t_seek_support_fptr)(t_GVA_Handle *gvahand); typedef t_GVA_RetCode (*t_get_video_chunk_fptr)(t_GVA_Handle *gvahand ,gint32 frame_nr ,unsigned char *chunk ,gint32 *sizes ,gint32 max_size ); typedef char * (*t_get_codec_name_fptr)(t_GVA_Handle *gvahand ,t_GVA_CodecType codec_type ,gint32 track_nr ); /* List Element Description for a Decoder */ typedef struct t_GVA_DecoderElem { char *decoder_name; char *decoder_description; void *next; /* functionpointers to decoder specific procedures */ t_check_sig_fptr fptr_check_sig; t_open_read_fptr fptr_open_read; t_close_fptr fptr_close; t_get_next_frame_fptr fptr_get_next_frame; t_seek_frame_fptr fptr_seek_frame; t_seek_audio_fptr fptr_seek_audio; t_get_audio_fptr fptr_get_audio; t_count_frames_fptr fptr_count_frames; t_seek_support_fptr fptr_seek_support; t_get_video_chunk_fptr fptr_get_video_chunk; t_get_codec_name_fptr fptr_get_codec_name; } t_GVA_DecoderElem; /* ------------------------------------ * Declare Public API functions * ------------------------------------ * Tracknumbers (vid_track, aud_track) start at 1 for the API user * (API internal the first track has number 0) */ t_GVA_Handle * GVA_open_read_pref(const char *filename, gint32 vid_track, gint32 aud_track ,const char *preferred_decoder ,gboolean disable_mmx ); t_GVA_Handle* GVA_open_read(const char *filename, gint32 vid_track, gint32 aud_track); t_GVA_RetCode GVA_get_next_frame(t_GVA_Handle *gvahand); t_GVA_RetCode GVA_seek_frame(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit); void GVA_close(t_GVA_Handle *gvahand); t_GVA_RetCode GVA_seek_audio(t_GVA_Handle *gvahand, gdouble pos, t_GVA_PosUnit pos_unit); t_GVA_RetCode GVA_get_audio(t_GVA_Handle *gvahand ,gint16 *output_i /* preallocated buffer large enough for samples * siezeof gint16 */ ,gint32 channel /* audiochannel 1 upto n */ ,gdouble samples /* number of samples to read */ ,t_GVA_AudPos mode_flag /* specify the position where to start reading audio from */ ); t_GVA_RetCode GVA_count_frames(t_GVA_Handle *gvahand); t_GVA_SeekSupport GVA_check_seek_support(t_GVA_Handle *gvahand); void GVA_set_fcache_size(t_GVA_Handle *gvahand ,gint32 frames_to_keep_cahed ); t_GVA_RetCode GVA_search_fcache(t_GVA_Handle *gvahand ,gint32 framenumber ); t_GVA_RetCode GVA_search_fcache_by_index(t_GVA_Handle *gvahand ,gint32 index ,gint32 *framenumber ); void GVA_debug_print_fcache(t_GVA_Handle *gvahand); void GVA_image_set_aspect(t_GVA_Handle *gvahand, gint32 image_id); t_GVA_RetCode GVA_gimp_image_to_rowbuffer(t_GVA_Handle *gvahand, gint32 image_id); t_GVA_RetCode GVA_frame_to_gimp_layer(t_GVA_Handle *gvahand , gboolean delete_mode , gint32 framenumber , gint32 deinterlace , gdouble threshold /* 0.0 <= threshold <= 1.0 */ ); gint32 GVA_frame_to_gimp_layer_2(t_GVA_Handle *gvahand , gint32 *image_id , gint32 old_layer_id , gboolean delete_mode , gint32 framenumber , gint32 deinterlace , gdouble threshold /* 0.0 <= threshold <= 1.0 */ ); gint32 GVA_fcache_to_gimp_image(t_GVA_Handle *gvahand , gint32 min_framenumber , gint32 max_framenumber , gint32 deinterlace , gdouble threshold ); guchar * GVA_frame_to_buffer(t_GVA_Handle *gvahand , gboolean do_scale , gint32 framenumber , gint32 deinterlace , gdouble threshold , gint32 *bpp , gint32 *width , gint32 *height ); guchar * GVA_fetch_frame_to_buffer(t_GVA_Handle *gvahand , gboolean do_scale , gint32 framenumber , gint32 deinterlace , gdouble threshold , gint32 *bpp , gint32 *width , gint32 *height ); guchar * GVA_delace_frame(t_GVA_Handle *gvahand , gint32 deinterlace , gdouble threshold ); void GVA_delace_drawable(gint32 drawable_id , gint32 deinterlace , gdouble threshold ); gint32 GVA_percent_2_frame(gint32 total_frames, gdouble percent); gdouble GVA_frame_2_percent(gint32 total_frames, gdouble framenr); void GVA_debug_print_videoindex(t_GVA_Handle *gvahand); char * GVA_build_videoindex_filename(const char *filename, gint32 track, const char *decoder_name); char * GVA_build_video_toc_filename(const char *filename, const char *decoder_name); gboolean GVA_has_video_chunk_proc(t_GVA_Handle *gvahand); t_GVA_RetCode GVA_get_video_chunk(t_GVA_Handle *gvahand , gint32 frame_nr , unsigned char *chunk , gint32 *size , gint32 max_size); char * GVA_get_codec_name(t_GVA_Handle *gvahand ,t_GVA_CodecType codec_type ,gint32 track_nr ); gint GVA_util_check_mpg_frame_type(unsigned char *buffer, gint32 buf_size); void GVA_util_fix_mpg_timecode(unsigned char *buffer ,gint32 buf_size ,gdouble master_framerate ,gint32 master_frame_nr ); gint32 GVA_util_calculate_mpeg_frameheader_size(unsigned char *buffer ,gint32 buf_size ); gboolean GVA_util_check_jpg_picture(unsigned char *buffer ,gint32 buf_size ,gint32 max_check_size ,gint32 *hdr_size ); gboolean GVA_util_check_png_picture(unsigned char *buffer ,gint32 buf_size ,gint32 max_check_size ,gint32 *hdr_size ); void GVA_md5_string(char *name, const char *uri); gchar* GVA_filename_to_uri(const char *filename); #endif gimp-gap-2.6.0+dfsg.orig/gap/0000755000175000017500000000000011212031411015511 5ustar thibautthibautgimp-gap-2.6.0+dfsg.orig/gap/gap_image.c0000644000175000017500000003270211212030253017575 0ustar thibautthibaut/* gap_image.c procedures * 2003.10.09 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains Image specific Procedures */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.20d; 2003.10.14 hof: created */ /* SYTEM (UNIX) includes */ #include #include #include #include #include extern int gap_debug; /* ============================================================================ * gap_image_delete_immediate * delete image (with workaround to ensure that most of the * allocatd memory is freed) * ============================================================================ */ void gap_image_delete_immediate (gint32 image_id) { if(gap_debug) printf("gap_image_delete_immediate: SCALED down to 2x2 id = %d (workaround for gimp_image-delete problem)\n", (int)image_id); gimp_image_undo_disable(image_id); gimp_image_scale(image_id, 2, 2); gimp_image_undo_enable(image_id); /* clear undo stack */ gimp_image_delete(image_id); } /* end gap_image_delete_immediate */ /* ============================================================================ * gap_image_merge_visible_layers * merge visible layer an return layer_id of the resulting merged layer. * (with workaround, for empty images return transparent layer) * ============================================================================ */ gint32 gap_image_merge_visible_layers(gint32 image_id, GimpMergeType mergemode) { GimpImageBaseType l_type; guint l_width, l_height; gint32 l_layer_id; /* get info about the image */ l_width = gimp_image_width(image_id); l_height = gimp_image_height(image_id); l_type = gimp_image_base_type(image_id); l_type = (l_type * 2); /* convert from GimpImageBaseType to GimpImageType */ /* add 2 full transparent dummy layers at top * (because gimp_image_merge_visible_layers complains * if there are less than 2 visible layers) */ l_layer_id = gimp_layer_new(image_id, "dummy", l_width, l_height, l_type, 0.0, /* Opacity full transparent */ 0); /* NORMAL */ gimp_image_add_layer(image_id, l_layer_id, 0); l_layer_id = gimp_layer_new(image_id, "dummy", 10, 10, l_type, 0.0, /* Opacity full transparent */ 0); /* NORMAL */ gimp_image_add_layer(image_id, l_layer_id, 0); return gimp_image_merge_visible_layers (image_id, mergemode); } /* end gap_image_merge_visible_layers */ /* ============================================================================ * gap_image_prevent_empty_image * check if the resulting image has at least one layer * (gimp 1.0.0 tends to crash on layerless images) * ============================================================================ */ void gap_image_prevent_empty_image(gint32 image_id) { GimpImageBaseType l_type; guint l_width, l_height; gint32 l_layer_id; gint l_nlayers; gint32 *l_layers_list; l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list != NULL) { g_free (l_layers_list); } else l_nlayers = 0; if(l_nlayers == 0) { /* the resulting image has no layer, add a transparent dummy layer */ /* get info about the image */ l_width = gimp_image_width(image_id); l_height = gimp_image_height(image_id); l_type = gimp_image_base_type(image_id); l_type = (l_type * 2); /* convert from GimpImageBaseType to GimpImageType */ /* add a transparent dummy layer */ l_layer_id = gimp_layer_new(image_id, "dummy", l_width, l_height, l_type, 0.0, /* Opacity full transparent */ 0); /* NORMAL */ gimp_image_add_layer(image_id, l_layer_id, 0); } } /* end gap_image_prevent_empty_image */ /* ============================================================================ * gap_image_new_with_layer_of_samesize * ============================================================================ * create empty image * if layer_id is NOT NULL then create one full transparent layer at full image size * and return the layer_id */ gint32 gap_image_new_with_layer_of_samesize(gint32 old_image_id, gint32 *layer_id) { GimpImageBaseType l_type; guint l_width; guint l_height; gint32 new_image_id; gdouble l_xresoulution, l_yresoulution; gint32 l_unit; /* create empty image */ l_width = gimp_image_width(old_image_id); l_height = gimp_image_height(old_image_id); l_type = gimp_image_base_type(old_image_id); l_unit = gimp_image_get_unit(old_image_id); gimp_image_get_resolution(old_image_id, &l_xresoulution, &l_yresoulution); new_image_id = gimp_image_new(l_width, l_height,l_type); gimp_image_set_resolution(new_image_id, l_xresoulution, l_yresoulution); gimp_image_set_unit(new_image_id, l_unit); if(layer_id) { l_type = (l_type * 2); /* convert from GimpImageBaseType to GimpImageType */ *layer_id = gimp_layer_new(new_image_id, "dummy", l_width, l_height, l_type, 0.0, /* Opacity full transparent */ 0); /* NORMAL */ gimp_image_add_layer(new_image_id, *layer_id, 0); } return (new_image_id); } /* end gap_image_new_with_layer_of_samesize */ gint32 gap_image_new_of_samesize(gint32 old_image_id) { return(gap_image_new_with_layer_of_samesize(old_image_id, NULL)); } /* ------------------------------------ * gap_image_is_alive * ------------------------------------ * TODO: gimp 1.3.x sometimes keeps a copy of closed images * therefore this proceedure may tell only half the truth * * return TRUE if OK (image is still valid) * return FALSE if image is NOT valid */ gboolean gap_image_is_alive(gint32 image_id) { gint32 *images; gint nimages; gint l_idi; gint l_found; if(image_id < 0) { return FALSE; } images = gimp_image_list(&nimages); l_idi = nimages -1; l_found = FALSE; while((l_idi >= 0) && images) { if(image_id == images[l_idi]) { l_found = TRUE; break; } l_idi--; } if(images) g_free(images); if(l_found) { return TRUE; /* OK */ } if(gap_debug) printf("gap_image_is_alive: image_id %d is not VALID\n", (int)image_id); return FALSE ; /* INVALID image id */ } /* end gap_image_is_alive */ /* ------------------------------------ * gap_image_get_any_layer * ------------------------------------ * return the id of the active layer * or the id of the first layer found in the image if there is no active layer * or -1 if the image has no layer at all. */ gint32 gap_image_get_any_layer(gint32 image_id) { gint32 l_layer_id; gint l_nlayers; gint32 *l_layers_list; l_layer_id = gimp_image_get_active_layer(image_id); if(l_layer_id < 0) { l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list != NULL) { l_layer_id = l_layers_list[0]; g_free (l_layers_list); } } return (l_layer_id); } /* end gap_image_get_any_layer */ /* ------------------------------------ * gap_image_merge_to_specified_layer * ------------------------------------ * remove all other layers from the image except the specified layer_id * (by removing other layers, make ref_layer_id visible and perform merging) */ gint32 gap_image_merge_to_specified_layer(gint32 ref_layer_id, GimpMergeType mergemode) { gint32 l_image_id; l_image_id = gimp_drawable_get_image(ref_layer_id); if(l_image_id >= 0) { gint32 l_idx; gint l_nlayers; gint32 *l_layers_list; l_layers_list = gimp_image_get_layers(l_image_id, &l_nlayers); if(l_layers_list != NULL) { for(l_idx = 0; l_idx < l_nlayers; l_idx++) { gboolean l_visible; if (l_layers_list[l_idx] == ref_layer_id) { gimp_drawable_set_visible(l_layers_list[l_idx], TRUE); } else { gimp_image_remove_layer(l_image_id, l_layers_list[l_idx]); } } g_free (l_layers_list); return (gap_image_merge_visible_layers(l_image_id, mergemode)); } } return (-1); } /* end gap_image_merge_to_specified_layer */ /* ------------------------------------------------------- * gap_image_set_selection_from_selection_or_drawable * ------------------------------------------------------- * create a selection in the specified image_id. * The selection is a scaled copy of the selection in another image, * refered by ref_drawable_id, or a Grayscale copy of the specified ref_drawable_id * (in case the refered image has no selection or the flag force_from_drawable is TRUE) * * - operates on a duplicate of the image refered by ref_drawable_id. * - this duplicate is scaled to same size as specified image_id * * return TRUE in case the selection was successfully created . */ gboolean gap_image_set_selection_from_selection_or_drawable(gint32 image_id, gint32 ref_drawable_id , gboolean force_from_drawable) { gint32 l_aux_channel_id; gint32 ref_image_id; gint32 work_drawable_id; /* the duplicate of the layer that is used as selction mask */ gint32 dup_image_id; gboolean has_selection; gboolean non_empty; gint x1, y1, x2, y2; if ((image_id < 0) || (ref_drawable_id < 0)) { return (FALSE); } ref_image_id = gimp_drawable_get_image(ref_drawable_id); if (ref_image_id < 0) { printf("ref_drawable_id does not refere to a valid image layer_id:%d\n", (int)ref_drawable_id); return (FALSE); } dup_image_id = gimp_image_duplicate(ref_image_id); if (dup_image_id < 0) { printf("duplicating of image failed, refered souce image_id:%d\n", (int)ref_image_id); return (FALSE); } /* clear undo stack */ if (gimp_image_undo_is_enabled(dup_image_id)) { gimp_image_undo_disable(dup_image_id); } if ((gimp_image_width(image_id) != gimp_image_width(dup_image_id)) || (gimp_image_height(image_id) != gimp_image_height(dup_image_id))) { if(gap_debug) { printf("scaling tmp image_id: %d\n", (int)dup_image_id); } gimp_image_scale(dup_image_id, gimp_image_width(image_id), gimp_image_height(image_id)); } has_selection = gimp_selection_bounds(ref_image_id, &non_empty, &x1, &y1, &x2, &y2); if ((has_selection) && (non_empty) && (force_from_drawable != TRUE)) { /* use scaled copy of the already exisating selection in the refered image */ work_drawable_id = gimp_image_get_selection(dup_image_id); } else { gint32 active_layer_stackposition; /* create selection as gray copy of the alt_selection layer */ active_layer_stackposition = gap_layer_get_stackposition(ref_image_id, ref_drawable_id); if(gimp_image_base_type(dup_image_id) != GIMP_GRAY) { if(gap_debug) { printf("convert to GRAYSCALE tmp image_id: %d\n", (int)dup_image_id); } gimp_image_convert_grayscale(dup_image_id); } work_drawable_id = gap_layer_get_id_by_stackposition(dup_image_id, active_layer_stackposition); gimp_layer_resize_to_image_size (work_drawable_id); } gimp_selection_all(image_id); //l_sel_channel_id = gimp_image_get_selection(image_id); l_aux_channel_id = gimp_selection_save(image_id); /* copy the work drawable (layer or channel) into the selection channel * the work layer is a grayscale copy GRAY or GRAYA of the alt_selection layer * that is already scaled and resized to fit the size of the target image * the work channel is the scaled selection of the image refred by ref_drawable_id * * copying is done into an auxiliary channel from where we regulary load the selection. * this is done because subseqent queries of the selection boudaries will deliver * full channel size rectangle after a direct copy into the selection. */ gap_layer_copy_picked_channel (l_aux_channel_id /* dst_drawable_id*/ , 0 /* dst_channel_pick */ , work_drawable_id /* src_drawable_id */ , 0 /* src_channel_pick */ , FALSE /* gboolean shadow */ ); gimp_selection_load(l_aux_channel_id); gimp_image_remove_channel(image_id, l_aux_channel_id); gap_image_delete_immediate(dup_image_id); return (TRUE); } /* end gap_image_set_selection_from_selection_or_drawable */ gimp-gap-2.6.0+dfsg.orig/gap/gap_onion_worker.h0000644000175000017500000000354111212030253021232 0ustar thibautthibaut/* gap_onion_worker.h * 2003.05.22 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains ONION Skin Layers worker Procedures * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 1.3.14a; 2003/05/22 hof: integration into gimp-gap-1.3.14 * 1.3.12a; 2003/05/03 hof: started port to gimp-1.3 /gtk+2.2 * version 1.2.2a; 2001.12.10 hof: created */ #ifndef _GAP_ONION_WORKER_H #define _GAP_ONION_WORKER_H #include /* onion_worker procedures */ gint gap_onion_worker_set_data_onion_cfg(GapOnionMainGlobalParams *gpp, char *key); gint gap_onion_worker_get_data_onion_cfg(GapOnionMainGlobalParams *gpp); gint gap_onion_worker_onion_visibility(GapOnionMainGlobalParams *gpp, gint visi_mode); gint gap_onion_worker_onion_delete(GapOnionMainGlobalParams *gpp); gint gap_onion_worker_onion_apply(GapOnionMainGlobalParams *gpp, gboolean use_cache); gint gap_onion_worker_onion_range(GapOnionMainGlobalParams *gpp); void gap_onion_worker_plug_in_gap_get_animinfo(gint32 image_ID, GapOnionMainAinfo *ainfo); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_story_file.h0000644000175000017500000004751411212030253020706 0ustar thibautthibaut/* gap_story_file.h * * This module handles GAP storyboard file * parsing of storyboard level1 files (load informations into a list) * and (re)write storyboard files from the list (back to storyboard file) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 2.3.0; 2006/04/14 new features: overlap, flip, mask definitions * version 1.3.25b; 2004/01/23 hof: created */ #ifndef _GAP_STORY_FILE_H #define _GAP_STORY_FILE_H #include "libgimp/gimp.h" #include "gap_lib.h" #include "gap_story_syntax.h" #include "gap_story_render_types.h" /* transition attribute types * (values are used as index for look-up tables) */ #define GAP_STB_ATT_TYPES_ARRAY_MAX 5 #define GAP_STB_ATT_TYPE_OPACITY 0 #define GAP_STB_ATT_TYPE_MOVE_X 1 #define GAP_STB_ATT_TYPE_MOVE_Y 2 #define GAP_STB_ATT_TYPE_ZOOM_X 3 #define GAP_STB_ATT_TYPE_ZOOM_Y 4 #define GAP_STB_MASK_SECTION_NAME "Masks" #define GAP_STB_MAX_FRAMENR 99999999 /* GapStoryRecordType enum values are superset of GapLibAinfoType * from the sourcefile gap_lib.h */ typedef enum { GAP_STBREC_VID_SILENCE ,GAP_STBREC_VID_COLOR ,GAP_STBREC_VID_IMAGE ,GAP_STBREC_VID_ANIMIMAGE ,GAP_STBREC_VID_FRAMES ,GAP_STBREC_VID_MOVIE ,GAP_STBREC_VID_COMMENT ,GAP_STBREC_VID_UNKNOWN ,GAP_STBREC_AUD_SILENCE ,GAP_STBREC_AUD_SOUND ,GAP_STBREC_AUD_MOVIE ,GAP_STBREC_ATT_TRANSITION ,GAP_STBREC_VID_SECTION ,GAP_STBREC_VID_BLACKSECTION } GapStoryRecordType; typedef enum { GAP_STB_TARGET_URILIST, GAP_STB_TARGET_UTF8_STRING, GAP_STB_TARGET_STRING, GAP_STB_TARGET_TEXT, GAP_STB_TARGET_COMPOUND_TEXT, GAP_STB_TARGET_STORYBOARD_ELEM } GapStoryDndTargets; typedef enum { GAP_STB_PM_NORMAL ,GAP_STB_PM_PINGPONG } GapStoryVideoPlaymode; typedef enum { GAP_STB_MASTER_TYPE_UNDEFINED ,GAP_STB_MASTER_TYPE_STORYBOARD ,GAP_STB_MASTER_TYPE_CLIPLIST } GapStoryMasterType; /* The GapStoryElem is a common used structure for * all type of video clips, audio clips, video attributes * and mask definitions. * mask definitions are handled as video clips using the reserved track number * GAP_STB_MASK_TRACK_NUMBER. */ typedef struct GapStoryElem { gint32 story_id; gint32 story_orig_id; gboolean selected; GapStoryRecordType record_type; GapStoryVideoPlaymode playmode; gint32 track; char *orig_filename; /* full filename use for IMAGE and MOVIE Files * and SECTIONS (for section_name) */ char *orig_src_line; /* without \n, used to store header, comment and unknown lines */ /* basename + ext are used for FRAME range elements only */ gchar *basename; /* path+filename (without number part and without extension */ gchar *ext; /* extenson ".xcf" ".jpg" ... including the dot */ gint32 seltrack; /* selected videotrack in a videofile (for GAP_FRN_MOVIE) */ gint32 exact_seek; /* 0 fast seek, 1 exact seek (for GAP_FRN_MOVIE) */ gdouble delace; /* 0.0 no deinterlace, 1.0-1.99 odd 2.0-2.99 even rows (for GAP_FRN_MOVIE) */ gint32 flip_request; /* 0 none, 1 flip horizontal, 2 flip vertical, 3 flip both */ char *mask_name; /* optional reference to a layer mask * if track == GAP_STB_MASK_TRACK_NUMBER this atribute * is the mandatory definition of the mask_name. */ gdouble mask_stepsize; GapStoryMaskAnchormode mask_anchor; gboolean mask_disable; gchar *preferred_decoder; gchar *filtermacro_file; gint32 fmac_total_steps; gint32 from_frame; gint32 to_frame; gint32 nloop; /* 1 play one time */ gint32 nframes; /* if playmode == normal * then frames = nloop * (ABS(from_frame - to_frame) + 1); * else frames = (nloop * 2 * ABS(from_frame - to_frame)) + 1; */ gdouble step_density; /* 1.0 for normal stepsize * 2.0 use every 2.nd frame (double speed at same framerate) * 0.5 use each frame twice (half speed at same framerate) */ gint32 file_line_nr; /* line Number in the storyboard file */ /* members for level2 VID Record types */ gdouble vid_wait_untiltime_sec; gdouble color_red; gdouble color_green; gdouble color_blue; gdouble color_alpha; /* members for attribute Record types */ gboolean att_keep_proportions; gboolean att_fit_width; gboolean att_fit_height; /* members for transition attribute Record type */ gboolean att_arr_enable[GAP_STB_ATT_TYPES_ARRAY_MAX]; gdouble att_arr_value_from[GAP_STB_ATT_TYPES_ARRAY_MAX]; gdouble att_arr_value_to[GAP_STB_ATT_TYPES_ARRAY_MAX]; gint32 att_arr_value_dur[GAP_STB_ATT_TYPES_ARRAY_MAX]; /* number of frames to change from -> to value */ gint32 att_overlap; /* number of overlapping frames (value > 0 will generate a shadow track) */ /* new members for Audio Record types */ char *aud_filename; gint32 aud_seltrack; /* selected audiotrack in a videofile (for GAP_AUT_MOVIE) */ gdouble aud_wait_untiltime_sec; gdouble aud_play_from_sec; gdouble aud_play_to_sec; gdouble aud_volume_start; gdouble aud_volume; gdouble aud_volume_end; gdouble aud_fade_in_sec; gdouble aud_fade_out_sec; gdouble aud_min_play_sec; /* for optimzed audio extract from videofiles */ gdouble aud_max_play_sec; gdouble aud_framerate; /* framerate that is used to convert audio unit frame <-> secs */ struct GapStoryElem *comment; struct GapStoryElem *next; } GapStoryElem; typedef struct GapStorySection { GapStoryElem *stb_elem; gchar *section_name; /* null refers to the main section */ gint32 current_vtrack; gint32 section_id; /* unique ID, NOT persistent */ gint32 version; /* numer of changes while editing, NOT persistent */ void *next; } GapStorySection; typedef struct GapStoryEditSettings { gchar *section_name; /* null refers to the main section */ gint32 track; gint32 page; } GapStoryEditSettings; typedef struct GapStoryFrameNumberMappingElem { gint32 mapped_frame_number; gint32 orig_frame_number; struct GapStoryFrameNumberMappingElem *next; } GapStoryFrameNumberMappingElem; typedef struct GapStoryFrameNumberMap { gint32 total_frames_selected; GapStoryFrameNumberMappingElem *map_list; } GapStoryFrameNumberMap; typedef struct GapStoryBoard { GapStorySection *active_section; /* reference pointer to active section (dont free this) */ GapStorySection *mask_section; /* reference pointer to mask section (dont free this) */ GapStorySection *stb_section; /* root of section list */ gchar *storyboardfile; GapStoryMasterType master_type; gint32 master_width; gint32 master_height; gdouble master_framerate; gboolean master_vtrack1_is_toplayer; /* default = true; */ gdouble master_aspect_ratio; gint32 master_aspect_width; gint32 master_aspect_height; gint32 master_samplerate; gdouble master_volume; gint32 layout_cols; gint32 layout_rows; gint32 layout_thumbsize; gchar *preferred_decoder; /* for error handling while parsing */ gchar *errtext; gchar *errline; gint32 errline_nr; gchar *warntext; gchar *warnline; gint32 warnline_nr; gint32 curr_nr; gchar *currline; /* dont g_free this one ! */ gint32 count_unprintable_chars; /* for composite vide playback */ gint32 stb_parttype; gint32 stb_unique_id; /* selection mapping is not relevant for rendering * but is used at playback of composite video * where frame ranges of the selected clips * are represented by a mapping * and the player only picks frame numbers via mapping */ GapStoryFrameNumberMap *mapping; gboolean unsaved_changes; GapStoryEditSettings *edit_settings; gchar *master_insert_area_format; } GapStoryBoard; typedef struct GapStoryLocateRet { GapStoryElem *stb_elem; gint32 ret_framenr; gboolean locate_ok; } GapStoryLocateRet; typedef struct GapStoryCalcAttr { gint32 width; gint32 height; gint32 x_offs; gint32 y_offs; gdouble opacity; } GapStoryCalcAttr; typedef struct GapStoryVideoFileRef { gchar *videofile; /* full filename */ gchar *userdata; gchar *preferred_decoder; gint32 seltrack; gint32 max_ref_framenr; void *next; } GapStoryVideoFileRef; void gap_story_debug_print_list(GapStoryBoard *stb); void gap_story_debug_print_elem(GapStoryElem *stb_elem); GapStoryBoard * gap_story_new_story_board(const char *filename); GapStoryBoard * gap_story_parse(const gchar *filename); void gap_story_elem_calculate_nframes(GapStoryElem *stb_elem); GapStoryLocateRet * gap_story_locate_framenr(GapStoryBoard *stb , gint32 in_framenr , gint32 in_track); GapStoryLocateRet * gap_story_locate_expanded_framenr(GapStorySection *section , gint32 in_framenr , gint32 in_track); void gap_story_lists_merge(GapStoryBoard *stb_dst , GapStoryBoard *stb_src , gint32 story_id , gboolean insert_after , gint32 dst_vtrack); gint32 gap_story_find_last_selected_in_track(GapStorySection *section, gint32 track_nr); GapStoryElem * gap_story_elem_find_by_story_id(GapStoryBoard *stb, gint32 story_id); GapStoryElem * gap_story_elem_find_by_story_orig_id(GapStoryBoard *stb, gint32 story_orig_id); gboolean gap_story_save(GapStoryBoard *stb, const char *filename); GapStoryElem * gap_story_new_elem(GapStoryRecordType record_type); long gap_story_upd_elem_from_filename(GapStoryElem *stb_elem, const char *filename); gboolean gap_story_filename_is_videofile_by_ext(const char *filename); gboolean gap_story_filename_is_videofile(const char *filename); void gap_story_elem_free(GapStoryElem **stb_elem); void gap_story_free_stb_section(GapStorySection *stb_section); void gap_story_free_selection_mapping(GapStoryFrameNumberMap *mapping); void gap_story_free_storyboard(GapStoryBoard **stb_ptr); GapStoryElem * gap_story_new_mask_elem(GapStoryRecordType record_type); GapStorySection * gap_story_new_section(); GapStorySection * gap_story_find_first_referable_subsection(GapStoryBoard *stb_dst); GapStoryElem * gap_story_elem_find_in_section_by_story_id(GapStorySection *section, gint32 story_id); GapStorySection * gap_story_find_section_by_story_id(GapStoryBoard *stb, gint32 story_id); GapStorySection * gap_story_find_section_by_stb_elem(GapStoryBoard *stb, GapStoryElem *stb_elem); GapStorySection * gap_story_find_section_by_name(GapStoryBoard *stb, const char *section_name); GapStorySection * gap_story_find_main_section(GapStoryBoard *stb); GapStorySection * gap_story_create_or_find_section_by_name(GapStoryBoard *stb, const char *section_name); gboolean gap_story_remove_section(GapStoryBoard *stb, GapStorySection *del_section); gchar * gap_story_generate_new_unique_section_name(GapStoryBoard *stb); void gap_story_list_append_elem(GapStoryBoard *stb, GapStoryElem *stb_elem); void gap_story_list_append_elem_at_section(GapStoryBoard *stb , GapStoryElem *stb_elem , GapStorySection *active_section); gint32 gap_story_count_total_frames_in_section(GapStorySection *section); gint32 gap_story_get_framenr_by_story_id(GapStorySection *section, gint32 story_id, gint32 in_track); gint32 gap_story_get_expanded_framenr_by_story_id(GapStorySection *section, gint32 story_id, gint32 in_track); char * gap_story_get_filename_from_elem(GapStoryElem *stb_elem); char * gap_story_get_filename_from_elem_nr(GapStoryElem *stb_elem, gint32 in_framenr); GapStoryElem * gap_story_fetch_nth_active_elem(GapStoryBoard *stb , gint32 seq_nr , gint32 in_track ); GapAnimInfo * gap_story_fake_ainfo_from_stb(GapStoryBoard *stb_ptr, gint32 in_track); GapStoryElem * gap_story_elem_duplicate(GapStoryElem *stb_elem); void gap_story_elem_copy(GapStoryElem *stb_elem_dst, GapStoryElem *stb_elem_src); GapStoryElem * gap_story_find_mask_definition_by_name(GapStoryBoard *stb_ptr, const char *mask_name); GapStoryElem * gap_story_find_mask_reference_by_name(GapStoryBoard *stb_ptr, const char *mask_name); void gap_story_enable_hidden_maskdefinitions(GapStoryBoard *stb_ptr); GapStoryBoard * gap_story_duplicate_full(GapStoryBoard *stb_ptr); GapStoryBoard * gap_story_duplicate_active_and_mask_section(GapStoryBoard *stb_ptr); GapStoryBoard * gap_story_duplicate_vtrack(GapStoryBoard *stb_ptr, gint32 in_vtrack); GapStoryBoard * gap_story_duplicate_sel_only(GapStoryBoard *stb_ptr, gint32 in_vtrack); GapStoryBoard * gap_story_duplicate_one_elem_and_masks(GapStoryBoard *stb_ptr , GapStorySection *active_section, gint32 story_id); GapStoryBoard * gap_story_duplicate_one_elem(GapStoryBoard *stb_ptr , GapStorySection *active_section, gint32 story_id); GapStoryBoard * gap_story_board_duplicate_distinct_sorted(GapStoryBoard *stb_dup, GapStoryBoard *stb_ptr); void gap_story_copy_sub_sections(GapStoryBoard *stb_src, GapStoryBoard *stb_dst); void gap_story_set_properties_like_sample_storyboard (GapStoryBoard *stb , GapStoryBoard *stb_sample); void gap_story_remove_sel_elems(GapStoryBoard *stb); gint32 gap_story_count_active_elements(GapStoryBoard *stb_ptr, gint32 in_track); void gap_story_get_master_pixelsize(GapStoryBoard *stb_ptr ,gint32 *width ,gint32 *height); gdouble gap_story_get_master_size_respecting_aspect(GapStoryBoard *stb_ptr ,gint32 *width ,gint32 *height); gdouble gap_story_adjust_size_respecting_aspect(GapStoryBoard *stb_ptr ,gint32 *width ,gint32 *height); void gap_story_selection_all_set(GapStoryBoard *stb, gboolean sel_state); void gap_story_selection_by_story_id(GapStoryBoard *stb, gboolean sel_state, gint32 story_id); void gap_story_selection_from_ref_list_orig_ids(GapStoryBoard *stb, gboolean sel_state, GapStoryBoard *stb_ref); const char * gap_story_get_preferred_decoder(GapStoryBoard *stb, GapStoryElem *stb_elem); void gap_story_set_aud_movie_min_max(GapStoryBoard *stb); gboolean gap_story_elem_is_audio(GapStoryElem *stb_elem); gboolean gap_story_elem_is_video(GapStoryElem *stb_elem); gboolean gap_story_elem_is_video_relevant(GapStoryElem *stb_elem); gboolean gap_story_elem_is_same_resource(GapStoryElem *stb_elem, GapStoryElem *stb_elem_ref); GapStoryElem * gap_story_elem_find_by_same_resource(GapStoryBoard *stb_ptr, GapStoryElem *stb_elem_ref); void gap_story_del_audio_track(GapStoryBoard *stb, gint aud_track); gboolean gap_story_gen_otone_audio(GapStoryBoard *stb ,gint vid_track ,gint aud_track ,gint aud_seltrack ,gboolean replace_existing_aud_track ,gdouble *first_non_matching_framerate ); gdouble gap_story_get_default_attribute(gint att_typ_idx); void gap_story_file_calculate_render_attributes(GapStoryCalcAttr *result_attr , gint32 view_vid_width , gint32 view_vid_height , gint32 vid_width , gint32 vid_height , gint32 frame_width , gint32 frame_height , gboolean keep_proportions , gboolean fit_width , gboolean fit_height , gdouble opacity , gdouble scale_x , gdouble scale_y , gdouble move_x , gdouble move_y ); gboolean gap_story_update_mask_name_references(GapStoryBoard *stb_ptr , const char *mask_name_new , const char *mask_name_old ); char * gap_story_generate_unique_maskname(GapStoryBoard *stb_ptr); GapStoryElem * gap_story_find_maskdef_equal_to_ref_elem(GapStoryBoard *stb_ptr, GapStoryElem *stb_ref_elem); gint32 gap_story_get_current_vtrack (GapStoryBoard *stb, GapStorySection *section); void gap_story_set_current_vtrack (GapStoryBoard *stb, GapStorySection *section , gint32 current_vtrack); gint32 gap_story_get_mapped_master_frame_number(GapStoryFrameNumberMap *mapping , gint32 frame_number); GapStoryFrameNumberMap * gap_story_create_new_mapping_from_selection(GapStorySection *active_section , gint32 vtrack); GapStoryFrameNumberMap * gap_story_create_new_mapping_by_story_id(GapStorySection *active_section , gint32 vtrack, gint32 story_id); void gap_story_debug_print_mapping(GapStoryFrameNumberMap *mapping); void gap_story_free_GapStoryVideoFileRef(GapStoryVideoFileRef *vref_list); GapStoryVideoFileRef * p_new_GapStoryVideoFileRef(const char *videofile , gint32 seltrack , const char *preferred_decoder , gint32 max_ref_framenr); GapStoryVideoFileRef * gap_story_get_video_file_ref_list(GapStoryBoard *stb); char * gap_story_build_basename(const char *filename); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_mov_render.c0000644000175000017500000007033211212030253020654 0ustar thibautthibaut/* gap_mov_render.c * 1997.11.06 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * Render utility Procedures for GAP MovePath * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 1.3.21b; 2003/09/22 hof: bugfix in selection handling * gimp 1.3.20d; 2003/09/14 hof: new: added bluebox stuff * gimp 1.3.20c; 2003/09/28 hof: new features: perspective transformation, tween_layer and trace_layer * changed opacity, rotation and resize from int to gdouble * gimp 1.3.20a; 2003/09/14 hof: fixed compiler warnings * gimp 1.3.14a; 2003/05/24 hof: created (splitted off from gap_mov_dialog) */ #include "config.h" /* SYTEM (UNIX) includes */ #include #include #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "gap-intl.h" #include "libgimp/gimp.h" #include "libgimp/gimpui.h" /* GAP includes */ #include "gap_layer_copy.h" #include "gap_lib.h" #include "gap_image.h" #include "gap_mov_exec.h" #include "gap_mov_dialog.h" #include "gap_mov_render.h" #include "gap_pdb_calls.h" #include "gap_vin.h" #include "gap_arr_dialog.h" extern int gap_debug; /* ==0 ... dont print debug infos */ static void p_mov_selection_handling(gint32 orig_layer_id , gint src_offset_x , gint src_offset_y , GapMovValues *val_ptr , GapMovCurrent *cur_ptr ); static void p_mov_apply_bluebox(gint32 layer_id , GapMovValues *val_ptr , GapMovCurrent *cur_ptr ); static void p_mov_transform_perspective(gint32 layer_id , GapMovValues *val_ptr , GapMovCurrent *cur_ptr , gint *resized_flag , guint *new_width , guint *new_height ); #define BOUNDS(a,x,y) ((a < x) ? x : ((a > y) ? y : a)) /* ------------------------- * p_get_paintmode * ------------------------- * */ static GimpLayerModeEffects p_get_paintmode(int mode, gint32 src_layer_id) { if(mode == GAP_MOV_KEEP_SRC_PAINTMODE) { GimpLayerModeEffects l_mode; l_mode = gimp_layer_get_mode(src_layer_id); return (l_mode); } return (GimpLayerModeEffects)mode; } /* end p_get_paintmode */ /* ============================================================================ * p_mov_selection_handling * Conditions: * a copy of the selection in the initial source_image (or the actual source_frame) * is available in tmpsel_channel_id * this channel is part of the val_ptr->tmpsel_image_id image. * the val_ptr->tmpsel_image_id image has the same size as the source image. * This procedure adds a dummy layer to the val_ptr->tmpsel_image, * copies the alpha channel from the passed orig_layer_id to the dummy layer * applies the selection to the dummy layer * and then replaces the alpha channel of the orig_layer_id by the alpha channel of the dummy * ============================================================================ */ static void p_mov_selection_handling(gint32 orig_layer_id , gint src_offset_x , gint src_offset_y , GapMovValues *val_ptr , GapMovCurrent *cur_ptr ) { gint l_bpp; gint l_width; gint l_height; gint32 l_tmp_layer_id; static gint32 display_id = -1; if(val_ptr->tmpsel_image_id < 0) { return; } if(!gimp_drawable_has_alpha(orig_layer_id)) { gimp_layer_add_alpha(orig_layer_id); } l_width = gimp_drawable_width(orig_layer_id); l_height = gimp_drawable_height(orig_layer_id); l_bpp = gimp_drawable_bpp(orig_layer_id); l_tmp_layer_id = gimp_layer_new(val_ptr->tmpsel_image_id, "dummy", l_width, l_height, GIMP_RGBA_IMAGE, 100.0, /* full opaque */ GIMP_NORMAL_MODE); gimp_image_add_layer(val_ptr->tmpsel_image_id, l_tmp_layer_id, 0); gimp_layer_set_offsets(l_tmp_layer_id, src_offset_x, src_offset_y); gimp_selection_none(val_ptr->tmpsel_image_id); gap_layer_copy_picked_channel(l_tmp_layer_id, 3 /* dst_pick is the alpha channel */ ,orig_layer_id, (l_bpp -1) ,FALSE /* shadow */ ); gimp_selection_load(val_ptr->tmpsel_channel_id); if(cur_ptr->currSelFeatherRadius > 0.001) { gimp_selection_feather(val_ptr->tmpsel_image_id, cur_ptr->currSelFeatherRadius); } gimp_selection_invert(val_ptr->tmpsel_image_id); if(!gimp_selection_is_empty(val_ptr->tmpsel_image_id)) { /* clear invers selected pixels to set unselected pixels transparent * (merge selection into alpha channel of l_tmp_layer_id) * We do not CLEAR on empty selection (== everything was selected originally), * because this would clear the alpha channels for all pixels. * But in that case we want all pixels to keep the origial alpha channel */ gimp_edit_clear(l_tmp_layer_id); /* copy alpha channel form dummy back to original */ gap_layer_copy_picked_channel(orig_layer_id, (l_bpp -1) ,l_tmp_layer_id, 3 /* dst_pick is the alpha channel */ ,FALSE /* shadow */ ); } /* DEBUG code: show the tmpsel_image */ if(1==0) { if(display_id < 0) { gimp_display_new(val_ptr->tmpsel_image_id); } return; } /* delete dummy layer */ gimp_image_remove_layer(val_ptr->tmpsel_image_id, l_tmp_layer_id); } /* end p_mov_selection_handling */ /* ============================================================================ * p_mov_apply_bluebox * perform perspective transformations on the passed layer * ============================================================================ */ static void p_mov_apply_bluebox(gint32 layer_id , GapMovValues *val_ptr , GapMovCurrent *cur_ptr ) { if(val_ptr->bbp == NULL) { /* blubox parameters are not provided by the caller. * in this case we init with default values and try to fetch * values from previous bluebox filter runs */ val_ptr->bbp = gap_bluebox_bbp_new(layer_id);; } if(val_ptr->bbp) { val_ptr->bbp->image_id = gimp_drawable_get_image(layer_id); val_ptr->bbp->drawable_id = layer_id; val_ptr->bbp->layer_id = layer_id; val_ptr->bbp->run_mode = GIMP_RUN_NONINTERACTIVE; val_ptr->bbp->run_flag = TRUE; gap_bluebox_apply(val_ptr->bbp); } } /* end p_mov_apply_bluebox */ /* ============================================================================ * p_mov_transform_perspective * perform perspective transformations on the passed layer * ============================================================================ */ static void p_mov_transform_perspective(gint32 layer_id , GapMovValues *val_ptr , GapMovCurrent *cur_ptr , gint *resized_flag , guint *new_width , guint *new_height ) { gdouble width; gdouble height; gdouble w2; gdouble h2; gdouble neww; gdouble newh; gdouble x0; gdouble y0; gdouble x1; gdouble y1; gdouble x2; gdouble y2; gdouble x3; gdouble y3; if( (cur_ptr->currTTLX == 1.0) && (cur_ptr->currTTLY == 1.0) && (cur_ptr->currTTRX == 1.0) && (cur_ptr->currTTRY == 1.0) && (cur_ptr->currTBLX == 1.0) && (cur_ptr->currTBLY == 1.0) && (cur_ptr->currTBRX == 1.0) && (cur_ptr->currTBRY == 1.0)) { /* all 4 corner points unchanged, no perspective call needed */ return; } width = gimp_drawable_width(layer_id); height = gimp_drawable_height(layer_id); w2 = width / 2.0; h2 = height / 2.0; /* apply transform factors curT### to all 4 corners */ x0 = w2 - (cur_ptr->currTTLX * w2); y0 = h2 - (cur_ptr->currTTLY * h2); x1 = w2 + (cur_ptr->currTTRX * w2); y1 = h2 - (cur_ptr->currTTRY * h2); x2 = w2 - (cur_ptr->currTBLX * w2); y2 = h2 + (cur_ptr->currTBLY * h2); x3 = w2 + (cur_ptr->currTBRX * w2); y3 = h2 + (cur_ptr->currTBRY * h2); neww = MAX((x1 - x0), (x3 - x2)); newh = MAX((y2 - y0), (y3 - y1)); if(gap_debug) { printf("** p_mov_transform_perspective:\n"); printf(" Factors: [0] %.3f %.3f [1] %.3f %.3f [2] %.3f %.3f [3] %.3f %.3f\n" ,(float)cur_ptr->currTTLX ,(float)cur_ptr->currTTLY ,(float)cur_ptr->currTTRX ,(float)cur_ptr->currTTRY ,(float)cur_ptr->currTBLX ,(float)cur_ptr->currTBLY ,(float)cur_ptr->currTBRX ,(float)cur_ptr->currTBRY ); printf(" width: %.3f height: %.3f\n" ,(float)width ,(float)height ); printf(" x0: %4.3f y0: %4.3f x1: %4.3f y1: %4.3f\n" ,(float)x0 ,(float)y0 ,(float)x1 ,(float)y1 ); printf(" x2: %4.3f y2: %4.3f x3: %4.3f y3: %4.3f\n\n" ,(float)x2 ,(float)y2 ,(float)x3 ,(float)y3 ); printf(" neww: %.3f newh: %.3f\n" ,(float)neww ,(float)newh ); } gimp_drawable_transform_perspective_default (layer_id, x0, y0, x1, y1, x2, y2, x3, y3, TRUE, /* whether to use interpolation and supersampling for good quality */ FALSE /* whether to clip results */ ); *resized_flag = 1; *new_width = neww; *new_height = newh; } /* end p_mov_transform_perspective */ /* ============================================================================ * gap_mov_render_render * insert current source layer into image * at current settings (position, size opacity ...) * ============================================================================ */ gint gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur_ptr) { gint32 l_cp_layer_id; gint32 l_cp_layer_mask_id; gint l_offset_x, l_offset_y; /* new offsets within dest. image */ gint l_src_offset_x, l_src_offset_y; /* layeroffsets as they were in src_image */ guint l_new_width; guint l_new_height; guint l_orig_width; guint l_orig_height; gint l_resized_flag; gint lx1, ly1, lx2, ly2; guint l_image_width; guint l_image_height; GimpLayerModeEffects l_mode; if(gap_debug) printf("gap_mov_render_render: frame/layer: %ld/%ld X=%f, Y=%f\n" " Width=%f Height=%f\n" " Opacity=%f Rotate=%f clip_to_img = %d force_visibility = %d\n" " src_stepmode = %d\n", cur_ptr->dst_frame_nr, cur_ptr->src_layer_idx, cur_ptr->currX, cur_ptr->currY, cur_ptr->currWidth, cur_ptr->currHeight, cur_ptr->currOpacity, cur_ptr->currRotation, val_ptr->clip_to_img, val_ptr->src_force_visible, val_ptr->src_stepmode); if(val_ptr->src_stepmode < GAP_STEP_FRAME) { if(gap_debug) { printf("gap_mov_render_render: Before gap_layer_copy_to_dest_image image_id:%d src_layer_id:%d\n" ,(int)image_id, (int)cur_ptr->src_layers[cur_ptr->src_layer_idx]); } l_mode = p_get_paintmode(val_ptr->src_paintmode ,cur_ptr->src_layers[cur_ptr->src_layer_idx] ); /* make a copy of the current source layer * (using current opacity & paintmode values) */ l_cp_layer_id = gap_layer_copy_to_dest_image(image_id, cur_ptr->src_layers[cur_ptr->src_layer_idx], cur_ptr->currOpacity, l_mode, &l_src_offset_x, &l_src_offset_y); } else { if(gap_debug) { printf("gap_mov_render_render: Before gap_layer_copy_to_dest_image image_id:%d cache_tmp_layer_id:%d\n" ,(int)image_id, (int)val_ptr->cache_tmp_layer_id); } l_mode = p_get_paintmode(val_ptr->src_paintmode ,val_ptr->cache_tmp_layer_id ); /* for FRAME based stepmodes use the flattened layer in the cahed frame image */ l_cp_layer_id = gap_layer_copy_to_dest_image(image_id, val_ptr->cache_tmp_layer_id, cur_ptr->currOpacity, l_mode, &l_src_offset_x, &l_src_offset_y); } /* add the copied layer to current destination image */ if(gap_debug) printf("gap_mov_render_render: after layer copy layer_id=%d\n", (int)l_cp_layer_id); if(l_cp_layer_id < 0) { return -1; } gimp_image_add_layer(image_id, l_cp_layer_id, val_ptr->dst_layerstack); if(gap_debug) printf("gap_mov_render_render: after add layer\n"); if(val_ptr->src_force_visible) { gimp_drawable_set_visible(l_cp_layer_id, TRUE); } /* check for layermask */ l_cp_layer_mask_id = gimp_layer_get_mask(l_cp_layer_id); if(l_cp_layer_mask_id >= 0) { /* apply the layermask * some transitions (especially rotate) can't operate proper on * layers with masks ! * (tests with gimp_rotate resulted in trashed images, * even if the mask was rotated too) */ gimp_layer_remove_mask (l_cp_layer_id, GIMP_MASK_APPLY); } /* remove selection (if there is one) * if there is a selection transitions (gimp_rotate) * will create new layer and do not operate on l_cp_layer_id */ gimp_selection_none(image_id); l_resized_flag = 0; l_orig_width = gimp_drawable_width(l_cp_layer_id); l_orig_height = gimp_drawable_height(l_cp_layer_id); l_new_width = l_orig_width; l_new_height = l_orig_height; if(val_ptr->src_apply_bluebox) { p_mov_apply_bluebox (l_cp_layer_id, val_ptr, cur_ptr); } if(val_ptr->src_selmode != GAP_MOV_SEL_IGNORE) { p_mov_selection_handling (l_cp_layer_id , l_src_offset_x , l_src_offset_y , val_ptr , cur_ptr ); } if((cur_ptr->currWidth * cur_ptr->currHeight) > (100.0 * 100.0)) { /* have to scale layer (enlarge) */ l_resized_flag = 1; l_new_width = (l_orig_width * cur_ptr->currWidth) / 100; l_new_height = (l_orig_height * cur_ptr->currHeight) / 100; gimp_layer_scale(l_cp_layer_id, l_new_width, l_new_height, 0); /* do 4-point perspective stuff (after enlarge) */ p_mov_transform_perspective(l_cp_layer_id , val_ptr , cur_ptr , &l_resized_flag , &l_new_width , &l_new_height ); } else { /* do 4-point perspective stuff (before shrink layer) */ p_mov_transform_perspective(l_cp_layer_id , val_ptr , cur_ptr , &l_resized_flag , &l_new_width , &l_new_height ); if((cur_ptr->currWidth > 100.01) || (cur_ptr->currWidth < 99.99) || (cur_ptr->currHeight > 100.01) || (cur_ptr->currHeight < 99.99)) { /* have to scale layer */ l_resized_flag = 1; l_new_width = (l_new_width * cur_ptr->currWidth) / 100; l_new_height = (l_new_height * cur_ptr->currHeight) / 100; gimp_layer_scale(l_cp_layer_id, l_new_width, l_new_height, 0); } } if((cur_ptr->currRotation > 0.5) || (cur_ptr->currRotation < -0.5)) { gboolean l_interpolation; l_resized_flag = 1; l_interpolation = TRUE; /* use the default interpolation (as configured in prefs) */ /* have to rotate the layer (rotation also changes size as needed) */ gap_pdb_gimp_rotate_degree(l_cp_layer_id, l_interpolation, cur_ptr->currRotation); l_new_width = gimp_drawable_width(l_cp_layer_id); l_new_height = gimp_drawable_height(l_cp_layer_id); } if(l_resized_flag == 1) { /* adjust offsets according to handle and change of size */ switch(val_ptr->src_handle) { case GAP_HANDLE_LEFT_BOT: l_src_offset_y += ((gint)l_orig_height - (gint)l_new_height); break; case GAP_HANDLE_RIGHT_TOP: l_src_offset_x += ((gint)l_orig_width - (gint)l_new_width); break; case GAP_HANDLE_RIGHT_BOT: l_src_offset_x += ((gint)l_orig_width - (gint)l_new_width); l_src_offset_y += ((gint)l_orig_height - (gint)l_new_height); break; case GAP_HANDLE_CENTER: l_src_offset_x += (((gint)l_orig_width - (gint)l_new_width) / 2); l_src_offset_y += (((gint)l_orig_height - (gint)l_new_height) / 2); break; case GAP_HANDLE_LEFT_TOP: default: break; } } /* calculate offsets in destination image */ l_offset_x = (cur_ptr->currX - cur_ptr->l_handleX) + l_src_offset_x; l_offset_y = (cur_ptr->currY - cur_ptr->l_handleY) + l_src_offset_y; /* modify coordinate offsets of the copied layer within dest. image */ gimp_layer_set_offsets(l_cp_layer_id, l_offset_x, l_offset_y); /* clip the handled layer to image size if desired */ if(val_ptr->clip_to_img != 0) { l_image_width = gimp_image_width(image_id); l_image_height = gimp_image_height(image_id); lx1 = BOUNDS (l_offset_x, 0, (gint32)l_image_width); ly1 = BOUNDS (l_offset_y, 0, (gint32)l_image_height); lx2 = BOUNDS ((gint32)(l_new_width + l_offset_x), 0, (gint32)l_image_width); ly2 = BOUNDS ((gint32)(l_new_height + l_offset_y), 0, (gint32)l_image_height); l_new_width = lx2 - lx1; l_new_height = ly2 - ly1; if (l_new_width && l_new_height) { gimp_layer_resize(l_cp_layer_id, l_new_width, l_new_height, -(lx1 - l_offset_x), -(ly1 - l_offset_y)); } else { /* no part of the layer is inside of the current frame (this image) * instead of removing we make the layer small and move him outside * the image. * (that helps to keep the layerstack position of the inserted layer(s) * constant in all handled video frames) */ gimp_layer_resize(l_cp_layer_id, 2, 2, -3, -3); } } /* if tracing is ON, copy the actually rendered object to the trace_image */ if(val_ptr->trace_image_id >= 0) { gint32 l_trc_layer_id; GimpMergeType l_mergemode; gdouble l_opacity_initial; l_mergemode = GIMP_EXPAND_AS_NECESSARY; if(val_ptr->clip_to_img) { l_mergemode = GIMP_CLIP_TO_IMAGE; } /* apply descending opacity for all previous added objects * (that are all collected in the val_ptr->trace_layer_id, that is the only layer in * the trace_image) */ gimp_layer_set_opacity(val_ptr->trace_layer_id, val_ptr->trace_opacity_desc); l_opacity_initial = (val_ptr->trace_opacity_initial * cur_ptr->currOpacity) / 100.0; l_opacity_initial = CLAMP(l_opacity_initial, 0.0, 100.0); l_trc_layer_id = gap_layer_copy_to_dest_image(val_ptr->trace_image_id, /* the dest image */ l_cp_layer_id, /* the layer to copy */ l_opacity_initial, 0, /* NORMAL paintmode */ &l_src_offset_x, &l_src_offset_y); gimp_image_add_layer(val_ptr->trace_image_id, l_trc_layer_id, 0); /* merge the newly added l_trc_layer_id down to one tracelayer again */ val_ptr->trace_layer_id = gap_image_merge_visible_layers(val_ptr->trace_image_id, l_mergemode); } if(gap_debug) printf("GAP gap_mov_render_render: exit OK\n"); return 0; } /* end gap_mov_render_render */ /* ============================================================================ * gap_mov_render_fetch_src_frame * fetch the requested video frame SourceImage into cache_tmp_image_id * and * - reduce all visible layer to one layer (cache_tmp_layer_id) * - (scale to animated preview size if called for AnimPreview ) * - reuse cached image (for subsequent calls for the same framenumber * of the same source image -- for GAP_STEP_FRAME_NONE * - never load current frame number from diskfile (use duplicate of the src_image) * returns 0 (OK) or -1 (on Errors) * ============================================================================ */ gint gap_mov_render_fetch_src_frame(GapMovValues *pvals, gint32 wanted_frame_nr) { GapAnimInfo *l_ainfo_ptr; GapAnimInfo *l_old_ainfo_ptr; if(gap_debug) { printf("gap_mov_render_fetch_src_frame: START src_image_id: %d wanted_frame_nr:%d" " cache_src_image_id:%d cache_frame_number:%d\n" , (int)pvals->src_image_id , (int)wanted_frame_nr , (int)pvals->cache_src_image_id , (int)pvals->cache_frame_number ); } if(pvals->src_image_id < 0) { return -1; } if((pvals->src_image_id != pvals->cache_src_image_id) || (wanted_frame_nr != pvals->cache_frame_number)) { if(pvals->cache_tmp_image_id >= 0) { if(gap_debug) { printf("gap_mov_render_fetch_src_frame: DELETE cache_tmp_image_id:%d\n", (int)pvals->cache_tmp_image_id); } /* destroy the cached frame image */ gimp_image_delete(pvals->cache_tmp_image_id); pvals->cache_tmp_image_id = -1; } l_ainfo_ptr = gap_lib_alloc_ainfo(pvals->src_image_id, GIMP_RUN_NONINTERACTIVE); if(pvals->cache_ainfo_ptr == NULL) { pvals->cache_ainfo_ptr = l_ainfo_ptr; } else { if ((pvals->src_image_id == pvals->cache_src_image_id) && (strcmp(pvals->cache_ainfo_ptr->basename, l_ainfo_ptr->basename) == 0)) { pvals->cache_ainfo_ptr->curr_frame_nr = l_ainfo_ptr->curr_frame_nr; gap_lib_free_ainfo(&l_ainfo_ptr); } else { /* update cached ainfo if source image has changed * (either by id or by its basename) */ l_old_ainfo_ptr = pvals->cache_ainfo_ptr; pvals->cache_ainfo_ptr = l_ainfo_ptr; gap_lib_free_ainfo(&l_old_ainfo_ptr); } } if ((wanted_frame_nr == pvals->cache_ainfo_ptr->curr_frame_nr) || (wanted_frame_nr < 0)) { /* always take the current source frame from the already opened image * not only for speedup reasons. (the diskfile may contain non actual imagedata) */ pvals->cache_tmp_image_id = gimp_image_duplicate(pvals->src_image_id); wanted_frame_nr = pvals->cache_ainfo_ptr->curr_frame_nr; } else { /* build the source framename */ if(pvals->cache_ainfo_ptr->new_filename != NULL) { g_free(pvals->cache_ainfo_ptr->new_filename); } pvals->cache_ainfo_ptr->new_filename = gap_lib_alloc_fname(pvals->cache_ainfo_ptr->basename, wanted_frame_nr, pvals->cache_ainfo_ptr->extension); if(pvals->cache_ainfo_ptr->new_filename == NULL) { printf("gap: error got no source frame filename\n"); return -1; } /* load the wanted source frame */ pvals->cache_tmp_image_id = gap_lib_load_image(pvals->cache_ainfo_ptr->new_filename); if(pvals->cache_tmp_image_id < 0) { printf("gap: load error on src image %s\n", pvals->cache_ainfo_ptr->new_filename); return -1; } } gimp_image_undo_disable (pvals->cache_tmp_image_id); pvals->cache_tmp_layer_id = gap_image_merge_visible_layers(pvals->cache_tmp_image_id, GIMP_EXPAND_AS_NECESSARY); /* check if we are generating an anim preview * where we must Scale (down) the src image to preview size */ if ((pvals->apv_mlayer_image >= 0) && ((pvals->apv_scalex != 100.0) || (pvals->apv_scaley != 100.0))) { gint32 l_size_x, l_size_y; if(gap_debug) { printf("gap_mov_render_fetch_src_frame: Scale for Animpreview apv_scalex %f apv_scaley %f\n" , (float)pvals->apv_scalex, (float)pvals->apv_scaley ); } l_size_x = (gimp_image_width(pvals->cache_tmp_image_id) * pvals->apv_scalex) / 100; l_size_y = (gimp_image_height(pvals->cache_tmp_image_id) * pvals->apv_scaley) / 100; gimp_image_scale(pvals->cache_tmp_image_id, l_size_x, l_size_y); } if(pvals->src_selmode != GAP_MOV_SEL_IGNORE) { if((pvals->tmpsel_channel_id < 0) || (pvals->src_selmode == GAP_MOV_SEL_FRAME_SPECIFIC)) { gint32 l_sel_channel_id; gboolean l_all_empty; l_all_empty = FALSE; /* pick the selection for the 1.st handled frame * or foreach handled frame when mode is GAP_MOV_SEL_FRAME_SPECIFIC */ if(gimp_selection_is_empty(pvals->cache_tmp_image_id)) { l_all_empty = TRUE; } l_sel_channel_id = gimp_image_get_selection(pvals->cache_tmp_image_id); gap_mov_render_create_or_replace_tempsel_image(l_sel_channel_id, pvals, l_all_empty); } } pvals->cache_src_image_id = pvals->src_image_id; pvals->cache_frame_number = wanted_frame_nr; } return 0; /* OK */ } /* end gap_mov_render_fetch_src_frame */ /* ============================================================================ * gap_mov_render_create_or_replace_tempsel_image * create or replace a temp image to store the selection * of the initial source image (or frame) * the all_empty parameter == TRUE indicates, that the channel_id * represents an empty selection. * in this case tmpsel_channel_id is set to everything selected * ============================================================================ */ void gap_mov_render_create_or_replace_tempsel_image(gint32 channel_id , GapMovValues *val_ptr , gboolean all_empty ) { if(val_ptr->tmpsel_image_id >= 0) { gimp_image_delete(val_ptr->tmpsel_image_id); } val_ptr->tmpsel_image_id = gimp_image_new(gimp_drawable_width(channel_id) ,gimp_drawable_height(channel_id) ,GIMP_RGB ); gimp_selection_all(val_ptr->tmpsel_image_id); val_ptr->tmpsel_channel_id = gimp_selection_save(val_ptr->tmpsel_image_id); if(!all_empty) { gap_layer_copy_content(val_ptr->tmpsel_channel_id /* dst */ ,channel_id /* src */ ); } } /* end gap_mov_render_create_or_replace_tempsel_image */ gimp-gap-2.6.0+dfsg.orig/gap/gap_story_sox.h0000644000175000017500000000253011212030253020565 0ustar thibautthibaut/* gap_story_sox.h * Headers for Audio resampling Modules */ /* * Copyright * * 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_STORY_SOX_H #define GAP_STORY_SOX_H #include /* GIMP includes */ #include "gtk/gtk.h" #include "gap-intl.h" #include "libgimp/gimp.h" #define GAP_STORY_SOX_DEFAULT_UTIL_SOX "sox" #define GAP_STORY_SOX_DEFAULT_UTIL_SOX_OPTIONS " \"$IN\" -t wav \"$OUT\" rate -h $RATE " void gap_story_sox_exec_resample(char *in_audiofile ,char *out_audiofile ,gint32 samplerate ,char *util_sox ,char *util_sox_options ); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_mod_layer_dialog.c0000644000175000017500000013736111212030253022014 0ustar thibautthibaut/* gap_mod_layer_dialog.c * 2004.11.11 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * modify Layer(s) in frames dialog * (perform actions (like raise, set visible, apply filter) * - foreach selected layer * - in each frame of the selected framerange) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 2.1.00 2004.11.01 hof: - created module */ /* SYTEM (UNIX) includes */ #include #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "config.h" #include "libgimp/gimp.h" #include /* GAP includes */ #include "gap-intl.h" #include "gap_stock.h" #include "gap_match.h" #include "gap_lib.h" #include "gap_mod_layer.h" #include "gap_mod_layer_dialog.h" #define GAP_MOD_FRAMES_PLUGIN_NAME "plug_in_gap_modify" #define GAP_MOD_FRAMES_HELP_ID "plug-in-gap-modify" #define SCALE_WIDTH 180 #define SPIN_BUTTON_WIDTH 75 #define RADIO_ITEM_INDEX_KEY "gap_radio_item_index_key" #define MENU_ITEM_INDEX_KEY "gap_menu_item_index_key" #define MENU_ITEM_TITLE_KEY "gap_menu_item_title_key" #define MENU_ITEM_TIPTEXT_KEY "gap_menu_item_tiptext_key" extern int gap_debug; /* ==0 ... dont print debug infos */ static void p_mod_frames_response (GtkWidget *widget, gint response_id, GapModFramesGlobalParams *gmop); static void p_upd_sensitivity(GapModFramesGlobalParams *gmop); static void p_func_optionmenu_callback (GtkWidget *wgt_item, GapModFramesGlobalParams *gmop); static void p_make_func_menu_item(const char *title , const char *tip_text , gint32 action_mode , GtkWidget *menu , GapModFramesGlobalParams *gmop ); static void p_make_func_menu_item_set_mode(const char *mode_name , gint32 action_mode , GtkWidget *menu , GapModFramesGlobalParams *gmop ); static void p_make_layer_attrinutes_submenu(GtkWidget *master_menu, GapModFramesGlobalParams *gmop); static void p_make_layer_modes_submenu(GtkWidget *master_menu, GapModFramesGlobalParams *gmop); static void p_make_layer_stackpositions_submenu(GtkWidget *master_menu, GapModFramesGlobalParams *gmop); static void p_make_merge_layers_submenu(GtkWidget *master_menu, GapModFramesGlobalParams *gmop); static void p_make_selection_submenu(GtkWidget *master_menu, GapModFramesGlobalParams *gmop); static void p_make_layermask_submenu(GtkWidget *master_menu, GapModFramesGlobalParams *gmop); static void p_make_toplevel_menu_items(GtkWidget *master_menu, GapModFramesGlobalParams *gmop); static void p_case_sensitive_toggled_callback(GtkCheckButton *checkbutton, GapModFramesGlobalParams *gmop); static void p_invert_selection_toggled_callback(GtkCheckButton *checkbutton, GapModFramesGlobalParams *gmop); static void p_layer_pattern_entry_update_cb(GtkWidget *widget, GapModFramesGlobalParams *gmop); static void p_new_layername_entry_update_cb(GtkWidget *widget, GapModFramesGlobalParams *gmop); static void p_sel_mode_radio_callback(GtkWidget *widget, GapModFramesGlobalParams *gmop); static void p_create_mod_frames_dialog(GapModFramesGlobalParams *gmop); /* --------------------------------- * p_mod_frames_response * --------------------------------- */ static void p_mod_frames_response (GtkWidget *widget, gint response_id, GapModFramesGlobalParams *gmop) { switch (response_id) { case GTK_RESPONSE_OK: gmop->run_flag = TRUE; default: if(gmop->shell) { GtkWidget *l_shell; l_shell = gmop->shell; gmop->shell = NULL; gtk_widget_destroy(l_shell); gtk_main_quit(); } break; } } /* end p_mod_frames_response */ /* --------------------------------- * p_upd_sensitivity * --------------------------------- */ static void p_upd_sensitivity(GapModFramesGlobalParams *gmop) { GtkWidget *wgt; gboolean l_sensitive; gboolean l_sensitive_frame; const char *l_label_name; l_sensitive = FALSE; switch(gmop->sel_mode) { case GAP_MTCH_EQUAL: case GAP_MTCH_START: case GAP_MTCH_END: case GAP_MTCH_ANYWHERE: /* insensitive for other select modes that are * lists of stacknumbers or all_visible layers */ l_sensitive = TRUE; break; default: break; } wgt = gmop->case_sensitive_check_button; if(wgt) { gtk_widget_set_sensitive(wgt, l_sensitive); } l_sensitive = TRUE; if(gmop->sel_mode == GAP_MTCH_ALL_VISIBLE) { /* the pattern entry is insensitive if all_visible layers (6) is selected */ l_sensitive = FALSE; } wgt = gmop->layer_pattern_entry; if(wgt) { gtk_widget_set_sensitive(wgt, l_sensitive); } l_sensitive = FALSE; l_sensitive_frame = TRUE; l_label_name = " "; switch(gmop->action_mode) { case GAP_MOD_ACM_DUPLICATE: case GAP_MOD_ACM_RENAME: l_label_name = _("New Layer Name"); l_sensitive = TRUE; break; case GAP_MOD_ACM_MERGE_EXPAND: case GAP_MOD_ACM_MERGE_IMG: case GAP_MOD_ACM_MERGE_BG: l_label_name = _("Merged Layer Name"); l_sensitive = TRUE; break; case GAP_MOD_ACM_SEL_SAVE: case GAP_MOD_ACM_SEL_LOAD: case GAP_MOD_ACM_SEL_DELETE: l_sensitive_frame = FALSE; l_label_name = _("Channel Name"); l_sensitive = TRUE; break; case GAP_MOD_ACM_SEL_REPLACE: case GAP_MOD_ACM_SEL_ADD: case GAP_MOD_ACM_SEL_SUBTRACT: case GAP_MOD_ACM_SEL_INTERSECT: case GAP_MOD_ACM_SEL_NONE: case GAP_MOD_ACM_SEL_ALL: case GAP_MOD_ACM_SEL_INVERT: l_sensitive_frame = FALSE; break; default: break; } wgt = gmop->new_layername_entry; if(wgt) { gtk_widget_set_sensitive(wgt, l_sensitive); } wgt = gmop->layer_selection_frame; if(wgt) { gtk_widget_set_sensitive(wgt, l_sensitive_frame); } wgt = gmop->new_layername_label; if(wgt) { gtk_label_set_text(GTK_LABEL(wgt), l_label_name); } } /* end p_upd_sensitivity */ /* --------------------------------- * p_func_optionmenu_callback * --------------------------------- */ static void p_func_optionmenu_callback (GtkWidget *wgt_item, GapModFramesGlobalParams *gmop) { gint32 l_idx; const char *title; const char *tiptext; if(gap_debug) printf("CB: p_func_optionmenu_callback\n"); if(gmop == NULL) return; l_idx = GPOINTER_TO_INT(g_object_get_data (G_OBJECT (wgt_item), MENU_ITEM_INDEX_KEY)); title = (const char *)g_object_get_data (G_OBJECT (wgt_item), MENU_ITEM_TITLE_KEY); tiptext = (const char *)g_object_get_data (G_OBJECT (wgt_item), MENU_ITEM_TIPTEXT_KEY); if(gap_debug) { printf("CB: p_func_optionmenu_callback index: %d\n" , (int)l_idx); } gmop->action_mode = l_idx; if(title) { if(gmop->func_info_label) { gtk_label_set_text(GTK_LABEL(gmop->func_info_label), title); } } /* update widget_sensitivity */ p_upd_sensitivity(gmop); } /* end p_func_optionmenu_callback */ /* --------------------------------- * p_make_func_menu_item * --------------------------------- */ static void p_make_func_menu_item(const char *title , const char *tip_text , gint32 action_mode , GtkWidget *menu , GapModFramesGlobalParams *gmop ) { GtkWidget *menu_item; menu_item = gtk_menu_item_new_with_label (title); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (p_func_optionmenu_callback), (gpointer)gmop); g_object_set_data (G_OBJECT (menu_item), MENU_ITEM_INDEX_KEY , GINT_TO_POINTER(action_mode)); g_object_set_data_full (G_OBJECT (menu_item), MENU_ITEM_TITLE_KEY , g_strdup(title), (GDestroyNotify) g_free); g_object_set_data_full (G_OBJECT (menu_item), MENU_ITEM_TIPTEXT_KEY , g_strdup(tip_text), (GDestroyNotify) g_free); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); if(action_mode == gmop->action_mode) { if(gmop->func_info_label) { gtk_label_set_text(GTK_LABEL(gmop->func_info_label), title); } } } /* end p_make_func_menu_item */ /* ------------------------------- * p_make_layer_attrinutes_submenu * ------------------------------- */ static void p_make_layer_attrinutes_submenu(GtkWidget *master_menu, GapModFramesGlobalParams *gmop) { GtkWidget *menu_item; GtkWidget *sub_menu; /* the Layer Attributes sub menu */ menu_item = gtk_menu_item_new_with_label (_("Layer Attributes")); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (master_menu), menu_item); sub_menu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), sub_menu); p_make_func_menu_item(_("Set layer(s) visible") ,_("set all selected layers visible") ,GAP_MOD_ACM_SET_VISIBLE ,sub_menu ,gmop ); p_make_func_menu_item(_("Set layer(s) invisible") ,_("set all selected layers invisible") ,GAP_MOD_ACM_SET_INVISIBLE ,sub_menu ,gmop ); p_make_func_menu_item(_("Set layer(s) linked") ,_("set all selected layers linked") ,GAP_MOD_ACM_SET_LINKED ,sub_menu ,gmop ); p_make_func_menu_item(_("Set layer(s) unlinked") ,_("set all selected layers unlinked") ,GAP_MOD_ACM_SET_UNLINKED ,sub_menu ,gmop ); } /* end p_make_layer_attrinutes_submenu */ /* ------------------------------ * p_make_func_menu_item_set_mode * ------------------------------ */ static void p_make_func_menu_item_set_mode(const char *mode_name , gint32 action_mode , GtkWidget *menu , GapModFramesGlobalParams *gmop) { char *title; char *tip_text; title = g_strdup_printf(_("Set layer(s) mode: %s"), mode_name); tip_text = g_strdup_printf(_("Set all selected layers to mode: %s"), mode_name); p_make_func_menu_item(title ,tip_text ,action_mode ,menu ,gmop ); g_free(title); g_free(tip_text); } /* end p_make_func_menu_item_set_mode */ /* ------------------------------ * p_make_layer_modes_submenu * ------------------------------ */ static void p_make_layer_modes_submenu(GtkWidget *master_menu, GapModFramesGlobalParams *gmop) { GtkWidget *menu_item; GtkWidget *sub_menu; /* the Layer Modes sub menu */ menu_item = gtk_menu_item_new_with_label (_("Layer Modes")); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (master_menu), menu_item); sub_menu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), sub_menu); p_make_func_menu_item_set_mode(_("Normal") ,GAP_MOD_ACM_SET_MODE_NORMAL ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Dissolve") ,GAP_MOD_ACM_SET_MODE_DISSOLVE ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Multiply") ,GAP_MOD_ACM_SET_MODE_MULTIPLY ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Divide") ,GAP_MOD_ACM_SET_MODE_DIVIDE ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Screen") ,GAP_MOD_ACM_SET_MODE_SCREEN ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Overlay") ,GAP_MOD_ACM_SET_MODE_OVERLAY ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Difference") ,GAP_MOD_ACM_SET_MODE_DIFFERENCE ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Addition") ,GAP_MOD_ACM_SET_MODE_ADDITION ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Subtract") ,GAP_MOD_ACM_SET_MODE_SUBTRACT ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Darken only") ,GAP_MOD_ACM_SET_MODE_DARKEN_ONLY ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Lighten only") ,GAP_MOD_ACM_SET_MODE_LIGHTEN_ONLY ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Dodge") ,GAP_MOD_ACM_SET_MODE_DODGE ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Burn") ,GAP_MOD_ACM_SET_MODE_BURN ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Hardlight") ,GAP_MOD_ACM_SET_MODE_HARDLIGHT ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Softlight") ,GAP_MOD_ACM_SET_MODE_SOFTLIGHT ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Color erase") ,GAP_MOD_ACM_SET_MODE_COLOR_ERASE ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Grain extract") ,GAP_MOD_ACM_SET_MODE_GRAIN_EXTRACT_MODE ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Grain merge") ,GAP_MOD_ACM_SET_MODE_GRAIN_MERGE_MODE ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Hue") ,GAP_MOD_ACM_SET_MODE_HUE_MODE ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Saturation") ,GAP_MOD_ACM_SET_MODE_SATURATION_MODE ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Color") ,GAP_MOD_ACM_SET_MODE_COLOR_MODE ,sub_menu ,gmop ); p_make_func_menu_item_set_mode(_("Value") ,GAP_MOD_ACM_SET_MODE_VALUE_MODE ,sub_menu ,gmop ); } /* end p_make_layer_modes_submenu */ /* ----------------------------------- * p_make_layer_stackpositions_submenu * ----------------------------------- */ static void p_make_layer_stackpositions_submenu(GtkWidget *master_menu, GapModFramesGlobalParams *gmop) { GtkWidget *menu_item; GtkWidget *sub_menu; /* the Layer Stackposition sub menu */ menu_item = gtk_menu_item_new_with_label (_("Layer Stackposition")); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (master_menu), menu_item); sub_menu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), sub_menu); p_make_func_menu_item(_("Raise layer(s)") ,_("raise all selected layers") ,GAP_MOD_ACM_RAISE ,sub_menu ,gmop ); p_make_func_menu_item(_("Lower layer(s)") ,_("lower all selected layers") ,GAP_MOD_ACM_LOWER ,sub_menu ,gmop ); } /* end p_make_layer_stackpositions_submenu */ /* ------------------------------ * p_make_merge_layers_submenu * ------------------------------ */ static void p_make_merge_layers_submenu(GtkWidget *master_menu, GapModFramesGlobalParams *gmop) { GtkWidget *menu_item; GtkWidget *sub_menu; /* the Merge Layers sub menu */ menu_item = gtk_menu_item_new_with_label (_("Merge Layers")); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (master_menu), menu_item); sub_menu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), sub_menu); p_make_func_menu_item(_("Merge layer(s); expand as necessary") ,_("merge selected layers and expand as necessary") ,GAP_MOD_ACM_MERGE_EXPAND ,sub_menu ,gmop ); p_make_func_menu_item(_("Merge layer(s) clipped to image") ,_("merge selected layers and clip to image") ,GAP_MOD_ACM_MERGE_IMG ,sub_menu ,gmop ); p_make_func_menu_item(_("Merge layer(s) clipped to bg-layer") ,_("merge selected layers and clip to bg-layer") ,GAP_MOD_ACM_MERGE_BG ,sub_menu ,gmop ); } /* end p_make_merge_layers_submenu */ /* ------------------------------ * p_make_selection_submenu * ------------------------------ */ static void p_make_selection_submenu(GtkWidget *master_menu, GapModFramesGlobalParams *gmop) { GtkWidget *menu_item; GtkWidget *sub_menu; /* the Selection sub menu */ menu_item = gtk_menu_item_new_with_label (_("Selection")); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (master_menu), menu_item); sub_menu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), sub_menu); p_make_func_menu_item(_("Replace selection (source is the active frame)") ,_("Replace Selection by Selection of the invoking Frame Image") ,GAP_MOD_ACM_SEL_REPLACE ,sub_menu ,gmop ); p_make_func_menu_item(_("Add selection (source is the active frame)") ,NULL ,GAP_MOD_ACM_SEL_ADD ,sub_menu ,gmop ); p_make_func_menu_item(_("Subtract selection (source is the active frame)") ,NULL ,GAP_MOD_ACM_SEL_SUBTRACT ,sub_menu ,gmop ); p_make_func_menu_item(_("Intersect selection (source is the active frame)") ,NULL ,GAP_MOD_ACM_SEL_INTERSECT ,sub_menu ,gmop ); p_make_func_menu_item(_("Selection none") ,NULL ,GAP_MOD_ACM_SEL_NONE ,sub_menu ,gmop ); p_make_func_menu_item(_("Selection all") ,NULL ,GAP_MOD_ACM_SEL_ALL ,sub_menu ,gmop ); p_make_func_menu_item(_("Selection invert") ,NULL ,GAP_MOD_ACM_SEL_INVERT ,sub_menu ,gmop ); p_make_func_menu_item(_("Selection from alpha channel (individual per frame)") ,NULL ,GAP_MOD_ACM_SEL_ALPHA ,sub_menu ,gmop ); p_make_func_menu_item(_("Save selection to channel (individual per frame)") ,NULL ,GAP_MOD_ACM_SEL_SAVE ,sub_menu ,gmop ); p_make_func_menu_item(_("Load selection from channel (individual per frame)") ,NULL ,GAP_MOD_ACM_SEL_LOAD ,sub_menu ,gmop ); p_make_func_menu_item(_("Delete channel (by name)") ,NULL ,GAP_MOD_ACM_SEL_DELETE ,sub_menu ,gmop ); } /* end p_make_selection_submenu */ /* ------------------------------ * p_make_layermask_submenu * ------------------------------ */ static void p_make_layermask_submenu(GtkWidget *master_menu, GapModFramesGlobalParams *gmop) { GtkWidget *menu_item; GtkWidget *sub_menu; /* the LayerMask sub menu */ menu_item = gtk_menu_item_new_with_label (_("Layer Mask")); gtk_widget_show (menu_item); gtk_menu_shell_append (GTK_MENU_SHELL (master_menu), menu_item); sub_menu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), sub_menu); p_make_func_menu_item(_("Add white layermask (opaque)") ,NULL ,GAP_MOD_ACM_LMASK_WHITE ,sub_menu ,gmop ); p_make_func_menu_item(_("Add black layermask (transparent)") ,NULL ,GAP_MOD_ACM_LMASK_BLACK ,sub_menu ,gmop ); p_make_func_menu_item(_("Add layermask from alpha") ,NULL ,GAP_MOD_ACM_LMASK_ALPHA ,sub_menu ,gmop ); p_make_func_menu_item(_("Add layermask transfer from alpha") ,NULL ,GAP_MOD_ACM_LMASK_TALPHA ,sub_menu ,gmop ); p_make_func_menu_item(_("Add layermask from selection") ,NULL ,GAP_MOD_ACM_LMASK_SEL ,sub_menu ,gmop ); p_make_func_menu_item(_("Add layermask from bw copy") ,NULL ,GAP_MOD_ACM_LMASK_BWCOPY ,sub_menu ,gmop ); p_make_func_menu_item(_("Invert existing layermask") ,NULL ,GAP_MOD_ACM_LMASK_INVERT ,sub_menu ,gmop ); p_make_func_menu_item(_("Apply filter on layermask") ,NULL ,GAP_MOD_ACM_APPLY_FILTER_ON_LAYERMASK ,sub_menu ,gmop ); p_make_func_menu_item(_("Delete layermask") ,NULL ,GAP_MOD_ACM_LMASK_DELETE ,sub_menu ,gmop ); p_make_func_menu_item(_("Apply layermask") ,NULL ,GAP_MOD_ACM_LMASK_APPLY ,sub_menu ,gmop ); p_make_func_menu_item(_("Copy layermask from layer above") ,NULL ,GAP_MOD_ACM_LMASK_COPY_FROM_UPPER_LMASK ,sub_menu ,gmop ); p_make_func_menu_item(_("Copy layermask from layer below") ,NULL ,GAP_MOD_ACM_LMASK_COPY_FROM_LOWER_LMASK ,sub_menu ,gmop ); p_make_func_menu_item(_("Create mask layer representing the opacity (alpha+layermask merged)") ,NULL ,GAP_MOD_ACM_CREATE_LAYER_FROM_OPACITY ,sub_menu ,gmop ); p_make_func_menu_item(_("Create mask layer as copy of the layermask (ignore alpha)") ,NULL ,GAP_MOD_ACM_CREATE_LAYER_FROM_LMASK ,sub_menu ,gmop ); p_make_func_menu_item(_("Create mask layer as copy of the alpha channel (ignore layermask)") ,NULL ,GAP_MOD_ACM_CREATE_LAYER_FROM_ALPHA ,sub_menu ,gmop ); } /* end p_make_layermask_submenu */ /* ------------------------------ * p_make_toplevel_menu_items * ------------------------------ */ static void p_make_toplevel_menu_items(GtkWidget *master_menu, GapModFramesGlobalParams *gmop) { /* apply filter has no sub_menu */ p_make_func_menu_item(_("Apply filter on layer(s)") ,_("apply filter to all selected layers") ,GAP_MOD_ACM_APPLY_FILTER ,master_menu ,gmop ); p_make_func_menu_item(_("Duplicate layer(s)") ,NULL ,GAP_MOD_ACM_DUPLICATE ,master_menu ,gmop ); p_make_func_menu_item(_("Delete layer(s)") ,NULL ,GAP_MOD_ACM_DELETE ,master_menu ,gmop ); p_make_func_menu_item(_("Rename layer(s)") ,NULL ,GAP_MOD_ACM_RENAME ,master_menu ,gmop ); p_make_func_menu_item(_("Resize layer(s) to image size") ,_("Resize selected layer(s) to image size") ,GAP_MOD_ACM_RESIZE_TO_IMG ,master_menu ,gmop ); p_make_func_menu_item(_("Add alpha channel") ,NULL ,GAP_MOD_ACM_ADD_ALPHA ,master_menu ,gmop ); } /* end p_make_toplevel_menu_items */ /* --------------------------------- * p_case_sensitive_toggled_callback * --------------------------------- */ static void p_case_sensitive_toggled_callback(GtkCheckButton *checkbutton, GapModFramesGlobalParams *gmop) { if(gmop) { if (GTK_TOGGLE_BUTTON(checkbutton)->active) { gmop->sel_case = TRUE; } else { gmop->sel_case = FALSE; } } } /* end p_case_sensitive_toggled_callback */ /* --------------------------------- * p_invert_selection_toggled_callback * --------------------------------- */ static void p_invert_selection_toggled_callback(GtkCheckButton *checkbutton, GapModFramesGlobalParams *gmop) { if(gmop) { if (GTK_TOGGLE_BUTTON(checkbutton)->active) { gmop->sel_invert = TRUE; } else { gmop->sel_invert = FALSE; } } } /* end p_invert_selection_toggled_callback */ /* -------------------------- * p_layer_pattern_entry_update_cb * -------------------------- */ static void p_layer_pattern_entry_update_cb(GtkWidget *widget, GapModFramesGlobalParams *gmop) { if(gmop == NULL) { return; } g_snprintf(gmop->sel_pattern, sizeof(gmop->sel_pattern), "%s" , gtk_entry_get_text(GTK_ENTRY(widget)) ); } /* end p_layer_pattern_entry_update_cb */ /* -------------------------- * p_new_layername_entry_update_cb * -------------------------- */ static void p_new_layername_entry_update_cb(GtkWidget *widget, GapModFramesGlobalParams *gmop) { if(gmop == NULL) { return; } g_snprintf(gmop->new_layername, sizeof(gmop->new_layername), "%s" , gtk_entry_get_text(GTK_ENTRY(widget)) ); } /* end p_new_layername_entry_update_cb */ /* -------------------------- * p_sel_mode_radio_callback * -------------------------- */ static void p_sel_mode_radio_callback(GtkWidget *widget, GapModFramesGlobalParams *gmop) { gint32 l_sel_mode; l_sel_mode = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget) , RADIO_ITEM_INDEX_KEY)); if((gmop) && (GTK_TOGGLE_BUTTON (widget)->active)) { gmop->sel_mode = l_sel_mode; /* update widget_sensitivity */ p_upd_sensitivity(gmop); } } /*end p_sel_mode_radio_callback */ /* ----------------------------- * p_create_mod_frames_dialog * ----------------------------- */ static void p_create_mod_frames_dialog(GapModFramesGlobalParams *gmop) { GtkWidget *dlg; GtkWidget *main_vbox; GtkWidget *hbox; GtkWidget *frame; GtkWidget *entry; GtkWidget *table; GtkWidget *func_table; GtkWidget *sel_table; GtkWidget *range_table; GtkWidget *label; GtkWidget *check_button; GtkWidget *menu_bar; GtkWidget *menu_item; GtkWidget *master_menu; gint row; GtkObject *adj; GtkWidget *radio_button; GSList *radio_group = NULL; gboolean l_radio_pressed; dlg = gimp_dialog_new (_("Frames Modify"), GAP_MOD_FRAMES_PLUGIN_NAME, NULL, 0, gimp_standard_help_func, GAP_MOD_FRAMES_HELP_ID, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gmop->shell = dlg; g_signal_connect (G_OBJECT (gmop->shell), "response", G_CALLBACK (p_mod_frames_response), gmop); main_vbox = gtk_vbox_new (FALSE, 4); gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6); gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dlg)->vbox), main_vbox); /* +++++++++++++++++++++++++ */ /* the function frame */ /* +++++++++++++++++++++++++ */ frame = gimp_frame_new (_("Function")); gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); table = gtk_table_new (3, 2, FALSE); func_table = table; gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_table_set_row_spacings (GTK_TABLE (table), 4); gtk_container_add (GTK_CONTAINER (frame), table); gtk_widget_show (table); row = 0; /* the Fuction label */ label = gtk_label_new (_("Function:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); gtk_widget_show (label); /* the hbox */ hbox = gtk_hbox_new (FALSE, 4); gtk_widget_show (hbox); /* the function menu_bar */ menu_bar = gtk_menu_bar_new(); gtk_widget_show (menu_bar); // the tooltip is drawn in front of the menu items // and forces the user for blind selection // as workaround dont show tooltip for the menu_bar at all: // gimp_help_set_help_data (menu_bar // , _("Function to be performed on all selected layers " // "in all frames of the selected frame range") // , NULL); gtk_table_attach (GTK_TABLE(table), menu_bar, 0, 1, row, row+1 , GTK_FILL, 0, 0, 0); /* the function_info_label (some kind of tooltip for the selected menu_item) */ label = gtk_label_new ("menu_item function description"); gmop->func_info_label = label; gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_widget_show (label); gtk_table_attach (GTK_TABLE(table), label, 1, 2, row, row+1 , GTK_FILL|GTK_EXPAND , 0, 0, 0); /* the master menu */ master_menu = gtk_menu_new (); /* the toplevel menu_item (will be replaced on any selection) */ menu_item = gtk_menu_item_new_with_label(_("Function:")); gtk_widget_show (menu_item); gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), menu_item); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), master_menu); /* make submenus */ p_make_layer_attrinutes_submenu(master_menu, gmop); p_make_layer_modes_submenu(master_menu, gmop); p_make_layer_stackpositions_submenu(master_menu, gmop); p_make_merge_layers_submenu(master_menu, gmop); p_make_selection_submenu(master_menu, gmop); p_make_layermask_submenu(master_menu, gmop); /* finally we have some menu items that are not grouped into sub-menus */ p_make_toplevel_menu_items(master_menu, gmop); row++; /* the LayerName (or channel Name) label */ label = gtk_label_new (_("Layer Name:")); gmop->new_layername_label = label; gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); gtk_table_attach (GTK_TABLE(table), label, 0, 1, row, row+1 , GTK_FILL, 0, 0, 0); gtk_widget_show (label); /* the LayerName (or channel Name) entry */ entry = gtk_entry_new(); gmop->new_layername_entry = entry; gtk_entry_set_text(GTK_ENTRY(entry), gmop->new_layername); gtk_widget_show(entry); gtk_table_attach (GTK_TABLE(table), entry, 1, 2, row, row+1 ,GTK_FILL|GTK_EXPAND , 0, 0, 0); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK (p_new_layername_entry_update_cb), gmop); gimp_help_set_help_data(entry , _("Name for all handled layers (or channels),\n" "where the string '[######]' is replaced by the frame number.") , NULL); /* +++++++++++++++++++++++++ */ /* the layer selection frame */ /* +++++++++++++++++++++++++ */ frame = gimp_frame_new (_("Layer Selection")); gmop->layer_selection_frame = frame; gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); table = gtk_table_new (8, 2, FALSE); sel_table = table; gtk_container_add (GTK_CONTAINER (frame), table); gtk_widget_show (table); row = 0; /* the radio button "Pattern is equal to layer name" */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Pattern is equal to layer name") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach (GTK_TABLE(sel_table), radio_button, 0, 1, row, row+1 , GTK_FILL, 0, 0, 0); l_radio_pressed = (gmop->sel_mode == GAP_MTCH_EQUAL); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button , _("Select all layers where layer name is equal to pattern") , NULL); gtk_widget_show (radio_button); g_object_set_data (G_OBJECT (radio_button), RADIO_ITEM_INDEX_KEY , GINT_TO_POINTER(GAP_MTCH_EQUAL)); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (p_sel_mode_radio_callback), gmop); /* the case sensitive check_button */ check_button = gtk_check_button_new_with_label (_("Case sensitive")); gmop->case_sensitive_check_button = check_button; gtk_widget_show (check_button); gtk_table_attach (GTK_TABLE (sel_table), check_button, 1, 2, row, row+1 ,(GtkAttachOptions) (GTK_FILL) ,(GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (check_button , _("Lowercase and uppercase letters are considered as different") , NULL); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button) , gmop->sel_case); g_signal_connect ( G_OBJECT (check_button), "toggled", G_CALLBACK (p_case_sensitive_toggled_callback), gmop); row++; /* the radio button "Pattern is start of layer name" */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Pattern is start of layer name") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach (GTK_TABLE(sel_table), radio_button, 0, 1, row, row+1 , GTK_FILL, 0, 0, 0); l_radio_pressed = (gmop->sel_mode == GAP_MTCH_START); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button , _("Select all layers where layer name starts with pattern") , NULL); gtk_widget_show (radio_button); g_object_set_data (G_OBJECT (radio_button), RADIO_ITEM_INDEX_KEY , GINT_TO_POINTER(GAP_MTCH_START)); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (p_sel_mode_radio_callback), gmop); /* the invert layer_selection check_button */ check_button = gtk_check_button_new_with_label (_("Invert Layer Selection")); gmop->invert_check_button = check_button; gtk_widget_show (check_button); gtk_table_attach (GTK_TABLE (sel_table), check_button, 1, 2, row, row+1 ,(GtkAttachOptions) (GTK_FILL) ,(GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (check_button , _("Perform actions on all unselected layers") , NULL); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button) , gmop->sel_invert); g_signal_connect ( G_OBJECT (check_button), "toggled", G_CALLBACK (p_invert_selection_toggled_callback), gmop); row++; /* the radio button "Pattern is end of layer name" */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Pattern is end of layer name") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach (GTK_TABLE(sel_table), radio_button, 0, 1, row, row+1 , GTK_FILL, 0, 0, 0); l_radio_pressed = (gmop->sel_mode == GAP_MTCH_END); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button , _("Select all layers where layer name ends up with pattern") , NULL); gtk_widget_show (radio_button); g_object_set_data (G_OBJECT (radio_button), RADIO_ITEM_INDEX_KEY , GINT_TO_POINTER(GAP_MTCH_END)); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (p_sel_mode_radio_callback), gmop); row++; /* the radio button "Pattern is a part of layer name" */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Pattern is a part of layer name") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach (GTK_TABLE(sel_table), radio_button, 0, 1, row, row+1 , GTK_FILL, 0, 0, 0); l_radio_pressed = (gmop->sel_mode == GAP_MTCH_ANYWHERE); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button , _("Select all layers where layer name contains pattern") , NULL); gtk_widget_show (radio_button); g_object_set_data (G_OBJECT (radio_button), RADIO_ITEM_INDEX_KEY , GINT_TO_POINTER(GAP_MTCH_ANYWHERE)); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (p_sel_mode_radio_callback), gmop); row++; /* the radio button "Pattern is a list of layerstack numbers" */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Pattern is a list of layerstack numbers") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach (GTK_TABLE(sel_table), radio_button, 0, 1, row, row+1 , GTK_FILL, 0, 0, 0); l_radio_pressed = (gmop->sel_mode == GAP_MTCH_NUMBERLIST); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button , _("Select layerstack positions where 0 is the top layer.\nExample: 0, 4-5, 8") , NULL); gtk_widget_show (radio_button); g_object_set_data (G_OBJECT (radio_button), RADIO_ITEM_INDEX_KEY , GINT_TO_POINTER(GAP_MTCH_NUMBERLIST)); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (p_sel_mode_radio_callback), gmop); row++; /* the radio button "Pattern is a list of reverse layerstack numbers" */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Pattern is a list of reverse layerstack numbers") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach (GTK_TABLE(sel_table), radio_button, 0, 1, row, row+1 , GTK_FILL, 0, 0, 0); l_radio_pressed = (gmop->sel_mode == GAP_MTCH_INV_NUMBERLIST); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button , _("Select layerstack positions where 0 is the background layer.\nExample: 0, 4-5, 8") , NULL); gtk_widget_show (radio_button); g_object_set_data (G_OBJECT (radio_button), RADIO_ITEM_INDEX_KEY , GINT_TO_POINTER(GAP_MTCH_INV_NUMBERLIST)); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (p_sel_mode_radio_callback), gmop); row++; /* the radio button "All visible (ignore pattern)" */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("All visible (ignore pattern)") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach (GTK_TABLE(sel_table), radio_button, 0, 1, row, row+1 , GTK_FILL, 0, 0, 0); l_radio_pressed = (gmop->sel_mode == GAP_MTCH_ALL_VISIBLE); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button , _("Select all visible layers") , NULL); gtk_widget_show (radio_button); g_object_set_data (G_OBJECT (radio_button), RADIO_ITEM_INDEX_KEY , GINT_TO_POINTER(GAP_MTCH_ALL_VISIBLE)); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (p_sel_mode_radio_callback), gmop); row++; /* the hbox */ hbox = gtk_hbox_new (FALSE, 4); gtk_widget_show (hbox); /* the layer_pattern label */ label = gtk_label_new (_("Layer Pattern:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_widget_show (label); /* the layer_pattern entry */ entry = gtk_entry_new(); gmop->layer_pattern_entry = entry; gtk_entry_set_text(GTK_ENTRY(entry), gmop->sel_pattern); gimp_help_set_help_data(entry , _("String to identify layer names or layerstack position numbers. Example: 0,3-5") , NULL); gtk_widget_show(entry); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK (p_layer_pattern_entry_update_cb), gmop); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 4); gtk_table_attach (GTK_TABLE(sel_table), hbox, 0, 2, row, row+1 , GTK_FILL | GTK_EXPAND, 0, 0, 0); /* +++++++++++++++++++++++++ */ /* the frame_range frame */ /* +++++++++++++++++++++++++ */ frame = gimp_frame_new (_("Frame Range")); gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); table = gtk_table_new (2, 3, FALSE); range_table = table; gtk_container_add (GTK_CONTAINER (frame), table); gtk_widget_show (table); row = 0; /* the from_frame scale entry */ adj = gimp_scale_entry_new (GTK_TABLE (range_table), 0, row, _("From Frame:"), SCALE_WIDTH, SPIN_BUTTON_WIDTH, (gdouble)gmop->ainfo_ptr->first_frame_nr, (gdouble)gmop->ainfo_ptr->first_frame_nr, /* lower */ (gdouble)gmop->ainfo_ptr->last_frame_nr, /* upper */ 1, 10, /* step, page */ 0, /* digits */ TRUE, /* constrain */ (gdouble)gmop->ainfo_ptr->first_frame_nr, /* lower unconstrained */ (gdouble)gmop->ainfo_ptr->last_frame_nr, /* upper unconstrained */ _("First handled frame"), NULL); gmop->frame_from_adj = adj; g_object_set_data(G_OBJECT(adj), "gmop", gmop); g_signal_connect (adj, "value_changed", G_CALLBACK (gimp_int_adjustment_update), &gmop->range_from); row++; /* the to_frame scale entry */ adj = gimp_scale_entry_new (GTK_TABLE (range_table), 0, row, _("To Frame:"), SCALE_WIDTH, SPIN_BUTTON_WIDTH, (gdouble)gmop->ainfo_ptr->last_frame_nr, (gdouble)gmop->ainfo_ptr->first_frame_nr, /* lower */ (gdouble)gmop->ainfo_ptr->last_frame_nr, /* upper */ 1, 10, /* step, page */ 0, /* digits */ TRUE, /* constrain */ (gdouble)gmop->ainfo_ptr->first_frame_nr, /* lower unconstrained */ (gdouble)gmop->ainfo_ptr->last_frame_nr, /* upper unconstrained */ _("Last handled frame"), NULL); gmop->frame_to_adj = adj; g_object_set_data(G_OBJECT(adj), "gmop", gmop); g_signal_connect (adj, "value_changed", G_CALLBACK (gimp_int_adjustment_update), &gmop->range_to); gtk_widget_show(main_vbox); } /* end p_create_mod_frames_dialog */ /* ----------------------------- * gap_mod_frames_dialog * ----------------------------- */ int gap_mod_frames_dialog(GapAnimInfo *ainfo_ptr, gint32 *range_from, gint32 *range_to, gint32 *action_mode, gint32 *sel_mode, gint32 *sel_case, gint32 *sel_invert, char *sel_pattern, char *new_layername) { GapModFramesGlobalParams global_modify_params; GapModFramesGlobalParams *gmop; if(gap_debug) printf("\nSTART gap_mod_frames_dialog\n"); gmop = &global_modify_params; gimp_ui_init ("gap_mod_frames", FALSE); gap_stock_init(); gmop->run_flag = FALSE; gmop->ainfo_ptr = ainfo_ptr; gmop->range_from = gmop->ainfo_ptr->first_frame_nr; gmop->range_to = gmop->ainfo_ptr->last_frame_nr; gmop->action_mode = 0; gmop->sel_mode = 4; /* pattern is list of layerstack numbers */ gmop->sel_case = TRUE; gmop->sel_invert = FALSE; gmop->sel_pattern[0] = '0'; gmop->sel_pattern[1] = '\0'; gmop->new_layername[0] = '\0'; gmop->case_sensitive_check_button = NULL; gmop->invert_check_button = NULL; gmop->layer_pattern_entry = NULL; gmop->new_layername_entry = NULL; gmop->new_layername_label = NULL; gmop->layer_selection_frame = NULL; p_create_mod_frames_dialog(gmop); p_upd_sensitivity(gmop); gtk_widget_show (gmop->shell); if(gap_debug) printf("gap_mod_layer_dialog.c BEFORE gtk_main\n"); gtk_main (); gdk_flush (); if(gap_debug) printf("gap_mod_layer_dialog.c END run_flag: %d\n", (int)gmop->run_flag); *range_from = gmop->range_from; *range_to = gmop->range_to; *action_mode = gmop->action_mode; *sel_mode = gmop->sel_mode; *sel_case = gmop->sel_case; *sel_invert = gmop->sel_invert; g_snprintf(sel_pattern, MAX_LAYERNAME, "%s", gmop->sel_pattern); g_snprintf(new_layername, MAX_LAYERNAME, "%s", gmop->new_layername); if(gmop->run_flag) { return 0; /* OK, request to run the modify frames plug-in */ } return -1; /* for cancel or close dialog without run request */ } /* end gap_mod_frames_dialog */ gimp-gap-2.6.0+dfsg.orig/gap/gap_dbbrowser_utils.h0000644000175000017500000000442611212030253021733 0ustar thibautthibaut/* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* gap_dbbrowser_utils.h (original code dbbrowser_utils.h by Thomas NOEL 09. dec .1998 hof: update for GIMP 1.1 20. dec .1997 hof: GAP variant of DBbrowser removed apply_callback added constraint_procedure, added 2 buttons added return type 0.08 26th sept 97 by Thomas NOEL */ #ifndef _GAP_DB_BROWSER_UTILS_H #define _GAP_DB_BROWSER_UTILS_H #include "libgimp/gimp.h" typedef struct { char selected_proc_name[256]; int button_nr; /* -1 on cancel, 0 .. n */ } GapDbBrowserResult; /* proc to check if to add or not to add the procedure to the browsers listbox * retcode: * 0 ... do not add * 1 ... add the procedure to the browsers listbox */ typedef int (*t_constraint_func) (gchar *proc_name, gint32 image_id); int gap_db_browser_dialog (char *title_txt, char *button_1_txt, char *button_2_txt, t_constraint_func constraint_func, t_constraint_func constraint_func_sel1, t_constraint_func constraint_func_sel2, GapDbBrowserResult *result, gint32 image_id, const char *help_id ); gchar* gap_db_get_plugin_menupath (const gchar *name); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_split.c0000644000175000017500000004664411212030253017660 0ustar thibautthibaut/* gap_split.c * 1997.11.06 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains * - gap_split_image * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history * 2.1.0; 2004/11/12 hof: added help button * 1.3.14a; 2003/05/25 hof: bugfix: defaultname for unnamed image * added digits and only_visible parameter * 1.1.28a; 2000/10/29 hof: subsequent save calls use GIMP_RUN_WITH_LAST_VALS * 1.1.9a; 1999/09/21 hof: bugfix GIMP_RUN_NONINTERACTIVE mode did not work * 1.1.8a; 1999/08/31 hof: accept video framenames without underscore '_' * 1.1.5a; 1999/05/08 hof: bugix (dont mix GimpImageType with GimpImageBaseType) * 0.96.00; 1998/07/01 hof: - added scale, resize and crop * (affects full range == all video frames) * - now using gap_arr_dialog.h * 0.94.01; 1998/04/28 hof: added flatten_mode to plugin: gap_range_to_multilayer * 0.92.00 1998.01.10 hof: bugfix in p_frames_to_multilayer * layers need alpha (to be raise/lower able) * 0.90.00 first development release */ #include "config.h" /* SYTEM (UNIX) includes */ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif /* GIMP includes */ #include "gtk/gtk.h" #include "config.h" #include "gap-intl.h" #include "libgimp/gimp.h" /* GAP includes */ #include "gap_libgapbase.h" #include "gap_layer_copy.h" #include "gap_lib.h" #include "gap_arr_dialog.h" #define PLUGIN_NAME_GAP_SPLIT "plug_in_gap_split" typedef struct { gint32 inverse_order; gint32 no_alpha; gint32 only_visible; gint32 copy_properties; gint32 digits; char extension[32]; } split_vals_t; extern int gap_debug; /* ==0 ... dont print debug infos */ #define GAP_HELP_ID_SPLIT "plug-in-gap-split" /* ------------------------------ * p_overwrite_dialog * ------------------------------ */ static gint p_overwrite_dialog(char *filename, gint overwrite_mode) { static GapArrButtonArg l_argv[3]; static GapArrArg argv[1]; if(g_file_test(filename, G_FILE_TEST_EXISTS)) { if (overwrite_mode < 1) { l_argv[0].but_txt = _("Overwrite Frame"); l_argv[0].but_val = 0; l_argv[1].but_txt = _("Overwrite All"); l_argv[1].but_val = 1; l_argv[2].but_txt = GTK_STOCK_CANCEL; l_argv[2].but_val = -1; gap_arr_arg_init(&argv[0], GAP_ARR_WGT_LABEL); argv[0].label_txt = filename; return(gap_arr_std_dialog ( _("GAP Question"), _("File already exists"), 1, argv, 3, l_argv, -1)); } } return (overwrite_mode); } /* end p_overwrite_dialog */ /* -------------------- * p_split_image * -------------------- * splits a multilayer image into frames, where each selected layer * produces a resulting frame. * * returns value >= 0 if all is ok return the image_id of * the new created image (the last handled video frame) * (or -1 on error) */ static int p_split_image(GapAnimInfo *ainfo_ptr, split_vals_t *valPtr) { GimpImageBaseType l_type; guint l_width, l_height; GimpRunMode l_run_mode; gint32 l_new_image_id; gint l_nlayers; gint32 *l_layers_list; gint32 l_src_layer_id; gint32 l_cp_layer_id; gint l_src_offset_x, l_src_offset_y; /* layeroffsets as they were in src_image */ gdouble l_percentage, l_percentage_step; char *l_sav_name; char *l_str; gint32 l_rc; int l_idx; int l_framenumber; long l_layer_idx; gint l_overwrite_mode; gdouble l_xresoulution, l_yresoulution; gint32 l_unit; if(gap_debug) { printf("DEBUG: p_split_image inverse_order:%d no_alpha:%d only_visible:%d copy_properties:%d digits:%d ext:%s\n" , (int)valPtr->inverse_order , (int)valPtr->no_alpha , (int)valPtr->only_visible , (int)valPtr->copy_properties , (int)valPtr->digits , valPtr->extension ); } l_rc = -1; l_percentage = 0.0; l_run_mode = ainfo_ptr->run_mode; l_overwrite_mode = 0; if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE) { gimp_progress_init( _("Splitting image into frames...")); } l_new_image_id = -1; /* get info about the image */ l_width = gimp_image_width(ainfo_ptr->image_id); l_height = gimp_image_height(ainfo_ptr->image_id); l_type = gimp_image_base_type(ainfo_ptr->image_id); l_unit = gimp_image_get_unit(ainfo_ptr->image_id); gimp_image_get_resolution(ainfo_ptr->image_id, &l_xresoulution, &l_yresoulution); l_layers_list = gimp_image_get_layers(ainfo_ptr->image_id, &l_nlayers); if(l_layers_list != NULL) { gint32 l_max_framenumber; /* count number of relevant layers (to be written as frame images) */ l_max_framenumber = 0; for(l_idx = 0; l_idx < l_nlayers; l_idx++) { if(valPtr->only_visible) { if (! gimp_drawable_get_visible(l_layers_list[l_idx])) { /* skip invisible layers in only_visible Mode */ continue; } } l_max_framenumber++; } l_percentage_step = 1.0 / (l_nlayers); l_framenumber = l_max_framenumber; for(l_idx = 0; l_idx < l_nlayers; l_idx++) { if (l_new_image_id >= 0) { /* destroy the tmp image (it was saved to disk before) */ gimp_image_delete(l_new_image_id); l_new_image_id = -1; } if(valPtr->inverse_order != TRUE) l_layer_idx = l_idx; else l_layer_idx = (l_nlayers - 1 ) - l_idx; l_src_layer_id = l_layers_list[l_layer_idx]; if(valPtr->only_visible) { if (! gimp_drawable_get_visible(l_src_layer_id)) { /* skip invisible layers in only_visible Mode */ continue; } } /* the implementation for duplicate mode is slow, but keeps all gimp image stuff * (such as channels, path, guides, parasites and whatever * will be added in future gimp versions....) in each copied frame. */ if(valPtr->copy_properties) { gint l_dup_idx; gint l_dup_nlayers; gint32 *l_dup_layers_list; l_new_image_id = gimp_image_duplicate(ainfo_ptr->image_id); l_cp_layer_id = -1; l_dup_layers_list = gimp_image_get_layers(l_new_image_id, &l_dup_nlayers); for(l_dup_idx = 0; l_dup_idx < l_dup_nlayers; l_dup_idx++) { if (l_dup_idx == l_layer_idx) { l_cp_layer_id = l_dup_layers_list[l_dup_idx]; } else { gimp_image_remove_layer(l_new_image_id, l_dup_layers_list[l_dup_idx]); } } g_free (l_dup_layers_list); } else { /* create new image */ l_new_image_id = gimp_image_new(l_width, l_height,l_type); gimp_image_set_resolution(l_new_image_id, l_xresoulution, l_yresoulution); gimp_image_set_unit(l_new_image_id, l_unit); if(l_new_image_id < 0) { l_rc = -1; break; } /* copy colormap in case of indexed image */ if (l_type == GIMP_INDEXED) { gint l_ncolors; guchar *l_cmap; l_cmap = gimp_image_get_colormap(ainfo_ptr->image_id, &l_ncolors); gimp_image_set_colormap(l_new_image_id, l_cmap, l_ncolors); g_free(l_cmap); } /* copy the layer */ l_cp_layer_id = gap_layer_copy_to_dest_image(l_new_image_id, l_src_layer_id, 100.0, /* Opacity */ 0, /* NORMAL */ &l_src_offset_x, &l_src_offset_y); /* add the copied layer to current destination image */ gimp_image_add_layer(l_new_image_id, l_cp_layer_id, 0); gimp_layer_set_offsets(l_cp_layer_id, l_src_offset_x, l_src_offset_y); gimp_drawable_set_visible(l_cp_layer_id, TRUE); } /* delete alpha channel ? */ if (valPtr->no_alpha == TRUE) { /* add a dummy layer (flatten needs at least 2 layers) */ l_cp_layer_id = gimp_layer_new(l_new_image_id, "dummy", 4, 4, /* width, height */ ((l_type * 2 ) + 1), /* convert from GimpImageBaseType to GimpImageType, and add alpha */ 0.0, /* Opacity full transparent */ 0); /* NORMAL */ gimp_image_add_layer(l_new_image_id, l_cp_layer_id, 0); gimp_image_flatten (l_new_image_id); } /* build the name for output image */ l_str = gap_base_dup_filename_and_replace_extension_by_underscore(ainfo_ptr->old_filename); l_sav_name = gap_lib_alloc_fname6(l_str, l_framenumber, /* start at 1 (not at 0) */ valPtr->extension, valPtr->digits); l_framenumber--; g_free(l_str); if(l_sav_name != NULL) { gboolean writePermission; writePermission = TRUE; /* check overwrite if Destination frame already exsts */ l_overwrite_mode = p_overwrite_dialog(l_sav_name, l_overwrite_mode); if(gap_debug) { printf("l_overwrite_mode:%d file:%s\n", l_overwrite_mode, l_sav_name); } if (l_overwrite_mode < 0) { if(gap_debug) { printf("overwrite of file:%s was cancelled\n", l_sav_name); } writePermission = FALSE; } else { g_remove(l_sav_name); if(g_file_test(l_sav_name, G_FILE_TEST_EXISTS)) { char *errMsg; errMsg = g_strdup_printf(_("failed to overwrite %s (check permissions ?)") , l_sav_name); g_message(errMsg); g_free(errMsg); writePermission = FALSE; } } if(writePermission == TRUE) { /* save with selected save procedure * (regardless if image was flattened or not) */ l_rc = gap_lib_save_named_image(l_new_image_id, l_sav_name, l_run_mode); if(l_rc < 0) { gap_arr_msg_win(ainfo_ptr->run_mode, _("Split Frames: Save operation failed.\n" "desired save plugin can't handle type\n" "or desired save plugin not available.")); } } else { l_rc = -1; } if(l_rc < 0) { break; } l_run_mode = GIMP_RUN_WITH_LAST_VALS; /* for all further calls */ /* set image name */ gimp_image_set_filename (l_new_image_id, l_sav_name); /* prepare return value */ l_rc = l_new_image_id; g_free(l_sav_name); } /* show progress bar */ if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE) { l_percentage += l_percentage_step; gimp_progress_update (l_percentage); } if (l_framenumber <= 0) { break; } } g_free (l_layers_list); } return l_rc; } /* end p_split_image */ /* ------------------- * p_split_dialog * ------------------- * * return 0 (OK) * or -1 in case of Error or cancel */ static long p_split_dialog(GapAnimInfo *ainfo_ptr, split_vals_t *valPtr) { static GapArrArg argv[9]; gchar *buf; gchar *extptr; gchar *baseName; extptr = &valPtr->extension[0]; if(extptr) { if(*extptr == '.') { extptr++; } } baseName = gap_base_dup_filename_and_replace_extension_by_underscore(ainfo_ptr->old_filename); buf = g_strdup_printf (_("Make a frame (diskfile) from each layer.\n" "Frames are named in the style:\n" ".\n" "The first frame for the current case gets the name\n\n" "%s000001.%s\n") ,baseName ,extptr ); g_free(baseName); gap_arr_arg_init(&argv[0], GAP_ARR_WGT_LABEL); argv[0].label_txt = &buf[0]; gap_arr_arg_init(&argv[1], GAP_ARR_WGT_TEXT); argv[1].label_txt = _("Extension:"); argv[1].help_txt = _("Extension of resulting frames. The extension is also used to define fileformat."); argv[1].text_buf_len = sizeof(valPtr->extension); argv[1].text_buf_ret = valPtr->extension; argv[1].has_default = TRUE; argv[1].text_buf_default = ".xcf"; gap_arr_arg_init(&argv[2], GAP_ARR_WGT_TOGGLE); argv[2].label_txt = _("Inverse Order:"); argv[2].help_txt = _("ON: Start with frame 000001 at top layer.\n" "OFF: Start with frame 000001 at background layer."); argv[2].int_ret = valPtr->inverse_order; argv[2].has_default = TRUE; argv[2].int_default = 0; gap_arr_arg_init(&argv[3], GAP_ARR_WGT_TOGGLE); argv[3].label_txt = _("Flatten:"); argv[3].help_txt = _("ON: Remove alpha channel in resulting frames. Transparent parts are filled with the background color.\n" "OFF: Layers in the resulting frames keep their alpha channel."); argv[3].int_ret = valPtr->no_alpha; argv[3].has_default = TRUE; argv[3].int_default = 0; gap_arr_arg_init(&argv[4], GAP_ARR_WGT_TOGGLE); argv[4].label_txt = _("Only Visible:"); argv[4].help_txt = _("ON: Handle only visible layers.\n" "OFF: handle all layers and force visibiblity"); argv[4].int_ret = valPtr->only_visible; argv[4].has_default = TRUE; argv[4].int_default = 0; gap_arr_arg_init(&argv[5], GAP_ARR_WGT_TOGGLE); argv[5].label_txt = _("Copy properties:"); argv[5].help_txt = _("ON: Copy all image properties (channels, pathes, guides) to all frame images.\n" "OFF: copy only layers without image properties to frame images"); argv[5].int_ret = valPtr->copy_properties; argv[5].has_default = TRUE; argv[5].int_default = 0; gap_arr_arg_init(&argv[6], GAP_ARR_WGT_INT); argv[6].constraint = TRUE; argv[6].label_txt = _("Digits:"); argv[6].help_txt = _("How many digits to use for the framenumber filename part"); argv[6].int_min = (gint)1; argv[6].int_max = (gint)6; argv[6].int_ret = (gint)valPtr->digits; argv[6].entry_width = 60; argv[6].has_default = TRUE; argv[6].int_default = 6; gap_arr_arg_init(&argv[7], GAP_ARR_WGT_DEFAULT_BUTTON); argv[7].label_txt = _("Default"); argv[7].help_txt = _("Reset all parameters to default values"); gap_arr_arg_init(&argv[8], GAP_ARR_WGT_HELP_BUTTON); argv[8].help_id = GAP_HELP_ID_SPLIT; if(TRUE == gap_arr_ok_cancel_dialog( _("Split Image into Frames"), _("Split Settings"), 8, argv)) { g_free (buf); valPtr->inverse_order = argv[2].int_ret; valPtr->no_alpha = argv[3].int_ret; valPtr->only_visible = argv[4].int_ret; valPtr->copy_properties = argv[5].int_ret; valPtr->digits = argv[6].int_ret; return 0; } else { g_free (buf); return -1; } } /* end p_split_dialog */ /* ---------------- * gap_split_image * ---------------- * Split one (multilayer) image into video frames * one frame per layer. */ int gap_split_image(GimpRunMode run_mode, gint32 image_id, gint32 inverse_order, gint32 no_alpha, char *extension, gint32 only_visible, gint32 copy_properties, gint32 digits ) { gint32 l_new_image_id; gint32 l_rc; char *l_imagename; split_vals_t l_splitVals; split_vals_t *valPtr; GapAnimInfo *ainfo_ptr; l_rc = -1; if(gap_debug) { printf("START: gap_split_image run_mod:%d, image_id:%d\n" ,(int) run_mode ,(int) image_id ); } valPtr = &l_splitVals; /* force a default name without framenumber part for unnamed images */ l_imagename = gimp_image_get_filename(image_id); if(l_imagename == NULL) { gimp_image_set_filename(image_id, "frame_.xcf"); } ainfo_ptr = gap_lib_alloc_ainfo(image_id, run_mode); if(ainfo_ptr != NULL) { valPtr->extension[0] = '\0'; /* Possibly retrieve data from a previous run */ gimp_get_data (PLUGIN_NAME_GAP_SPLIT, &l_splitVals); if (l_splitVals.extension[0] == '\0') { /* use default values * (because there are no useful values of a previous run in the same session) */ strcpy(&valPtr->extension[0], ".xcf"); valPtr->inverse_order = 0; valPtr->no_alpha = 0; valPtr->only_visible = 0; valPtr->copy_properties = 0; valPtr->digits = 6; } if(run_mode == GIMP_RUN_INTERACTIVE) { l_rc = p_split_dialog (ainfo_ptr, valPtr); } else if(run_mode == GIMP_RUN_NONINTERACTIVE) { l_rc = 0; valPtr->inverse_order = inverse_order; valPtr->no_alpha = no_alpha; valPtr->only_visible = only_visible; valPtr->copy_properties = copy_properties; valPtr->digits = digits; strncpy(&valPtr->extension[0], extension, sizeof(valPtr->extension) -1); valPtr->extension[sizeof(valPtr->extension) -1] = '\0'; } else if (run_mode == GIMP_RUN_WITH_LAST_VALS) { l_rc = 0; } if(l_rc >= 0) { l_new_image_id = p_split_image(ainfo_ptr, valPtr); if (l_new_image_id >= 0) { /* Store values for next run */ if (run_mode == GIMP_RUN_INTERACTIVE) { gimp_set_data(PLUGIN_NAME_GAP_SPLIT, &l_splitVals, sizeof(l_splitVals)); } /* create a display for the new created image * (it is the first or the last frame of the * new created animation sequence) */ gimp_display_new(l_new_image_id); } l_rc = l_new_image_id; } gap_lib_free_ainfo(&ainfo_ptr); } return(l_rc); } /* end gap_split_image */ gimp-gap-2.6.0+dfsg.orig/gap/gap_image.h0000644000175000017500000000364011212030253017601 0ustar thibautthibaut/* gap_image.h * 2003.10.09 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains Image specific Procedures * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.20d; 2003.10.14 hof: created */ #ifndef _GAP_IMAGE_H #define _GAP_IMAGE_H #include "config.h" /* SYTEM (UNIX) includes */ #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" void gap_image_delete_immediate (gint32 image_id); gint32 gap_image_merge_visible_layers(gint32 image_id, GimpMergeType mergemode); void gap_image_prevent_empty_image(gint32 image_id); gint32 gap_image_new_with_layer_of_samesize(gint32 old_image_id, gint32 *layer_id); gint32 gap_image_new_of_samesize(gint32 old_image_id); gboolean gap_image_is_alive(gint32 image_id); gint32 gap_image_get_any_layer(gint32 image_id); gint32 gap_image_merge_to_specified_layer(gint32 ref_layer_id, GimpMergeType mergemode); gboolean gap_image_set_selection_from_selection_or_drawable(gint32 image_id, gint32 ref_drawable_id , gboolean force_from_drawable); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_mov_render.h0000644000175000017500000000313411212030253020655 0ustar thibautthibaut/* gap_mov_render.h * 1997.11.06 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * Render utility Procedures for GAP MovePath * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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_MOV_RENDER_H #define _GAP_MOV_RENDER_H /* revision history: * gimp 1.3.21b; 2003/10/22 hof: gap_mov_render_create_or_replace_tempsel_image new parameter all_empty * gimp 1.3.20d; 2003/10/15 hof: sourcecode cleanup * gimp 1.3.14a; 2003/05/24 hof: created (splitted off from gap_mov_dialog) */ #include "gap_mov_dialog.h" gint gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur_ptr); gint gap_mov_render_fetch_src_frame(GapMovValues *pvals, gint32 wanted_frame_nr); void gap_mov_render_create_or_replace_tempsel_image(gint32 channel_id, GapMovValues *val_ptr, gboolean all_empty); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_mod_layer.h0000644000175000017500000001205611212030253020473 0ustar thibautthibaut/* gap_mod_layer.h * 1998.10.14 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * modify Layer (perform actions (like raise, set visible, apply filter) * - foreach selected layer * - in each frame of the selected framerange) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 1.3.24a; 2004/01/17 hof: added Layermask Handling (the GAP_MOD_ACM_LMASK_xxx modes) * version 0.98.00 1998.11.27 hof: - use new module gap_pdb_calls.h * version 0.97.00 hof: - created module (as extract gap_fileter_foreach) */ #ifndef _GAP_MOD_LAYER_H #define _GAP_MOD_LAYER_H #define MAX_LAYERNAME 128 /* action_mode values */ #define GAP_MOD_ACM_SET_VISIBLE 0 #define GAP_MOD_ACM_SET_INVISIBLE 1 #define GAP_MOD_ACM_SET_LINKED 2 #define GAP_MOD_ACM_SET_UNLINKED 3 #define GAP_MOD_ACM_RAISE 4 #define GAP_MOD_ACM_LOWER 5 #define GAP_MOD_ACM_MERGE_EXPAND 6 #define GAP_MOD_ACM_MERGE_IMG 7 #define GAP_MOD_ACM_MERGE_BG 8 #define GAP_MOD_ACM_APPLY_FILTER 9 #define GAP_MOD_ACM_DUPLICATE 10 #define GAP_MOD_ACM_DELETE 11 #define GAP_MOD_ACM_RENAME 12 #define GAP_MOD_ACM_SEL_REPLACE 13 #define GAP_MOD_ACM_SEL_ADD 14 #define GAP_MOD_ACM_SEL_SUBTRACT 15 #define GAP_MOD_ACM_SEL_INTERSECT 16 #define GAP_MOD_ACM_SEL_NONE 17 #define GAP_MOD_ACM_SEL_ALL 18 #define GAP_MOD_ACM_SEL_INVERT 19 #define GAP_MOD_ACM_SEL_SAVE 20 #define GAP_MOD_ACM_SEL_LOAD 21 #define GAP_MOD_ACM_SEL_DELETE 22 #define GAP_MOD_ACM_ADD_ALPHA 23 #define GAP_MOD_ACM_LMASK_WHITE 24 #define GAP_MOD_ACM_LMASK_BLACK 25 #define GAP_MOD_ACM_LMASK_ALPHA 26 #define GAP_MOD_ACM_LMASK_TALPHA 27 #define GAP_MOD_ACM_LMASK_SEL 28 #define GAP_MOD_ACM_LMASK_BWCOPY 29 #define GAP_MOD_ACM_LMASK_DELETE 30 #define GAP_MOD_ACM_LMASK_APPLY 31 #define GAP_MOD_ACM_LMASK_COPY_FROM_UPPER_LMASK 32 #define GAP_MOD_ACM_LMASK_COPY_FROM_LOWER_LMASK 33 #define GAP_MOD_ACM_LMASK_INVERT 34 #define GAP_MOD_ACM_SET_MODE_NORMAL 35 #define GAP_MOD_ACM_SET_MODE_DISSOLVE 36 #define GAP_MOD_ACM_SET_MODE_MULTIPLY 37 #define GAP_MOD_ACM_SET_MODE_DIVIDE 38 #define GAP_MOD_ACM_SET_MODE_SCREEN 39 #define GAP_MOD_ACM_SET_MODE_OVERLAY 40 #define GAP_MOD_ACM_SET_MODE_DIFFERENCE 41 #define GAP_MOD_ACM_SET_MODE_ADDITION 42 #define GAP_MOD_ACM_SET_MODE_SUBTRACT 43 #define GAP_MOD_ACM_SET_MODE_DARKEN_ONLY 44 #define GAP_MOD_ACM_SET_MODE_LIGHTEN_ONLY 45 #define GAP_MOD_ACM_SET_MODE_DODGE 46 #define GAP_MOD_ACM_SET_MODE_BURN 47 #define GAP_MOD_ACM_SET_MODE_HARDLIGHT 48 #define GAP_MOD_ACM_SET_MODE_SOFTLIGHT 49 #define GAP_MOD_ACM_SET_MODE_COLOR_ERASE 50 #define GAP_MOD_ACM_SET_MODE_GRAIN_EXTRACT_MODE 51 #define GAP_MOD_ACM_SET_MODE_GRAIN_MERGE_MODE 52 #define GAP_MOD_ACM_SET_MODE_HUE_MODE 53 #define GAP_MOD_ACM_SET_MODE_SATURATION_MODE 54 #define GAP_MOD_ACM_SET_MODE_COLOR_MODE 55 #define GAP_MOD_ACM_SET_MODE_VALUE_MODE 56 #define GAP_MOD_ACM_APPLY_FILTER_ON_LAYERMASK 57 #define GAP_MOD_ACM_SEL_ALPHA 58 #define GAP_MOD_ACM_RESIZE_TO_IMG 59 #define GAP_MOD_ACM_CREATE_LAYER_FROM_OPACITY 60 #define GAP_MOD_ACM_CREATE_LAYER_FROM_LMASK 61 #define GAP_MOD_ACM_CREATE_LAYER_FROM_ALPHA 62 typedef struct { gint32 layer_id; gint visible; gint selected; } GapModLayliElem; GapModLayliElem *gap_mod_alloc_layli(gint32 image_id, gint32 *l_sel_cnt, gint *nlayers, gint32 sel_mode, gint32 sel_case, gint32 sel_invert, char *sel_pattern ); int gap_mod_get_1st_selected (GapModLayliElem * layli_ptr, gint nlayers); gint gap_mod_layer(GimpRunMode run_mode, gint32 image_id, gint32 range_from, gint32 range_to, gint32 action_mode, gint32 sel_mode, gint32 sel_case, gint32 sel_invert, char *sel_pattern, char *new_layername); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_filter_iterators.h0000644000175000017500000000351311212030253022077 0ustar thibautthibaut/* gap_filter_iterators.h * * 1997.12.18 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * - Headers for XXX_Iterator_ALT Procedures * * for now i made some Iterator Plugins using the ending _ALT, * If New plugins were added to the gimp, or existing ones were updated, * the Authors should supply original _Iterator Procedures * (without the _ALT ending) * This Procedures are then used instead of my (Hacked _ALT) versions. * to modify the settings for the plugin when called step by step * on animated multilayer Images. * without name conflicts. */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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_FILTER_ITERATORS_H #define _GAP_FILTER_ITERATORS_H typedef gint (*t_iter_ALT_func) (GimpRunMode run_mode, gint32 total_steps, gdouble current_step, gint32 len_struct); typedef struct t_iter_ALT_tab { char *proc_name; t_iter_ALT_func proc_func; } t_iter_ALT_tab; gint gap_common_iterator(const char *c_keyname, GimpRunMode run_mode, gint32 total_steps, gdouble current_step, gint32 len_struct); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_player_main.h0000644000175000017500000002042411212030253021016 0ustar thibautthibaut/* gap_player_main.h * * This module handles GAP video playback * based on thumbnail files */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.26d; 2004/01/28 hof: mtrace_mode * version 1.3.20d; 2003/10/06 hof: new gpp struct members for resize behaviour * version 1.3.19a; 2003/09/07 hof: audiosupport (based on wavplay, for UNIX only), * version 1.3.15a; 2003/06/21 hof: created */ #ifndef _GAP_PLAYER_MAIN_H #define _GAP_PLAYER_MAIN_H #include "libgimp/gimp.h" #include "gap_lib.h" #include #include #include #include "gap_pview_da.h" #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" #else #ifndef GAP_STUBTYPE_GVA_HANDLE typedef gpointer t_GVA_Handle; #define GAP_STUBTYPE_GVA_HANDLE #endif #endif #define MAX_AUDIOFILE_LEN 1024 typedef enum { GAP_PLAYER_MTRACE_OFF ,GAP_PLAYER_MTRACE_IMG_SIZE ,GAP_PLAYER_MTRACE_PV_SIZE } GapPlayerMtraceType; typedef struct GapPlayerAddClip { gpointer user_data_ptr; /* sgpp */ GapAnimInfo *ainfo_ptr; gint32 range_from; gint32 range_to; } GapPlayerAddClip; /* Function Typedefs */ typedef void (*GapPlayerSetRangeFptr)(GapPlayerAddClip *plac_ptr); #define GAP_PLAYER_DONT_FORCE_ASPECT 0.0 typedef struct GapPlayerMainGlobalParams { gboolean standalone_mode; GimpRunMode run_mode; gint32 image_id; gchar *imagename; gint32 imagewidth; gint32 imageheight; gdouble aspect_ratio; /* 0.0 use original size, else force aspect */ GapAnimInfo *ainfo_ptr; GapStoryBoard *stb_ptr; t_GVA_Handle *gvahand; gchar *gva_videofile; gint32 mtrace_image_id; /* multilayer image trace image id */ GapPlayerMtraceType mtrace_mode; /* Init GAP_PLAYER_MTRACE_OFF */ GapPlayerSetRangeFptr fptr_set_range; /* procedure to callback at set range */ gpointer user_data_ptr; /* userdata for the callback procedure */ gboolean autostart; gboolean caller_range_linked; /* propagate range selection immediate to the caller */ gboolean use_thumbnails; gboolean exact_timing; /* TRUE: allow drop frames fro exact timing, FALSE: disable drop */ gboolean play_is_active; gboolean play_selection_only; gboolean play_loop; gboolean play_pingpong; gboolean play_backward; gboolean request_cancel_video_api; gboolean cancel_video_api; gboolean gva_lock; gint32 play_timertag; gint32 begin_frame; gint32 end_frame; gint32 play_current_framenr; gint32 pb_stepsize; gdouble speed; /* playback speed fps */ gdouble original_speed; /* playback speed fps */ gdouble prev_speed; /* previous playback speed fps */ gint32 pv_pixelsize; /* 32 upto 512 */ gint32 pv_width; gint32 pv_height; /* lockflags */ gboolean in_feedback; gboolean in_timer_playback; gboolean in_resize; /* for disable resize while initial startup */ gint32 go_job_framenr; gint32 go_timertag; gint32 go_base_framenr; gint32 go_base; gint32 pingpong_count; /* GUI widget pointers */ GapPView *pv_ptr; GtkWidget *shell_window; GtkWidget *docking_container; /* NULL if not docked, or vbox to contain player */ GtkWidget *frame_with_name; GtkObject *from_spinbutton_adj; GtkObject *to_spinbutton_adj; GtkWidget *framenr_scale; GtkObject *framenr_spinbutton_adj; GtkObject *speed_spinbutton_adj; GtkObject *size_spinbutton_adj; GtkWidget *from_button; GtkWidget *to_button; GtkWidget *progress_bar; GtkWidget *status_label; GtkWidget *timepos_label; GtkWidget *resize_box; GtkWidget *size_spinbutton; GtkWidget *use_thumb_checkbutton; GtkWidget *exact_timing_checkbutton; GtkWidget *pinpong_checkbutton; GtkWidget *selonly_checkbutton; GtkWidget *loop_checkbutton; GTimer *gtimer; gdouble cycle_time_secs; gdouble rest_secs; gdouble delay_secs; gdouble framecnt; gint32 seltrack; gdouble delace; gchar *preferred_decoder; gboolean force_open_as_video; gboolean have_progress_bar; gchar *progress_bar_idle_txt; gint32 resize_handler_id; gint32 old_resize_width; gint32 old_resize_height; gboolean startup; gint32 shell_initial_width; gint32 shell_initial_height; /* audio stuff */ gboolean audio_enable; gint32 audio_resync; /* force audio brak for n frames and sync restart */ gchar audio_filename[MAX_AUDIOFILE_LEN]; gchar audio_wavfile_tmp[MAX_AUDIOFILE_LEN]; gint32 audio_frame_offset; guint32 audio_samplerate; guint32 audio_required_samplerate; guint32 audio_bits; guint32 audio_channels; guint32 audio_samples; gint32 audio_status; gdouble audio_volume; /* 0.0 upto 1.0 */ gint32 audio_tmp_samplerate; gint32 audio_tmp_samples; gboolean audio_tmp_resample; gboolean audio_tmp_dialog_is_open; GtkWidget *audio_filename_entry; GtkWidget *audio_offset_time_label; GtkWidget *audio_total_time_label; GtkWidget *audio_total_frames_label; GtkWidget *audio_samples_label; GtkWidget *audio_samplerate_label; GtkWidget *audio_bits_label; GtkWidget *audio_channels_label; GtkObject *audio_volume_spinbutton_adj; GtkObject *audio_frame_offset_spinbutton_adj; GtkWidget *audio_filesel; GtkWidget *audio_table; GtkWidget *audio_status_label; GtkWidget *video_total_time_label; GtkWidget *video_total_frames_label; gboolean vindex_creation_is_running; GtkWidget *play_n_stop_hbox; GtkWidget *cancel_vindex_button; const char *help_id; gboolean onion_delete; /* player cache settings */ GtkObject *cache_size_spinbutton_adj; GtkWidget *label_current_cache_values; GtkWidget *progress_bar_cache_usage; gint32 max_player_cache; /* max bytesize to use for caching frames * (at pview widget size) * a value of 0 turns cahing OFF */ GapPlayerCacheCompressionType cache_compression; gdouble cache_jpeg_quality; /* layout options */ gboolean show_go_buttons; gboolean show_position_scale; GtkWidget *show_go_buttons_checkbutton; GtkWidget *show_position_scale_checkbutton; GtkWidget *gobutton_hbox; GtkWidget *frame_scale_hbox; /* flags to trigger built in transformations */ gint32 flip_request; gint32 flip_status; gint32 stb_in_track; /* for playback of storyboard composite video */ gint32 stb_parttype; gint32 stb_unique_id; GapStoryRenderVidHandle *stb_comp_vidhand; /* audio otone extract stuff */ gboolean audio_auto_offset_by_framenr; gint32 audio_otone_atrack; GtkWidget *audio_auto_offset_by_framenr_checkbutton; GtkWidget *audio_otone_extract_button; GtkWidget *audio_otone_atrack_spinbutton; GtkObject *audio_otone_atrack_spinbutton_adj; GtkWidget *progress_bar_audio; GtkWidget *audio_enable_checkbutton; GapDrawableVideoRef *dvref_ptr; } GapPlayerMainGlobalParams; #define GAP_PLAYER_MAIN_AUSTAT_UNCHECKED -1 #define GAP_PLAYER_MAIN_AUSTAT_NONE 0 #define GAP_PLAYER_MAIN_AUSTAT_SERVER_STARTED 1 #define GAP_PLAYER_MAIN_AUSTAT_FILENAME_SET 2 #define GAP_PLAYER_MAIN_AUSTAT_PLAYING 3 #define GAP_PLAYER_MAIN_MIN_SAMPLERATE 1000 #define GAP_PLAYER_MAIN_MAX_SAMPLERATE 48000 #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_libgapstory.h0000644000175000017500000000247311212030253021061 0ustar thibautthibaut/* gap_libgapstory.h * 1997.11.01 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * Master includefile for the library libgapstory (Storyboard SYNTAX AND PARSER) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 2.1.0a 2004/09/12 hof: created */ #ifndef _LIBGAPSTORY_H #define _LIBGAPSTORY_H #include "libgimp/gimp.h" /* libgapstory depends on libgimpgap */ #include "gap_libgimpgap.h" #include "gap_story_file.h" #include "gap_story_processor.h" #include "gap_story_sox.h" #include "gap_story_syntax.h" #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_story_main.h0000644000175000017500000003517611212030253020714 0ustar thibautthibaut/* gap_story_main.h * * This module handles GAP storyboard level1 editing */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.25a; 2004/01/23 hof: created */ #ifndef _GAP_STORY_MAIN_H #define _GAP_STORY_MAIN_H #include "libgimp/gimp.h" #include "gap_lib.h" #include #include #include #include "gap_pview_da.h" #include "gap_story_file.h" #include "gap_story_undo_types.h" #include "gap_player_main.h" #define GAP_STORY_PLUG_IN_PROC "plug_in_gap_storyboard_edit" #define GAP_STORYBOARD_EDIT_HELP_ID "plug-in-gap-storyboard-edit" #define GAP_STORY_MAX_STORYFILENAME_LEN 2048 #define GAP_STORY_MAX_CLIP_WIDGETS 2000 #define GAP_STORY_DEFAULT_FRAMERATE 25.0 #define GAP_STORY_DEFAULT_SAMPLERATE 44100 #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 #define GAP_STB_ATT_GFX_ARRAY_MAX 2 /* max flip request and delace modes (for dimensions of radio button tables) */ #define GAP_MAX_FLIP_REQUEST 4 #define GAP_MAX_DELACE_MODES 5 typedef enum { GAP_STB_EDMO_SEQUENCE_NUMBER ,GAP_STB_EDMO_FRAME_NUMBER ,GAP_STB_EDMO_TIMECODE } GapStoryElemDisplayMode; typedef enum { GAP_STB_CLIPTARGET_CLIPLIST_APPEND ,GAP_STB_CLIPTARGET_STORYBOARD_APPEND } GapStoryClipTargetEnum; typedef enum { GAP_STB_VLIST_MOVIE ,GAP_STB_VLIST_SECTION ,GAP_STB_VLIST_ANIM_IMAGE } GapStoryVthumbEnum; typedef enum { GAP_VTHUMB_PREFETCH_NOT_ACTIVE ,GAP_VTHUMB_PREFETCH_IN_PROGRESS ,GAP_VTHUMB_PREFETCH_RESTART_REQUEST ,GAP_VTHUMB_PREFETCH_CANCEL_REQUEST ,GAP_VTHUMB_PREFETCH_PENDING } GapVThumbPrefetchProgressMode; /* video list element describes base resource that has * a unique video_id and requires (much) more than one thumbnail * per resource. * * currently supported video resource types are defined via GapStoryVthumbEnum. * * The storyboard dialog has a global video thumbnail list that keeps * all non-persistent thumbnails in memory, connected to the video list elem * by theis video_id. * * Note that other resources that are based on single images / frames * use persistent thumbnails (according to the same open thumbnail standard * as supported by the gimp) */ typedef struct GapStoryVTResurceElem { GapStoryVthumbEnum vt_type; gint32 section_id; gint32 version; gchar *video_filename; /* filename of the video or anim image, * or section_name */ gint32 seltrack; /* not relevant for * GAP_STB_VLIST_SECTION and * GAP_STB_VLIST_ANIM_IMAGE */ gint32 video_id; /* uniqie video resource id */ gint32 total_frames; /* total frames of the video resource */ void *next; } GapStoryVTResurceElem; /* video thumbnail elemnt is used in the storyboard dialog * (and clip properties dialog) */ typedef struct GapVThumbElem { guchar *th_data; gint32 th_width; gint32 th_height; gint32 th_bpp; gint32 framenr; gint32 video_id; void *next; } GapVThumbElem; typedef struct GapStbPropWidget /* nickname: pw */ { GapStoryElem *stb_elem_bck; /* backup for use at reset button pressed */ GapStoryElem *stb_elem_refptr; /* never g_free this one ! */ GapStoryBoard *stb_refptr; /* never g_free this one ! */ void *sgpp; /* never g_free this one ! */ void *tabw; /* never g_free this one ! (pointer to parent GapStbTabWidgets) */ gint32 go_job_framenr; gboolean go_render_all_request; gboolean go_recreate_request; gint32 go_timertag; gboolean scene_detection_busy; gboolean close_flag; gdouble delace_threshold; gint32 delace_mode; gint32 flip_request; GapStoryMaskAnchormode mask_anchor; GapPView *pv_ptr; /* for gap preview rendering of clip icon based on drawing_area */ GapPView *mask_pv_ptr; /* for gap preview rendering of mask icon based on drawing_area */ GtkWidget *mask_pv_container; /* holds the layermask preview (hidden when not relevant) */ GapPView *typ_icon_pv_ptr; /* for display of the clip or mask type */ GtkWidget *pw_prop_dialog; GtkWidget *pw_filesel; GtkWidget *pw_filename_entry; GtkWidget *master_table; GtkWidget *cliptype_label; GtkWidget *dur_frames_label; GtkWidget *dur_time_label; GtkWidget *pingpong_toggle; GtkWidget *comment_entry; GtkWidget *pw_fmac_filesel; GtkWidget *fmac_entry; GtkObject *pw_spinbutton_from_adj; GtkObject *pw_spinbutton_to_adj; GtkObject *pw_spinbutton_loops_adj; GtkObject *pw_spinbutton_seltrack_adj; GtkObject *pw_spinbutton_delace_adj; GtkWidget *pw_spinbutton_delace; GtkObject *pw_spinbutton_step_density_adj; GtkWidget *pw_framenr_label; GtkWidget *pw_frametime_label; GtkWidget *pw_delace_mode_radio_button_arr[GAP_MAX_DELACE_MODES]; GtkWidget *pw_flip_request_radio_button_arr[GAP_MAX_FLIP_REQUEST]; /* for mask handling */ GtkWidget *pw_mask_definition_name_label; gboolean is_mask_definition; GtkWidget *pw_mask_name_entry; /* relevant to enter mask definition */ GtkWidget *mask_name_combo; /* selected mask_name reference */ gint32 mask_name_combo_elem_count; GtkWidget *mask_anchor_label; GtkWidget *pingpong_label; GtkWidget *pw_mask_enable_toggle; GtkWidget *pw_mask_anchor_radio_button_arr[2]; GtkObject *pw_spinbutton_mask_stepsize_adj; GtkWidget *pw_spinbutton_fmac_steps; GtkObject *pw_spinbutton_fmac_steps_adj; GtkWidget *pw_label_alternate_fmac_file; struct GapStbPropWidget *next; } GapStbPropWidget; typedef struct GapStbAttrLayerInfo /* nickname: linfo */ { gboolean layer_is_fake; GapStoryRecordType layer_record_type; gint32 layer_local_framenr; gint32 layer_seltrack; gchar *layer_filename; } GapStbAttrLayerInfo; typedef struct GapStbSecpropWidget /* nickname: spw */ { GapStorySection *section_refptr; /* never g_free this one ! */ GapStoryBoard *stb_refptr; /* never g_free this one ! */ void *sgpp; /* never g_free this one ! */ void *tabw; /* never g_free this one ! (pointer to parent GapStbTabWidgets) */ GapPView *typ_icon_pv_ptr; /* for display of the section type */ GtkWidget *spw_prop_dialog; GtkWidget *spw_section_name_entry; GtkWidget *master_table; GtkWidget *cliptype_label; GtkWidget *dur_frames_label; GtkWidget *dur_time_label; GtkWidget *spw_info_text_label; GtkWidget *spw_delete_button; } GapStbSecpropWidget; /* for graphical display of transition attributes */ typedef struct GapStbAttGfx { gint32 image_id; gint32 orig_layer_id; /* invisible frame at original image size */ gint32 opre_layer_id; /* invisible prefetch frame at original image size */ gint32 deco_layer_id; /* decor layer (always on top of stack) */ gint32 curr_layer_id; /* copy of orig_layer_id, after transformations */ gint32 pref_layer_id; /* copy of opre_layer_id, after transformations (visible if overlapping is active) */ gint32 base_layer_id; /* decor layer (always BG) */ gboolean auto_update; /* information about the orig layer */ GapStbAttrLayerInfo orig_info; GapStbAttrLayerInfo opre_info; GapPView *pv_ptr; GtkWidget *auto_update_toggle; GtkWidget *framenr_label; GtkWidget *frametime_label; } GapStbAttGfx; /* widgets for one transition attribute */ typedef struct GapStbAttRow { GtkWidget *enable_toggle; GtkObject *spinbutton_from_adj; GtkObject *spinbutton_to_adj; GtkObject *spinbutton_dur_adj; GtkWidget *dur_time_label; GtkWidget *spinbutton_from; GtkWidget *spinbutton_to; GtkWidget *spinbutton_dur; GtkWidget *button_from; GtkWidget *button_to; GtkWidget *button_dur; } GapStbAttRow; typedef struct GapStbAttrWidget /* nickname: attw */ { GapStoryElem *stb_elem_bck; /* backup for use at reset button pressed */ GapStoryElem *stb_elem_refptr; /* never g_free this one ! */ GapStoryBoard *stb_refptr; /* never g_free this one ! */ void *sgpp; /* never g_free this one ! */ void *tabw; /* never g_free this one ! (pointer to parent GapStbTabWidgets) */ gint32 go_timertag; gboolean timer_full_update_request; gboolean close_flag; GtkWidget *attw_prop_dialog; GtkWidget *master_table; GtkWidget *fit_width_toggle; GtkWidget *fit_height_toggle; GtkWidget *keep_proportions_toggle; GapStbAttRow att_rows[GAP_STB_ATT_TYPES_ARRAY_MAX]; GapStbAttGfx gfx_tab[GAP_STB_ATT_GFX_ARRAY_MAX]; /* 0 .. from, 1 .. to */ GtkObject *spinbutton_overlap_dur_adj; GtkWidget *spinbutton_overlap_dur; GtkWidget *button_overlap_dur; GtkWidget *comment_entry; struct GapStbAttrWidget *next; } GapStbAttrWidget; typedef struct GapStbFrameWidget /* nickname: fw */ { GtkWidget *event_box; GtkWidget *vbox; GtkWidget *vbox2; GtkWidget *hbox; GtkWidget *key_label; /* for the 6-digit framenumber */ GtkWidget *val_label; GapPView *pv_ptr; /* for gap preview rendering based on drawing_area */ GapStoryElem *stb_elem_refptr; /* never g_free this one ! */ GapStoryBoard *stb_refptr; /* never g_free this one ! */ gint32 seq_nr; /* position in the storyboard list (starting at 1) */ char *frame_filename; void *sgpp; /* never g_free this one ! */ void *tabw; /* never g_free this one ! (pointer to parent GapStbTabWidgets) */ } GapStbFrameWidget; typedef struct GapStbTabWidgets /* nickname: tabw */ { GapStoryMasterType type; GapStbFrameWidget **fw_tab; gint32 fw_tab_size; gint32 mount_col; gint32 mount_row; gint32 cols; gint32 rows; gint32 thumbsize; gint32 thumb_width; gint32 thumb_height; gint32 rowpage; gint32 vtrack; gint32 story_id_at_prev_paste; gboolean master_dlg_open; gboolean otone_dlg_open; GtkWidget *mount_table; GtkWidget *fw_gtk_table; GtkWidget *frame_with_name; GtkWidget *total_rows_label; GtkObject *rowpage_spinbutton_adj; GtkObject *rowpage_vscale_adj; GtkWidget *rowpage_vscale; GtkWidget *vtrack_spinbutton; GtkObject *vtrack_spinbutton_adj; GtkWidget *filesel; GtkWidget *filename_entry; char *filename_refptr; /* never g_free this one ! */ gint32 filename_maxlen; GtkWidget *load_button; GtkWidget *save_button; GtkWidget *play_button; GtkWidget *undo_button; GtkWidget *redo_button; GtkWidget *edit_cut_button; GtkWidget *edit_copy_button; GtkWidget *edit_paste_button; GtkWidget *new_clip_button; GtkWidget *sections_combo; gint32 sections_combo_elem_count; /* current number element in the combo box */ GapStbPropWidget *pw; GapStbSecpropWidget *spw; GapStbAttrWidget *attw; GapStoryElemDisplayMode edmode; GapStoryUndoElem *undo_stack_list; GapStoryUndoElem *undo_stack_ptr; gdouble undo_stack_group_counter; void *sgpp; /* never g_free this one ! */ } GapStbTabWidgets; typedef struct GapStbMainGlobalParams /* nickname: sgpp */ { GimpRunMode run_mode; gboolean initialized; /* FALSE at startup */ gboolean run; gint32 image_id; gchar storyboard_filename[GAP_STORY_MAX_STORYFILENAME_LEN]; gchar cliplist_filename[GAP_STORY_MAX_STORYFILENAME_LEN]; GapStoryBoard *stb; GapStoryBoard *cll; GapStoryBoard *curr_selection; GapPlayerMainGlobalParams *plp; /* GUI widget pointers */ GapStbTabWidgets *stb_widgets; GapStbTabWidgets *cll_widgets; GapStoryVTResurceElem *video_list; GapVThumbElem *vthumb_list; t_GVA_Handle *gvahand; gchar *gva_videofile; GtkWidget *progress_bar_master; GtkWidget *progress_bar_sub; gboolean gva_lock; gboolean cancel_video_api; gboolean auto_vthumb; gboolean auto_vthumb_refresh_canceled; gboolean in_player_call; gboolean arr_dlg_open; gboolean force_stb_aspect; GapStoryClipTargetEnum clip_target; GapVThumbPrefetchProgressMode vthumb_prefetch_in_progress; /* layout values * those values are used for LAST_VALUES runmode at startup only * rendering uses the values in the tabw structures */ gboolean win_prop_dlg_open; GapStoryElemDisplayMode cll_edmode; gint32 cll_cols; gint32 cll_rows; gint32 cll_thumbsize; GapStoryElemDisplayMode stb_edmode; gint32 stb_cols; gint32 stb_rows; gint32 stb_thumbsize; /* end layout values */ GtkWidget *shell_window; GtkWidget *player_frame; GtkWidget *menu_item_win_vthumbs; GtkWidget *menu_item_stb_save; GtkWidget *menu_item_stb_save_as; GtkWidget *menu_item_stb_add_clip; GtkWidget *menu_item_stb_add_section_clip; GtkWidget *menu_item_stb_playback; GtkWidget *menu_item_stb_properties; GtkWidget *menu_item_stb_att_properties; GtkWidget *menu_item_stb_audio_otone; GtkWidget *menu_item_stb_encode; GtkWidget *menu_item_stb_undo; GtkWidget *menu_item_stb_redo; GtkWidget *menu_item_stb_close; GtkWidget *menu_item_cll_save; GtkWidget *menu_item_cll_save_as; GtkWidget *menu_item_cll_add_clip; GtkWidget *menu_item_cll_add_section_clip; GtkWidget *menu_item_cll_playback; GtkWidget *menu_item_cll_properties; GtkWidget *menu_item_cll_att_properties; GtkWidget *menu_item_cll_audio_otone; GtkWidget *menu_item_cll_encode; GtkWidget *menu_item_cll_undo; GtkWidget *menu_item_cll_redo; GtkWidget *menu_item_cll_close; GdkPixbuf *dnd_pixbuf; } GapStbMainGlobalParams; #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_audio_extract.h0000644000175000017500000000471511212030253021356 0ustar thibautthibaut/* gap_audio_extract.h * * GAP extract audio from videofile procedures * */ /* 2008.06.24 hof created (moved audio extract parts of gap_vex_exec.c to this module) */ #ifndef GAP_AUDIO_EXTRACT_H #define GAP_AUDIO_EXTRACT_H #include "config.h" /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" /* GAP includes */ #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 #include "gap-intl.h" #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* ------------------------- * gap_audio_extract_as_wav * ------------------------- * extract specified number of samples at current * position of the specified (already opened) videohandle. * and optional save extracted audiodata as RIFF WAVE file * (set wav_save to FALSE to skip writing to wav file, * this is typical used to perform dummy read for * advancing current position in the videohandle) */ void gap_audio_extract_as_wav(const char *audiofile , t_GVA_Handle *gvahand , gdouble samples_to_read , gboolean wav_save , gboolean do_progress , GtkWidget *progressBar , t_GVA_progress_callback_fptr fptr_progress_callback , gpointer user_data ); /* --------------------------------- * gap_audio_extract_from_videofile * --------------------------------- * extract the specified audiotrack to WAVE file. (name specified via audiofile) * starting at position (specified by l_pos and l_pos_unit) * in length of extracted_frames (if number of frames is exactly known) * or in length expected_frames (is a guess if l_extracted_frames < 1) * use do_progress flag value TRUE for progress feedback on the specified * progressBar. * (if progressBar = NULL gimp progress is used * this usually refers to the progress bar in the image window) * Note: * this feature is not present if compiled without GAP_ENABLE_VIDEOAPI_SUPPORT */ void gap_audio_extract_from_videofile(const char *videoname , const char *audiofile , gint32 audiotrack , const char *preferred_decoder , gint exact_seek , t_GVA_PosUnit pos_unit , gdouble pos , gdouble extracted_frames , gdouble expected_frames , gboolean do_progress , GtkWidget *progressBar , t_GVA_progress_callback_fptr fptr_progress_callback , gpointer user_data ); #endif /* GAP_ENABLE_VIDEOAPI_SUPPORT */ #endif /* end GAP_AUDIO_EXTRACT_H */ gimp-gap-2.6.0+dfsg.orig/gap/gap_player_cache.h0000644000175000017500000000722711212030253021143 0ustar thibautthibaut/* gap_player_cache.h * * This module handles frame caching for GAP video playback */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 2.2.1; 2006/05/22 hof: created */ #ifndef _GAP_PLAYER_CACHE_H #define _GAP_PLAYER_CACHE_H #define GAP_PLAYER_CACHE_FRAME_SZIE (3 * 400 * 320) #define GAP_PLAYER_CACHE_DEFAULT_MAX_BYTESIZE (200 * GAP_PLAYER_CACHE_FRAME_SZIE) #include "libgimp/gimp.h" #include "gap_lib.h" #include #include #include #include "gap_pview_da.h" #include "gap_story_file.h" typedef enum { GAP_PLAYER_CACHE_COMPRESSION_NONE ,GAP_PLAYER_CACHE_COMPRESSION_JPEG } GapPlayerCacheCompressionType; typedef enum { GAP_PLAYER_CACHE_FRAME_IMAGE ,GAP_PLAYER_CACHE_FRAME_MOVIE ,GAP_PLAYER_CACHE_FRAME_ANIMIMAGE } GapPlayerCacheFrameType; typedef struct GapPlayerCacheData { GapPlayerCacheCompressionType compression; gint32 th_data_size; guchar *th_data; gint32 th_width; gint32 th_height; gint32 th_bpp; gint32 flip_status; } GapPlayerCacheData; gint32 gap_player_cache_get_max_bytesize(void); gint32 gap_player_cache_get_current_bytes_used(void); gint32 gap_player_cache_get_current_frames_cached(void); gint32 gap_player_cache_get_gimprc_bytesize(void); void gap_player_cache_set_gimprc_bytesize(gint32 bytesize); void gap_player_cache_set_max_bytesize(gint32 max_bytesize); GapPlayerCacheData* gap_player_cache_lookup(const gchar *ckey); void gap_player_cache_insert(const gchar *ckey , GapPlayerCacheData *data); guchar* gap_player_cache_decompress(GapPlayerCacheData *cdata); GapPlayerCacheData* gap_player_cache_new_data(guchar *th_data , gint32 th_size , gint32 th_width , gint32 th_height , gint32 th_bpp , GapPlayerCacheCompressionType compression , gint32 flip_status ); gchar* gap_player_cache_new_image_key(const char *filename); gchar* gap_player_cache_new_movie_key(const char *filename , gint32 framenr , gint32 seltrack , gdouble delace ); gchar* gap_player_cache_new_composite_video_key(const char *filename , gint32 framenr , gint32 type , gint32 version); void gap_player_cache_free_all(void); void gap_player_cache_free_cdata(GapPlayerCacheData *cdata); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_mov_dialog.c0000755000175000017500000056501511212030253020646 0ustar thibautthibaut/* gap_mov_dialog.c * by hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * Dialog Window for Move Path (gap_mov) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 2.1.0b; 2004/11/04 hof: replaced deprecated option_menu by combo box * gimp 2.1.0b; 2004/08/14 hof: feature: point navigation + SHIFT ==> mov_follow_keyframe * gimp 2.1.0b; 2004/08/10 hof: bugfix save/load Pathpoints work again. * gimp 2.1.0a; 2004/06/26 hof: #144649 use NULL for the default cursor as active_cursor * gimp 2.0.1a; 2004/05/01 hof: proc: mov_dialog init mgp->drawable with temporary image (pvals->tmp_image_id) * this shows a valid copy of the dest frames at startup * (from where the move path plug-in was invoked) * gimp 2.1.0a; 2004/04/18 hof: gtk_window_present(GTK_WINDOW(filesel)) on attempt * to open an already open filesel dialog window * gimp 1.3.21d; 2003/10/29 hof: removed deprecated calls to gtk_window_set_policy * gimp 1.3.20d; 2003/10/14 hof: added bluebox filter effect * gimp 1.3.20d; 2003/10/05 hof: use gimp_image_undo_disable for internal temporary images * (for better performance and less resources) * defaults for anim preview subdialog * dynamic preview resize on window resize * gimp 1.3.20c; 2003/09/29 hof: new features: instant_apply, perspective transformation, * - tween_layer and trace_layer * - changed opacity, rotation and resize from int to gdouble * gimp 1.3.17b; 2003/07/31 hof: message text fixes for translators (# 118392) * gimp 1.3.16c; 2003/07/12 hof: removed deprecated GtkKPreview widget (replaced by drawing_area based gap_pview_da calls) * cursor crosslines ar now switchable (show_cursor flag) * gimp 1.3.15a; 2003/06/21 hof: attempt to remove some deprecated calls (no success) * gimp 1.3.14b; 2003/06/03 hof: added gap_stock_init * replaced mov_gtk_button_new_with_pixmap by gtk_button_new_from_stock * gimp 1.3.14a; 2003/05/24 hof: moved render procedures to module gap_mov_render * placed OK button right. * added pixmaps (thanks to Jakub Steiner for providing the pixmaps) * sven: replaced _gimp_help_init by gimp_ui_init * gimp 1.3.12a; 2003/05/03 hof: merge into CVS-gimp-gap project, replace gimp_help_init by _gimp_help_init * gimp 1.3.4b; 2002/03/15 hof: temp. reverted setting of preview widget size. * gimp 1.3.4; 2002/03/12 hof: ported to gtk+-2.0.0 * still needs GTK_DISABLE_DEPRECATED (port is not complete) * gimp 1.1.29b; 2000/11/30 hof: new feature: FRAME based Stepmodes, changes for NONINTERACTIVE mode * gimp 1.1.23a; 2000/06/04 hof: new button: rotation follow path * gimp 1.1.20a; 2000/04/25 hof: support for keyframes, anim_preview (suggested by jakub steiner) * gimp 1.1.17b; 2000/02/23 hof: bugfix: dont flatten the preview, just merge visible layers * bugfix: for current frame never use diskfile for the preview * (to avoid inconsitencies, and to speed up a little) * added "Show Path", pick and drag Controlpoints * gimp 1.1.17a; 2000/02/20 hof: use gimp_help_set_help_data for tooltips * added spinbuttons, and more layout cosmetics. * gimp 1.1.15a; 2000/01/26 hof: removed gimp 1.0.x support * gimp 1.1.13b; 1999/12/04 hof: some cosmetic gtk fixes * changed border_width spacing and Buttons in action area * to same style as used in dialogs of the gimp 1.1.13 main dialogs * gimp 1.1.8a; 1999/08/31 hof: accept video framenames without underscore '_' * gimp 1.1.5a; 1999/05/08 hof: call fileselect in gtk+1.2 style * version 0.99.00; 1999.03.03 hof: bugfix: update of the preview (did'nt work with gimp1.1.2) * version 0.98.00; 1998.11.28 hof: Port to GIMP 1.1: replaced buildmenu.h, apply layermask (before rotate) * mov_imglayer_constrain must check for drawable_id -1 * version 0.97.00; 1998.10.19 hof: Set window title to "Move Path" * version 0.96.02; 1998.07.30 hof: added clip to frame option and tooltips * version 0.96.00; 1998.07.09 hof: bugfix (filesel did not reopen after cancel) * version 0.95.00; 1998.05.12 hof: added rotatation capabilities * version 0.94.00; 1998.04.25 hof: use only one point as default * bugfix: initial value for src_paintmode * fixes the problem reported in gap_layer_copy_to_dest_image (can't get new layer) * version 0.90.00; 1997.12.14 hof: 1.st (pre) release */ #include "config.h" #define MOVE_PATH_LAYOUT_BIG_PREVIEW /* if defined MOVE_PATH_LAYOUT_BIG_PREVIEW use layout with bigger initial preview size * and with frame range selection widget group at right side of the preview * * the other layout variante has the range selection widget group under the preview * (maybe this will be a configure option later) */ /* SYTEM (UNIX) includes */ #include #include #include #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "gap-intl.h" #include "libgimp/gimp.h" #include "libgimp/gimpui.h" /* GAP includes */ #include "gap_libgapbase.h" #include "gap_layer_copy.h" #include "gap_lib.h" #include "gap_image.h" #include "gap_mov_exec.h" #include "gap_mov_dialog.h" #include "gap_mov_render.h" #include "gap_pdb_calls.h" #include "gap_vin.h" #include "gap_arr_dialog.h" #include "gap_pview_da.h" #include "gap_stock.h" extern int gap_debug; /* ==0 ... dont print debug infos */ /* Some useful defines and macros */ #define GAP_MOVE_PATH_HELP_ID "plug-in-gap-move-path" #define ENTRY_WIDTH 60 #define SPINBUTTON_WIDTH 60 #define SCALE_WIDTH 125 /* instant apply is implemented via timer, configured to fire 10 times per second (100 msec) * this collects instant_apply_requests set by other widget callbacks and events * and then update only once. * The timer is completely removed, when instant_apply is OFF * instant_apply requires much CPU and IO power especially on big images * and images with many layers */ #define INSTANT_TIMERINTERVAL_MILLISEC 100 #ifdef MOVE_PATH_LAYOUT_BIG_PREVIEW #define PREVIEW_SIZE 340 #else #define PREVIEW_SIZE 256 #endif #define RADIUS 3 #define PREVIEW 0x1 #define CURSOR 0x2 #define PATH_LINE 0x4 #define ALL 0xf #define GAP_MOV_CHECK_SIZE 8 /* event masks for the preview widget */ #define PREVIEW_MASK GDK_EXPOSURE_MASK | \ GDK_BUTTON_PRESS_MASK |\ GDK_BUTTON_RELEASE_MASK |\ GDK_BUTTON_MOTION_MASK #define POINT_INDEX_LABEL_LENGTH 256 typedef struct { gint run; } t_mov_interface; typedef struct { GimpDrawable *drawable; gint dwidth, dheight; gint bpp; GapPView *pv_ptr; GimpPixelRgn src_rgn; gint show_path; gint show_cursor; gint show_grid; gint instant_apply; gboolean instant_apply_request; gint32 instant_timertag; gint startup; gint pwidth, pheight; gint curx, cury; /* x,y of cursor in preview */ GtkWidget *filesel; GtkAdjustment *x_adj; GtkAdjustment *y_adj; GtkAdjustment *wres_adj; GtkAdjustment *hres_adj; GtkAdjustment *opacity_adj; GtkAdjustment *rotation_adj; GtkAdjustment *keyframe_adj; GtkAdjustment *preview_frame_nr_adj; GtkWidget *src_layer_combo; GtkWidget *constrain; /* scale width/height keeps ratio constant */ GtkAdjustment *ttlx_adj; GtkAdjustment *ttly_adj; GtkAdjustment *ttrx_adj; GtkAdjustment *ttry_adj; GtkAdjustment *tblx_adj; GtkAdjustment *tbly_adj; GtkAdjustment *tbrx_adj; GtkAdjustment *tbry_adj; GtkAdjustment *sel_feather_radius_adj; GtkAdjustment *step_speed_factor_adj; GtkAdjustment *tween_opacity_initial_adj; GtkAdjustment *tween_opacity_desc_adj; GtkAdjustment *trace_opacity_initial_adj; GtkAdjustment *trace_opacity_desc_adj; GtkAdjustment *tween_steps_adj; gchar point_index_text[POINT_INDEX_LABEL_LENGTH]; GtkWidget *point_index_frame; gint p_x, p_y; gdouble opacity; gdouble w_resize; gdouble h_resize; gdouble rotation; gdouble ttlx; /* 0.0 upto 10.0 transform x top left */ gdouble ttly; /* 0.0 upto 10.0 transform y top left */ gdouble ttrx; /* 0.0 upto 10.0 transform x top right */ gdouble ttry; /* 0.0 upto 10.0 transform y top right */ gdouble tblx; /* 0.0 upto 10.0 transform x bot left */ gdouble tbly; /* 0.0 upto 10.0 transform y bot left */ gdouble tbrx; /* 0.0 upto 10.0 transform x bot right */ gdouble tbry; /* 0.0 upto 10.0 transform y bot right */ gdouble sel_feather_radius; gint keyframe_abs; gint max_frame; gint preview_frame_nr; /* default: current frame */ gint old_preview_frame_nr; GapAnimInfo *ainfo_ptr; gint in_call; char *pointfile_name; gint first_nr; gint last_nr; GtkWidget *shell; gint shell_initial_width; gint shell_initial_height; GtkWidget *master_vbox; GdkCursor *cursor_wait; GdkCursor *cursor_acitve; GimpRGB pathcolor; } t_mov_gui_stuff; /* Declare a local function. */ long gap_mov_dlg_move_dialog (GapMovData *mov_ptr); static void p_update_point_index_text (t_mov_gui_stuff *mgp); static void p_points_from_tab (t_mov_gui_stuff *mgp); static void p_points_to_tab (t_mov_gui_stuff *mgp); static void p_point_refresh (t_mov_gui_stuff *mgp); static void p_pick_nearest_point (gint px, gint py); static void p_reset_points (); static void p_clear_one_point (gint idx); static void p_mix_one_point(gint idx, gint ref1, gint ref2, gdouble mix_factor); static void p_load_points (char *filename); static void p_save_points (char *filename, t_mov_gui_stuff *mgp); static GimpDrawable * p_get_flattened_drawable (gint32 image_id); static GimpDrawable * p_get_prevw_drawable (t_mov_gui_stuff *mgp); static gint mov_dialog ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gint min, gint max); static GtkWidget * mov_modify_tab_create (t_mov_gui_stuff *mgp); static GtkWidget * mov_trans_tab_create (t_mov_gui_stuff *mgp); static GtkWidget * mov_selection_handling_tab_create (t_mov_gui_stuff *mgp); static void mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean vertical_layout); static void mov_refresh_src_layer_menu(t_mov_gui_stuff *mgp); static GtkWidget * mov_src_sel_create (t_mov_gui_stuff *mgp); static GtkWidget * mov_advanced_tab_create(t_mov_gui_stuff *mgp); static GtkWidget * mov_edit_button_box_create (t_mov_gui_stuff *mgp); static GtkWidget * mov_path_framerange_box_create(t_mov_gui_stuff *mgp, gboolean vertical_layout ); static void mov_path_prevw_preview_init ( t_mov_gui_stuff *mgp ); static void mov_path_prevw_draw ( t_mov_gui_stuff *mgp, gint update ); static void mov_instant_int_adjustment_update (GtkObject *obj, gpointer val); static void mov_instant_double_adjustment_update (GtkObject *obj, gpointer val); static void mov_path_colorbutton_update ( GimpColorButton *widget, t_mov_gui_stuff *mgp); static void mov_path_keycolorbutton_clicked ( GimpColorButton *widget, t_mov_gui_stuff *mgp); static void mov_path_keycolorbutton_changed ( GimpColorButton *widget, t_mov_gui_stuff *mgp); static void mov_path_x_adjustment_update ( GtkWidget *widget, gpointer data ); static void mov_path_y_adjustment_update ( GtkWidget *widget, gpointer data ); static void mov_path_tfactor_adjustment_update( GtkWidget *widget, gdouble *val); static void mov_path_feather_adjustment_update( GtkWidget *widget, gdouble *val ); static void mov_selmode_menu_callback (GtkWidget *widget, t_mov_gui_stuff *mgp); static void mov_path_resize_adjustment_update( GtkObject *obj, gdouble *val); static void mov_path_tween_steps_adjustment_update( GtkObject *obj, gint *val); static void mov_path_prevw_cursor_update ( t_mov_gui_stuff *mgp ); static gint mov_path_prevw_preview_expose ( GtkWidget *widget, GdkEvent *event ); static gint mov_path_prevw_preview_events ( GtkWidget *widget, GdkEvent *event ); static gint p_chk_keyframes(t_mov_gui_stuff *mgp); static void mov_grab_bezier_path(t_mov_gui_stuff *mgp , gint32 vectors_id , gint32 stroke_id , const char *vectorname ); static void mov_grab_anchorpoints_path(t_mov_gui_stuff *mgp ,gint num_path_point_details ,gdouble *points_details ); static void mov_padd_callback (GtkWidget *widget,gpointer data); static void mov_pgrab_callback (GtkWidget *widget,GdkEventButton *bevent,gpointer data); static void mov_pins_callback (GtkWidget *widget,gpointer data); static void mov_pdel_callback (GtkWidget *widget,gpointer data); static void mov_follow_keyframe (t_mov_gui_stuff *mgp); static void mov_pnext_callback (GtkWidget *widget,GdkEventButton *bevent,gpointer data); static void mov_pprev_callback (GtkWidget *widget,GdkEventButton *bevent,gpointer data); static void mov_pfirst_callback (GtkWidget *widget,GdkEventButton *bevent,gpointer data); static void mov_plast_callback (GtkWidget *widget,GdkEventButton *bevent,gpointer data); static void mov_pdel_all_callback (GtkWidget *widget,gpointer data); static void mov_pclr_callback (GtkWidget *widget,gpointer data); static void mov_pclr_all_callback (GtkWidget *widget,GdkEventButton *bevent,gpointer data); static void mov_prot_follow_callback (GtkWidget *widget,GdkEventButton *bevent,gpointer data); static void mov_pload_callback (GtkWidget *widget,gpointer data); static void mov_psave_callback (GtkWidget *widget,gpointer data); static void p_points_load_from_file (GtkWidget *widget,t_mov_gui_stuff *mgp); static void p_points_save_to_file (GtkWidget *widget,t_mov_gui_stuff *mgp); static gboolean mov_check_valid_src_layer(t_mov_gui_stuff *mgp); static void mov_help_callback (GtkWidget *widget, t_mov_gui_stuff *mgp); static void mov_close_callback (GtkWidget *widget, t_mov_gui_stuff *mgp); static void mov_ok_callback (GtkWidget *widget, t_mov_gui_stuff *mgp); static void mov_upvw_callback (GtkWidget *widget, t_mov_gui_stuff *mgp); static void mov_apv_callback (GtkWidget *widget,gpointer data); static void p_filesel_close_cb (GtkWidget *widget, t_mov_gui_stuff *mgp); static gint mov_imglayer_constrain (gint32 image_id, gint32 drawable_id, gpointer data); static void mov_imglayer_menu_callback (GtkWidget *, t_mov_gui_stuff *mgp); static void mov_paintmode_menu_callback (GtkWidget *, t_mov_gui_stuff *mgp); static void mov_handmode_menu_callback (GtkWidget *, t_mov_gui_stuff *mgp); static void mov_stepmode_menu_callback (GtkWidget *, t_mov_gui_stuff *mgp); static void mov_tweenlayer_sensitivity(t_mov_gui_stuff *mgp); static void mov_tracelayer_sensitivity(t_mov_gui_stuff *mgp); static void mov_gint_toggle_callback (GtkWidget *, gpointer); static void mov_force_visibility_toggle_callback ( GtkWidget *widget, gpointer data ); static void mov_bluebox_callback (GtkWidget *, gpointer); static void mov_tracelayer_callback (GtkWidget *, gpointer); static void mov_show_path_or_cursor (t_mov_gui_stuff *mgp); static void mov_show_path_callback (GtkWidget *, t_mov_gui_stuff *mgp); static void mov_show_cursor_callback (GtkWidget *, t_mov_gui_stuff *mgp); static void mov_show_grid_callback (GtkWidget *, t_mov_gui_stuff *mgp); static void mov_install_timer (t_mov_gui_stuff *mgp); static void mov_remove_timer (t_mov_gui_stuff *mgp); static void mov_instant_timer_callback (gpointer user_data); static void mov_instant_apply_callback (GtkWidget *, t_mov_gui_stuff *mgp); static void mov_set_instant_apply_request(t_mov_gui_stuff *mgp); static void mov_set_waiting_cursor (t_mov_gui_stuff *mgp); static void mov_set_active_cursor (t_mov_gui_stuff *mgp); GtkObject * p_mov_spinbutton_new(GtkTable *table ,gint col ,gint row ,gchar *label_text ,gint scale_width /* dummy, not used */ ,gint spinbutton_width ,gdouble initial_val ,gdouble lower /* dummy, not used */ ,gdouble upper /* dummy, not used */ ,gdouble sstep ,gdouble pagestep ,gint digits ,gboolean constrain ,gdouble umin ,gdouble umax ,gchar *tooltip_text ,gchar *privatetip ); static void mov_fit_initial_shell_window(t_mov_gui_stuff *mgp); static void mov_shell_window_size_allocate (GtkWidget *widget, GtkAllocation *allocation, gpointer user_data); static void mov_pview_size_allocate_callback(GtkWidget *widget , GtkAllocation *allocation , t_mov_gui_stuff *mgp ); static GapMovValues *pvals; static t_mov_interface mov_int = { FALSE /* run */ }; /* ============================================================================ ********************** * * * Dialog interface * * * ********************** * ============================================================================ */ long gap_mov_dlg_move_dialog (GapMovData *mov_ptr) { GimpDrawable *l_drawable_ptr; gint l_first, l_last; char *l_str; t_mov_gui_stuff *mgp; if(gap_debug) printf("GAP-DEBUG: START gap_mov_dlg_move_dialog\n"); mgp = g_new( t_mov_gui_stuff, 1 ); if(mgp == NULL) { printf("error can't alloc path_preview structure\n"); return -1; } mgp->shell_initial_width = -1; mgp->shell_initial_height = -1; mgp->show_path = TRUE; mgp->show_cursor = TRUE; mgp->show_grid = FALSE; mgp->instant_apply = FALSE; mgp->instant_apply_request = FALSE; mgp->instant_timertag = -1; mgp->startup = TRUE; mgp->keyframe_adj = NULL; mgp->preview_frame_nr_adj = NULL; mgp->pv_ptr = NULL; mgp->cursor_wait = gdk_cursor_new (GDK_WATCH); mgp->cursor_acitve = NULL; /* use the default cursor */ mgp->step_speed_factor_adj = NULL; mgp->tween_opacity_initial_adj = NULL; mgp->tween_opacity_desc_adj = NULL; mgp->trace_opacity_initial_adj = NULL; mgp->sel_feather_radius_adj = NULL; pvals = mov_ptr->val_ptr; l_str = gap_base_strdup_del_underscore(mov_ptr->dst_ainfo_ptr->basename); mgp->pointfile_name = g_strdup_printf("%s.path_points", l_str); g_free(l_str); l_first = mov_ptr->dst_ainfo_ptr->first_frame_nr; l_last = mov_ptr->dst_ainfo_ptr->last_frame_nr; /* init parameter values */ pvals->dst_image_id = mov_ptr->dst_ainfo_ptr->image_id; pvals->tmp_image_id = -1; pvals->tmpsel_image_id= -1; pvals->tmpsel_channel_id = -1; pvals->tmp_alt_image_id = -1; pvals->tmp_alt_framenr = -1; pvals->tween_image_id = -1; pvals->trace_image_id = -1; pvals->src_image_id = -1; pvals->src_layer_id = -1; pvals->src_paintmode = GIMP_NORMAL_MODE; pvals->src_handle = GAP_HANDLE_LEFT_TOP; pvals->src_stepmode = GAP_STEP_LOOP; pvals->src_selmode = GAP_MOV_SEL_IGNORE; pvals->src_force_visible = 1; pvals->src_apply_bluebox = 0; pvals->bbp = NULL; pvals->bbp_pv = NULL; pvals->clip_to_img = 0; pvals->step_speed_factor = 1.0; pvals->tracelayer_enable = FALSE; pvals->trace_opacity_initial = 100.0; pvals->trace_opacity_desc = 80.0; pvals->tween_steps = 0; pvals->tween_opacity_initial = 80.0; pvals->tween_opacity_desc = 80.0; pvals->apv_mode = GAP_APV_QUICK; pvals->apv_src_frame = -1; pvals->apv_mlayer_image = -1; pvals->apv_gap_paste_buff = NULL; pvals->apv_scalex = 40.0; pvals->apv_scaley = 40.0; pvals->cache_src_image_id = -1; pvals->cache_tmp_image_id = -1; pvals->cache_tmp_layer_id = -1; pvals->cache_frame_number = -1; pvals->cache_ainfo_ptr = NULL; p_reset_points(); /* pvals->point[1].p_x = 100; */ /* default: move from 0/0 to 100/0 */ pvals->dst_range_start = mov_ptr->dst_ainfo_ptr->curr_frame_nr; pvals->dst_range_end = l_last; pvals->dst_layerstack = 0; /* 0 ... insert layer on top of stack */ mgp->filesel = NULL; /* fileselector is not open */ mgp->ainfo_ptr = mov_ptr->dst_ainfo_ptr; mgp->preview_frame_nr = mov_ptr->dst_ainfo_ptr->curr_frame_nr; mgp->old_preview_frame_nr = mgp->preview_frame_nr; mgp->point_index_frame = NULL; p_points_from_tab(mgp); p_update_point_index_text(mgp); /* duplicate the curerent image (for flatten & preview) */ pvals->tmp_image_id = gimp_image_duplicate(pvals->dst_image_id); /* wanted to disable undo for performance reasons * but if this is done here, the initial preview is black * and get error (gap_main:######): LibGimp-CRITICAL **: file gimppixelrgn.c: line 268 (gimp_pixel_ * TODO: findout why, then try disable undo again */ /* gimp_image_undo_disable(pvals->tmp_image_id); */ /* flatten image, and get the (only) resulting drawable */ l_drawable_ptr = p_get_prevw_drawable(mgp); /* do DIALOG window */ mov_dialog(l_drawable_ptr, mgp, l_first, l_last); p_points_to_tab(mgp); /* destroy the tmp image(s) */ gimp_image_delete(pvals->tmp_image_id); if(pvals->tmp_alt_image_id >= 0) { gimp_image_delete(pvals->tmp_alt_image_id); } /* delete the temp selection image */ if(gap_image_is_alive(pvals->tmpsel_image_id)) { gimp_image_delete(pvals->tmpsel_image_id); } pvals->tmpsel_image_id = -1; pvals->tmpsel_channel_id = -1; /* remove timer if there is one */ mov_remove_timer(mgp); g_free(mgp); if(gap_debug) printf("GAP-DEBUG: END gap_mov_dlg_move_dialog\n"); if(mov_int.run == TRUE) return 0; else return -1; } /* ============================================================================ ******************* * * * Main Dialog * * * ******************* * ============================================================================ */ static gint mov_dialog ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gint first_nr, gint last_nr ) { GtkWidget *notebook; GtkWidget *vbox; GtkWidget *hbbox; GtkWidget *spc_hbox; GtkWidget *dlg; GtkWidget *frame; GtkWidget *button; GtkWidget *label; GtkWidget *src_sel_frame; GtkWidget *advanced_frame; GtkWidget *framerange_table; gboolean vertical_layout; if(gap_debug) printf("GAP-DEBUG: START mov_dialog\n"); gimp_ui_init ("gap_move", FALSE); gap_stock_init(); #ifdef MOVE_PATH_LAYOUT_BIG_PREVIEW vertical_layout = TRUE; #else vertical_layout = FALSE; #endif /* dialog */ dlg = gtk_dialog_new (); gtk_window_set_type_hint (dlg, GDK_WINDOW_TYPE_HINT_NORMAL); mgp->shell = dlg; mgp->first_nr = first_nr; mgp->last_nr = last_nr; gtk_window_set_title (GTK_WINDOW (dlg), _("Move Path")); gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE); g_signal_connect (G_OBJECT (dlg), "destroy", G_CALLBACK (mov_close_callback), mgp); gtk_window_set_resizable(GTK_WINDOW (mgp->shell), TRUE); /* Action area */ gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dlg)->action_area), 2); gtk_box_set_homogeneous (GTK_BOX (GTK_DIALOG (dlg)->action_area), FALSE); hbbox = gtk_hbutton_box_new (); gtk_box_set_spacing (GTK_BOX (hbbox), 2); gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dlg)->action_area), hbbox, FALSE, FALSE, 0); gtk_widget_show (hbbox); /* the HELP button */ if (gimp_show_help_button ()) { button = gtk_button_new_from_stock ( GTK_STOCK_HELP); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_box_pack_end (GTK_BOX (hbbox), button, FALSE, TRUE, 0); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK(mov_help_callback), mgp); } /* the CANCEL button */ button = gtk_button_new_from_stock ( GTK_STOCK_CANCEL); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (hbbox), button, TRUE, TRUE, 0); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK(mov_close_callback), mgp); /* button = gtk_button_new_with_label */ button = gtk_button_new_from_stock ( GTK_STOCK_REFRESH ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (hbbox), button, TRUE, TRUE, 0); gimp_help_set_help_data(button, _("Show preview frame with selected source layer at current controlpoint") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (mov_upvw_callback), mgp); button = gtk_button_new_from_stock ( GAP_STOCK_ANIM_PREVIEW ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (hbbox), button, TRUE, TRUE, 0); gimp_help_set_help_data(button, _("Generate animated preview as multilayer image") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (mov_apv_callback), mgp); button = gtk_button_new_from_stock ( GTK_STOCK_OK); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (hbbox), button, TRUE, TRUE, 0); gtk_widget_grab_default (button); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (mov_ok_callback), mgp); /* parameter settings */ spc_hbox = gtk_hbox_new (FALSE, 0); gtk_widget_show (spc_hbox); frame = gimp_frame_new ( _("Copy moving source-layer(s) into frames")); gtk_widget_show (frame); gtk_box_pack_start (GTK_BOX (spc_hbox), frame, TRUE, TRUE, 10); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), spc_hbox, TRUE, TRUE, 2); /* the vbox */ vbox = gtk_vbox_new (FALSE, 3); gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); gtk_container_add (GTK_CONTAINER (frame), vbox); gtk_widget_show (vbox); /* the notebook */ notebook = gtk_notebook_new(); { GtkWidget *hbox; hbox = gtk_hbox_new (FALSE, 3); gtk_widget_show (hbox); gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 4); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); } /* the source select frame */ src_sel_frame = mov_src_sel_create (mgp); gtk_container_add (GTK_CONTAINER (notebook), src_sel_frame); label = gtk_label_new(_("Source Select")); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook) , gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 0) , label ); /* the advanced features frame */ advanced_frame = mov_advanced_tab_create(mgp); gtk_container_add (GTK_CONTAINER (notebook), advanced_frame); label = gtk_label_new(_("Advanced Settings")); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook) , gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 1) , label ); gtk_widget_show (notebook); /* the path preview frame (with all the controlpoint widgets) */ mgp->max_frame = MAX(first_nr, last_nr); mgp->master_vbox = vbox; mov_path_prevw_create ( drawable, mgp, vertical_layout); if(!vertical_layout) { /* the box with the framerange selection widgets * (if we have vertical_layout using the BIG Preview * the framerange_table was already done in the mov_path_prevw_create procedure, * otherwise we have to create it now) */ framerange_table = mov_path_framerange_box_create(mgp, vertical_layout); gtk_box_pack_start (GTK_BOX (vbox), framerange_table, FALSE, FALSE, 0); } gtk_widget_show (dlg); gtk_widget_realize(mgp->shell); mgp->startup = FALSE; gap_pview_set_size(mgp->pv_ptr , mgp->pwidth , mgp->pheight , GAP_MOV_CHECK_SIZE ); /* init drawable for preview rendering * (at startup this is a copy of the frame from where we were invoked) */ if(pvals->tmp_image_id >= 0) { mgp->drawable = p_get_flattened_drawable(pvals->tmp_image_id); } mov_path_prevw_preview_init(mgp); mov_show_path_or_cursor(mgp); g_signal_connect (G_OBJECT (mgp->shell), "size_allocate", G_CALLBACK (mov_shell_window_size_allocate), mgp); gtk_main (); gdk_flush (); if(gap_debug) printf("GAP-DEBUG: END mov_dialog\n"); return mov_int.run; } /* end mov_dialog */ static gboolean mov_check_valid_src_layer(t_mov_gui_stuff *mgp) { if(mgp->startup) { return(FALSE); } if(pvals->src_layer_id < 0) { g_message(_("No source image was selected.\n" "Please open a 2nd image of the same type before opening 'Move Path'")); return(FALSE); } return(TRUE); } /* end mov_check_valid_src_layer */ /* ============================================================================ * implementation of CALLBACK procedures * ============================================================================ */ static void mov_help_callback (GtkWidget *widget, t_mov_gui_stuff *mgp) { if(gap_debug) printf("mov_help_callback:\n"); gimp_standard_help_func(GAP_MOVE_PATH_HELP_ID, mgp->shell); } /* end mov_help_callback */ static void mov_close_callback (GtkWidget *widget, t_mov_gui_stuff *mgp) { if(mgp) { mov_remove_timer(mgp); if(mgp->shell) { GtkWidget *l_shell; l_shell = mgp->shell; mgp->shell = NULL; /* mov_close_callback is the signal handler for the "destroy" * signal of the shell window. * the gtk_widget_destroy call will immediate reenter this procedure. * (for this reason the mgp->shell is set to NULL * before the gtk_widget_destroy call) */ gtk_widget_destroy (l_shell); } } gtk_main_quit (); } /* end mov_close_callback */ static void mov_ok_callback (GtkWidget *widget, t_mov_gui_stuff *mgp) { if(pvals != NULL) { if(!mov_check_valid_src_layer(mgp)) { return; } } if(!p_chk_keyframes(mgp)) { return; } mov_int.run = TRUE; if(pvals->point_idx_max == 0) { /* if we have only one point duplicate that point * (move algorithm needs at least 2 points) */ mov_padd_callback(NULL, mgp); } mov_close_callback(mgp->shell, mgp); } /* end mov_ok_callback */ /* --------------------------- * mov_upvw_callback * --------------------------- * this callback does completely draw the preview */ static void mov_upvw_callback (GtkWidget *widget, t_mov_gui_stuff *mgp) { char *l_filename; long l_frame_nr; gint32 l_new_tmp_image_id; gint32 l_old_tmp_image_id; if(gap_debug) printf("mov_upvw_callback nr: %d old_nr: %d\n", (int)mgp->preview_frame_nr , (int)mgp->old_preview_frame_nr); l_frame_nr = (long)mgp->preview_frame_nr; l_filename = gap_lib_alloc_fname(mgp->ainfo_ptr->basename, l_frame_nr, mgp->ainfo_ptr->extension); if(l_filename != NULL) { if(!mgp->instant_apply) { /* dont show waiting cursor at instant_apply * (cursor flickering is boring on fast machines, * and users with slow machines should not touch instant_apply at all) */ mov_set_waiting_cursor(mgp); } /* replace the temporary image */ if(mgp->preview_frame_nr == mgp->ainfo_ptr->curr_frame_nr) { l_new_tmp_image_id = gimp_image_duplicate(mgp->ainfo_ptr->image_id); } else { if((pvals->tmp_alt_image_id >= 0) && (pvals->tmp_alt_framenr == l_frame_nr)) { /* we can reuse the cached frame image */ l_new_tmp_image_id = gimp_image_duplicate(pvals->tmp_alt_image_id); } else { if(pvals->tmp_alt_image_id >= 0) { gimp_image_delete(pvals->tmp_alt_image_id); pvals->tmp_alt_image_id = -1; pvals->tmp_alt_framenr = -1; } /* we must load a frame for preview update */ l_new_tmp_image_id = gap_lib_load_image(l_filename); /* keep a copy of the frame to speed up further (instant) updates */ pvals->tmp_alt_image_id = gimp_image_duplicate(l_new_tmp_image_id); pvals->tmp_alt_framenr = l_frame_nr; } } gimp_image_undo_disable(l_new_tmp_image_id); g_free(l_filename); if (l_new_tmp_image_id >= 0) { /* use the new loaded temporary image */ l_old_tmp_image_id = pvals->tmp_image_id; pvals->tmp_image_id = l_new_tmp_image_id; /* flatten image, and get the (only) resulting drawable */ mgp->drawable = p_get_prevw_drawable(mgp); /* gimp_display_new(pvals->tmp_image_id); */ /* add a display for debugging only */ /* re initialize preview image */ mov_path_prevw_preview_init(mgp); p_point_refresh(mgp); mgp->old_preview_frame_nr = mgp->preview_frame_nr; gtk_widget_queue_draw(mgp->pv_ptr->da_widget); mov_path_prevw_draw ( mgp, CURSOR | PATH_LINE ); gdk_flush(); /* destroy the old tmp image */ gimp_image_delete(l_old_tmp_image_id); mgp->instant_apply_request = FALSE; } mov_set_active_cursor(mgp); } } /* end mov_upvw_callback */ static void mov_apv_callback (GtkWidget *widget, gpointer data) { #define ARGC_APV 5 t_mov_gui_stuff *mgp; GapVinVideoInfo *vin_ptr; static gint apv_locked = FALSE; gint32 l_new_image_id; GimpParam *return_vals; int nreturn_vals; gint l_rc; static GapArrArg argv[ARGC_APV]; static char *radio_apv_mode[3] = { N_("Object on empty frames") , N_("Object on one frame") , N_("Exact object on frames") }; static int gettextize_loop = 0; mgp = data; if(!p_chk_keyframes(mgp)) { return; } if(apv_locked) { return; } apv_locked = TRUE; if(gap_debug) printf("mov_apv_callback preview_frame_nr: %d\n", (int)mgp->preview_frame_nr); for (;gettextize_loop < 3; gettextize_loop++) { radio_apv_mode[gettextize_loop] = gettext(radio_apv_mode[gettextize_loop]); } gap_arr_arg_init(&argv[0], GAP_ARR_WGT_RADIO); argv[0].label_txt = _("Anim Preview Mode:"); argv[0].help_txt = NULL; argv[0].radio_argc = 3; argv[0].radio_argv = radio_apv_mode; argv[0].radio_ret = 0; argv[0].has_default = TRUE; argv[0].radio_default = 0; switch(pvals->apv_mode) { case GAP_APV_EXACT: argv[0].radio_ret = 2; break; case GAP_APV_ONE_FRAME: argv[0].radio_ret = 1; break; default: argv[0].radio_ret = 0; break; } gap_arr_arg_init(&argv[1], GAP_ARR_WGT_FLT_PAIR); argv[1].constraint = TRUE; argv[1].label_txt = _("Scale Preview:"); argv[1].help_txt = _("Scale down size of the generated animated preview (in %)"); argv[1].flt_min = 5.0; argv[1].flt_max = 100.0; argv[1].flt_step = 1.0; argv[1].flt_ret = pvals->apv_scalex; argv[1].has_default = TRUE; argv[1].flt_default = 40; gap_arr_arg_init(&argv[2], GAP_ARR_WGT_FLT_PAIR); argv[2].constraint = TRUE; argv[2].label_txt = _("Framerate:"); argv[2].help_txt = _("Framerate to use in the animated preview in frames/sec"); argv[2].flt_min = 1.0; argv[2].flt_max = 100.0; argv[2].flt_step = 1.0; argv[2].flt_ret = 24; vin_ptr = gap_vin_get_all(mgp->ainfo_ptr->basename); if(vin_ptr) { if(vin_ptr->framerate > 0) argv[2].flt_ret = vin_ptr->framerate; g_free(vin_ptr); } argv[2].has_default = TRUE; argv[2].flt_default = argv[2].flt_ret; gap_arr_arg_init(&argv[3], GAP_ARR_WGT_TOGGLE); argv[3].label_txt = _("Copy to Video Buffer:"); argv[3].help_txt = _("Save all single frames of animated preview to video buffer." "(configured in gimprc by video-paste-dir and video-paste-basename)"); argv[3].int_ret = 0; argv[3].has_default = TRUE; argv[3].int_default = 0; gap_arr_arg_init(&argv[4], GAP_ARR_WGT_DEFAULT_BUTTON); argv[4].label_txt = _("Default"); argv[4].help_txt = _("Reset all parameters to default values"); l_rc = gap_arr_ok_cancel_dialog( _("Move Path Animated Preview"), _("Options"), ARGC_APV, argv); /* quit if MovePath Mainwindow was closed */ if(mgp->shell == NULL) { gtk_main_quit(); return; } if(l_rc) { switch(argv[0].radio_ret) { case 2: pvals->apv_mode = GAP_APV_EXACT; break; case 1: pvals->apv_mode = GAP_APV_ONE_FRAME; break; default: pvals->apv_mode = GAP_APV_QUICK; break; } pvals->apv_scalex = argv[1].flt_ret; pvals->apv_scaley = argv[1].flt_ret; pvals->apv_framerate = argv[2].flt_ret; if(argv[3].int_ret) { pvals->apv_gap_paste_buff = gap_lib_get_video_paste_name(); gap_vid_edit_clear(); } else { pvals->apv_gap_paste_buff = NULL; } if(gap_debug) printf("Generating Animated Preview\n"); /* TODO: here we should start a thread for calculate and playback of the anim preview, * so the move_path main window is not blocked until playback exits */ p_points_to_tab(mgp); if(!p_chk_keyframes(mgp)) { return; } mov_set_waiting_cursor(mgp); l_new_image_id = gap_mov_exec_anim_preview(pvals, mgp->ainfo_ptr, mgp->preview_frame_nr); if(l_new_image_id < 0) { gap_arr_msg_win(GIMP_RUN_INTERACTIVE, _("Generation of animated preview failed")); } else { gint32 dummy_layer_id; dummy_layer_id = gap_image_get_any_layer(l_new_image_id); mov_set_waiting_cursor(mgp); /* for refresh */ return_vals = gimp_run_procedure ("plug_in_animationplay", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, l_new_image_id, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_END); gimp_destroy_params(return_vals, nreturn_vals); } pvals->apv_mlayer_image = -1; mov_set_active_cursor(mgp); } apv_locked = FALSE; } /* end mov_apv_callback */ static void p_copy_point(gint to_idx, gint from_idx) { pvals->point[to_idx].p_x = pvals->point[from_idx].p_x; pvals->point[to_idx].p_y = pvals->point[from_idx].p_y; pvals->point[to_idx].opacity = pvals->point[from_idx].opacity; pvals->point[to_idx].w_resize = pvals->point[from_idx].w_resize; pvals->point[to_idx].h_resize = pvals->point[from_idx].h_resize; pvals->point[to_idx].rotation = pvals->point[from_idx].rotation; pvals->point[to_idx].ttlx = pvals->point[from_idx].ttlx; pvals->point[to_idx].ttly = pvals->point[from_idx].ttly; pvals->point[to_idx].ttrx = pvals->point[from_idx].ttrx; pvals->point[to_idx].ttry = pvals->point[from_idx].ttry; pvals->point[to_idx].tblx = pvals->point[from_idx].tblx; pvals->point[to_idx].tbly = pvals->point[from_idx].tbly; pvals->point[to_idx].tbrx = pvals->point[from_idx].tbrx; pvals->point[to_idx].tbry = pvals->point[from_idx].tbry; pvals->point[to_idx].sel_feather_radius = pvals->point[from_idx].sel_feather_radius; /* do not copy keyframe */ pvals->point[to_idx].keyframe_abs = 0; pvals->point[to_idx].keyframe = 0; } /* -------------------------- * mov_grab_bezier_path * -------------------------- * grab the bezier path divided in * straight lines and assign them to N-controlpoints. * this procedure uses the number of frames to be handled * as the wanted number of contolpoints. * (but constrain to the maximum allowed number of contolpoints) */ static void mov_grab_bezier_path(t_mov_gui_stuff *mgp, gint32 vectors_id, gint32 stroke_id, const char *vectorname) { gint32 image_id; gint num_lines; gint num_points; gdouble max_distance; gdouble distance; gdouble step_length; gdouble precision; gint l_ii; image_id = mgp->ainfo_ptr->image_id; step_length = 1.0; num_points = 1 + abs(pvals->dst_range_end - pvals->dst_range_start); num_points = MIN((GAP_MOV_MAX_POINT-2), num_points); num_lines = num_points -1; distance = 0.0; precision = 1.0; /* shall give 1 pixel precision */ if(num_lines > 0) { max_distance = gimp_vectors_stroke_get_length(vectors_id, stroke_id, precision); step_length = max_distance / ((gdouble)num_lines); } for(l_ii=0; l_ii < num_points ; l_ii++) { gdouble xdouble; gdouble ydouble; gdouble slope; gboolean valid; gboolean success; success = gimp_vectors_stroke_get_point_at_dist(vectors_id , stroke_id , distance , precision , &xdouble , &ydouble , &slope , &valid ); if(gap_debug) { printf("PATH distance: %.3f, (%.4f / %.4f) X:%03d Y: %03d slope:%.3f valid:%d success:%d\n" , (float)distance , (float)xdouble , (float)ydouble , (int)pvals->point[l_ii].p_x , (int)pvals->point[l_ii].p_y , (float)slope , (int)valid , (int)success ); } if((!valid) || (!success)) { /* stop because we already reached the end of the path. * (distance in pixles is greater than number of the frames to handle) */ return; } pvals->point_idx_max = l_ii; p_clear_one_point(l_ii); pvals->point[l_ii].p_x = rint(xdouble); pvals->point[l_ii].p_y = rint(ydouble); distance += step_length; } } /* end mov_grab_bezier_path */ /* -------------------------- * mov_grab_anchorpoints_path * -------------------------- * grab the bezier path divided in * straight lines and assign them to N-controlpoints. * this procedure uses the number of frames to be handled * as the wanted number of contolpoints. * (but constrain to the maximum allowed number of contolpoints) */ static void mov_grab_anchorpoints_path(t_mov_gui_stuff *mgp, gint num_path_point_details, gdouble *points_details ) { gint l_ii; gint l_ti; gint l_idx; gint point_x; gint point_y; #define GAP_BEZIER_CTRL1_X_INDEX 0 #define GAP_BEZIER_CTRL1_Y_INDEX 1 #define GAP_BEZIER_ANCHOR_X_INDEX 2 #define GAP_BEZIER_ANCHOR_Y_INDEX 3 #define GAP_BEZIER_CTRL2_X_INDEX 4 #define GAP_BEZIER_CTRL12Y_INDEX 5 point_x = 0; point_y = 0; l_ti = 0; l_idx = 0; l_ii = 0; while(l_idx < GAP_MOV_MAX_POINT -2) { if(gap_debug) { printf("Point[%03d]: detail: %3.3f\n" , (int)l_ii , (float)points_details[l_ii] ); } /* this implemenatation just fetches the bezier ancor points * and ignores bezier control points * Each Bezier segment endpoint (anchor, A) has two * additional control points (C) associated. They are specified in the * order CACCACCAC... * where each point consists of 2 flaot values in order x y. * */ switch (l_ti) { case GAP_BEZIER_ANCHOR_X_INDEX: point_x = (gint)points_details[l_ii]; break; case GAP_BEZIER_ANCHOR_Y_INDEX: point_y = (gint)points_details[l_ii]; break; default: break; } l_ti++; l_ii++; if((l_ti >= 6) || (l_ii == num_path_point_details)) { if(gap_debug) { printf("\n"); } l_ti=0; if(gap_debug) { printf("ANCHOR x:%d y:%d\n\n" ,(int)point_x ,(int)point_y ); } pvals->point_idx_max = l_idx; p_clear_one_point(l_idx); pvals->point[l_idx].p_x = point_x; pvals->point[l_idx].p_y = point_y; l_idx++; } if (l_ii >= num_path_point_details) { break; } } if(gap_debug) { printf("\n"); } } /* end mov_grab_anchorpoints_path */ static void mov_pgrab_callback (GtkWidget *widget, GdkEventButton *bevent, gpointer data) { t_mov_gui_stuff *mgp = data; gint32 image_id; gint32 vectors_id; if(gap_debug) printf("mov_pgrab_callback\n"); /* get the image where MovePath was invoked from */ image_id = mgp->ainfo_ptr->image_id; vectors_id = gimp_image_get_active_vectors(image_id); if(vectors_id >= 0) { GimpVectorsStrokeType pathtype; gboolean path_closed; gint num_path_point_details; gdouble *points_details; gchar *vectorname; gint num_stroke_ids; gint *stroke_ids; vectorname = gimp_vectors_get_name(vectors_id); points_details = NULL; num_path_point_details = 0; if(gap_debug) { printf("vectorname :%s\n", vectorname); } stroke_ids = gimp_vectors_get_strokes(vectors_id, &num_stroke_ids); if(gap_debug) { printf("num_stroke_ids:%d\n" , (int)num_stroke_ids ); } if (num_stroke_ids < 1) { g_message(_("No stroke ids found in path:\n" "'%s'\n" "in the Image:\n" "'%s'") ,vectorname ,mgp->ainfo_ptr->old_filename ); return; } /* TODO how to handle path that has more than one stroke_id. * the current implementation uses only the 1.st stroke_id */ pathtype = gimp_vectors_stroke_get_points(vectors_id , stroke_ids[0] , &num_path_point_details , &points_details , &path_closed ); if(gap_debug) { printf("pathtype:%d path_closed flag :%d num_points:%d num_stroke_ids:%d\n" , (int)pathtype , (int)path_closed , (int)num_path_point_details , (int)num_stroke_ids ); } if(pathtype != GIMP_VECTORS_STROKE_TYPE_BEZIER) { g_message(_("Unsupported pathtype %d found in path:\n" "'%s'\n" "in the Image:\n" "'%s'") ,(int)pathtype ,vectorname ,mgp->ainfo_ptr->old_filename ); return; } if(num_path_point_details < 1) { g_message(_("No controlpoints found in path:\n" "'%s'\n" "in the Image:\n" "'%s'") ,vectorname ,mgp->ainfo_ptr->old_filename ); return; } if(bevent->state & GDK_SHIFT_MASK) { /* When SHIFT Key was pressed * the path will be divided in n-parts to get * one controlpoint per handled frame. */ mov_grab_bezier_path(mgp, vectors_id, stroke_ids[0], vectorname); } else { mov_grab_anchorpoints_path(mgp ,num_path_point_details ,points_details ); } g_free(stroke_ids); g_free(points_details); pvals->point_idx = 0; p_point_refresh(mgp); mov_set_instant_apply_request(mgp); } else { g_message(_("No path found in the image:\n" "'%s'") ,mgp->ainfo_ptr->old_filename ); } } /* end mov_pgrab_callback */ static void mov_padd_callback (GtkWidget *widget, gpointer data) { t_mov_gui_stuff *mgp = data; gint l_idx; if(gap_debug) printf("mov_padd_callback\n"); l_idx = pvals->point_idx_max; if (l_idx < GAP_MOV_MAX_POINT -2) { /* advance to next point */ p_points_to_tab(mgp); pvals->point_idx_max++; pvals->point_idx = pvals->point_idx_max; /* copy values from previous point to current (new) point */ p_copy_point(pvals->point_idx_max, l_idx); p_point_refresh(mgp); } } static void mov_pins_callback (GtkWidget *widget, gpointer data) { t_mov_gui_stuff *mgp = data; gint l_idx; if(gap_debug) printf("mov_pins_callback\n"); l_idx = pvals->point_idx_max; if (l_idx < GAP_MOV_MAX_POINT -2) { /* advance to next point */ p_points_to_tab(mgp); pvals->point_idx_max++; for(l_idx = pvals->point_idx_max; l_idx > pvals->point_idx; l_idx--) { /* copy values from prev point */ p_copy_point(l_idx, l_idx-1); } pvals->point_idx++; p_point_refresh(mgp); } } static void mov_pdel_callback (GtkWidget *widget, gpointer data) { t_mov_gui_stuff *mgp = data; gint l_idx; if(gap_debug) printf("mov_pdel_callback\n"); l_idx = pvals->point_idx_max; if(pvals->point_idx_max == 0) { /* This is the las t point to delete */ p_reset_points(); } else { for(l_idx = pvals->point_idx; l_idx < pvals->point_idx_max; l_idx++) { /* copy values from next point */ p_copy_point(l_idx, l_idx+1); } pvals->point_idx_max--; pvals->point_idx = MIN(pvals->point_idx, pvals->point_idx_max); } p_point_refresh(mgp); mov_set_instant_apply_request(mgp); } static void mov_follow_keyframe(t_mov_gui_stuff *mgp) { gint32 keyframe_abs; keyframe_abs = mgp->keyframe_abs; if(pvals->point_idx <= 0) { keyframe_abs = mgp->first_nr; } else { if(pvals->point_idx >= pvals->point_idx_max) { keyframe_abs = mgp->last_nr; } else { if(keyframe_abs < 1) { return; } } } if((keyframe_abs >= mgp->first_nr) && (keyframe_abs <= mgp->last_nr)) { mgp->preview_frame_nr = keyframe_abs; gtk_adjustment_set_value (mgp->preview_frame_nr_adj, (gdouble)keyframe_abs); } } static void mov_pnext_callback (GtkWidget *widget, GdkEventButton *bevent, gpointer data) { t_mov_gui_stuff *mgp = data; if(gap_debug) printf("mov_pnext_callback\n"); if (pvals->point_idx < pvals->point_idx_max) { /* advance to next point */ p_points_to_tab(mgp); pvals->point_idx++; p_point_refresh(mgp); if (bevent->state & GDK_SHIFT_MASK) { mov_follow_keyframe(mgp); } mov_set_instant_apply_request(mgp); } } static void mov_pprev_callback (GtkWidget *widget, GdkEventButton *bevent, gpointer data) { t_mov_gui_stuff *mgp = data; if(gap_debug) printf("mov_pprev_callback\n"); if (pvals->point_idx > 0) { /* advance to next point */ p_points_to_tab(mgp); pvals->point_idx--; p_point_refresh(mgp); if (bevent->state & GDK_SHIFT_MASK) { mov_follow_keyframe(mgp); } mov_set_instant_apply_request(mgp); } } static void mov_pfirst_callback (GtkWidget *widget, GdkEventButton *bevent, gpointer data) { t_mov_gui_stuff *mgp = data; if(gap_debug) printf("mov_pfirst_callback\n"); /* advance to first point */ p_points_to_tab(mgp); pvals->point_idx = 0; p_point_refresh(mgp); if (bevent->state & GDK_SHIFT_MASK) { mov_follow_keyframe(mgp); } mov_set_instant_apply_request(mgp); } static void mov_plast_callback (GtkWidget *widget, GdkEventButton *bevent, gpointer data) { t_mov_gui_stuff *mgp = data; if(gap_debug) printf("mov_plast_callback\n"); /* advance to first point */ p_points_to_tab(mgp); pvals->point_idx = pvals->point_idx_max; p_point_refresh(mgp); if (bevent->state & GDK_SHIFT_MASK) { mov_follow_keyframe(mgp); } mov_set_instant_apply_request(mgp); } static void mov_pclr_callback (GtkWidget *widget, gpointer data) { t_mov_gui_stuff *mgp = data; if(gap_debug) printf("mov_pclr_callback\n"); p_clear_one_point(pvals->point_idx); /* clear the current point */ p_point_refresh(mgp); mov_set_instant_apply_request(mgp); } static void mov_pdel_all_callback (GtkWidget *widget, gpointer data) { t_mov_gui_stuff *mgp = data; if(gap_debug) printf("mov_pdel_all_callback\n"); p_reset_points(); p_point_refresh(mgp); mov_set_instant_apply_request(mgp); } static void mov_pclr_all_callback (GtkWidget *widget, GdkEventButton *bevent, gpointer data) { gint l_idx; gint l_ref_idx1; gint l_ref_idx2; t_mov_gui_stuff *mgp = data; gdouble mix_factor; if(gap_debug) printf("mov_pclr_all_callback\n"); if(bevent->state & GDK_SHIFT_MASK) { for(l_idx = 1; l_idx <= pvals->point_idx_max; l_idx++) { mix_factor = 0.0; l_ref_idx1 = 0; l_ref_idx2 = 0; p_mix_one_point(l_idx, l_ref_idx1, l_ref_idx2, mix_factor); } } else { if(bevent->state & GDK_CONTROL_MASK) { for(l_idx = 1; l_idx <= pvals->point_idx_max -1; l_idx++) { mix_factor = (gdouble)l_idx / (gdouble)pvals->point_idx_max; l_ref_idx1 = 0; l_ref_idx2 = pvals->point_idx_max; p_mix_one_point(l_idx, l_ref_idx1, l_ref_idx2, mix_factor); } } else { for(l_idx = 0; l_idx <= pvals->point_idx_max; l_idx++) { p_clear_one_point(l_idx); } } } p_point_refresh(mgp); mov_set_instant_apply_request(mgp); } static void mov_prot_follow_callback (GtkWidget *widget, GdkEventButton *bevent, gpointer data) { gdouble l_startangle; int key_modifier; t_mov_gui_stuff *mgp = data; key_modifier = 0; if(gap_debug) printf("mov_prot_follow_callback\n"); /* SHIFT: GDK_SHIFT_MASK, * CTRL: GDK_CONTROL_MASK, * ALT: GDK_MOD1_MASK */ key_modifier = 0; if (bevent->state & GDK_SHIFT_MASK) { key_modifier = 1; /* SHIFT */ } if(gap_debug) { printf("key_modifier %d\n", (int)key_modifier); } if( pvals->point_idx_max > 1) { l_startangle = 0.0; if(key_modifier != 0) { /* SHIFT */ p_points_to_tab(mgp); l_startangle = pvals->point[0].rotation; } gap_mov_exec_calculate_rotate_follow(pvals, l_startangle); } p_point_refresh(mgp); mov_set_instant_apply_request(mgp); } static void p_filesel_close_cb(GtkWidget *widget, t_mov_gui_stuff *mgp) { if(mgp->filesel == NULL) return; gtk_widget_destroy(GTK_WIDGET(mgp->filesel)); mgp->filesel = NULL; /* now filesel is closed */ } static void mov_pload_callback (GtkWidget *widget, gpointer data) { GtkWidget *filesel; t_mov_gui_stuff *mgp = data; if(mgp->filesel != NULL) { gtk_window_present(GTK_WINDOW(mgp->filesel)); return; /* filesel is already open */ } filesel = gtk_file_selection_new ( _("Load Path Points from File")); mgp->filesel = filesel; gtk_window_set_position (GTK_WINDOW (filesel), GTK_WIN_POS_MOUSE); g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button), "clicked", G_CALLBACK (p_points_load_from_file), mgp); g_signal_connect(G_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button), "clicked", G_CALLBACK (p_filesel_close_cb), mgp); gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), mgp->pointfile_name); gtk_widget_show (filesel); /* "destroy" has to be the last signal, * (otherwise the other callbacks are never called) */ g_signal_connect (G_OBJECT (filesel), "destroy", G_CALLBACK (p_filesel_close_cb), mgp); } static void mov_psave_callback (GtkWidget *widget, gpointer data) { GtkWidget *filesel; t_mov_gui_stuff *mgp = data; if(mgp->filesel != NULL) { gtk_window_present(GTK_WINDOW(mgp->filesel)); return; /* filesel is already open */ } filesel = gtk_file_selection_new ( _("Save Path Points to File")); mgp->filesel = filesel; gtk_window_set_position (GTK_WINDOW (filesel), GTK_WIN_POS_MOUSE); g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button), "clicked", G_CALLBACK (p_points_save_to_file), mgp); g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button), "clicked", G_CALLBACK (p_filesel_close_cb), mgp); gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), mgp->pointfile_name); gtk_widget_show (filesel); /* "destroy" has to be the last signal, * (otherwise the other callbacks are never called) */ g_signal_connect (G_OBJECT (filesel), "destroy", G_CALLBACK (p_filesel_close_cb), mgp); } static void p_points_load_from_file (GtkWidget *widget, t_mov_gui_stuff *mgp) { const gchar *filename; if(gap_debug) printf("p_points_load_from_file\n"); if(mgp->filesel == NULL) { return; } filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (mgp->filesel)); g_free(mgp->pointfile_name); mgp->pointfile_name = g_strdup(filename); if(gap_debug) printf("p_points_load_from_file %s\n", mgp->pointfile_name); gtk_widget_destroy(GTK_WIDGET(mgp->filesel)); mgp->filesel = NULL; p_load_points(mgp->pointfile_name); p_point_refresh(mgp); mov_set_instant_apply_request(mgp); } /* end p_points_load_from_file */ static void p_points_save_to_file (GtkWidget *widget, t_mov_gui_stuff *mgp) { const gchar *filename; if(gap_debug) printf("p_points_save_to_file\n"); if(mgp->filesel == NULL) { return; /* filesel is already open */ } filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (mgp->filesel)); g_free(mgp->pointfile_name); mgp->pointfile_name = g_strdup(filename); if(gap_debug) printf("p_points_save_to_file %s\n", mgp->pointfile_name); gtk_widget_destroy(GTK_WIDGET(mgp->filesel)); mgp->filesel = NULL; p_points_to_tab(mgp); p_save_points(mgp->pointfile_name, mgp); /* quit if MovePath Mainwindow was closed */ if(mgp->shell == NULL) { gtk_main_quit(); return; } p_point_refresh(mgp); } /* end p_points_save_to_file */ static void p_point_refresh(t_mov_gui_stuff *mgp) { p_points_from_tab(mgp); p_update_point_index_text(mgp); if(gap_debug) printf("p_point_refresh:newval in_call=%d\n", mgp->in_call ); if( !mgp->in_call ) { mov_path_prevw_cursor_update( mgp ); mov_path_prevw_draw ( mgp, CURSOR | PATH_LINE ); } mgp->in_call = TRUE; gtk_adjustment_set_value (mgp->x_adj, (gdouble)mgp->p_x); gtk_adjustment_set_value (mgp->y_adj, (gdouble)mgp->p_y); gtk_adjustment_set_value (mgp->wres_adj, (gdouble)mgp->w_resize); gtk_adjustment_set_value (mgp->hres_adj, (gdouble)mgp->h_resize); gtk_adjustment_set_value (mgp->opacity_adj, (gdouble)mgp->opacity); gtk_adjustment_set_value (mgp->rotation_adj, (gdouble)mgp->rotation); gtk_adjustment_set_value (mgp->keyframe_adj, (gdouble)mgp->keyframe_abs); gtk_adjustment_set_value (mgp->ttlx_adj, (gdouble)mgp->ttlx); gtk_adjustment_set_value (mgp->ttly_adj, (gdouble)mgp->ttly); gtk_adjustment_set_value (mgp->ttrx_adj, (gdouble)mgp->ttrx); gtk_adjustment_set_value (mgp->ttry_adj, (gdouble)mgp->ttry); gtk_adjustment_set_value (mgp->tblx_adj, (gdouble)mgp->tblx); gtk_adjustment_set_value (mgp->tbly_adj, (gdouble)mgp->tbly); gtk_adjustment_set_value (mgp->tbrx_adj, (gdouble)mgp->tbrx); gtk_adjustment_set_value (mgp->tbry_adj, (gdouble)mgp->tbry); gtk_adjustment_set_value (mgp->sel_feather_radius_adj, (gdouble)mgp->sel_feather_radius); mgp->in_call = FALSE; } /* end p_point_refresh */ static void p_pick_nearest_point(gint px, gint py) { gint l_idx; gint l_idx_min; gdouble l_sq_dist; gdouble l_dx, l_dy; gdouble l_sq_dist_min; l_idx_min = 0; l_sq_dist_min = G_MAXDOUBLE; if(gap_debug) printf("\np_pick_nearest_point: near to %4d %4d\n", (int)px, (int)py); for(l_idx = pvals->point_idx_max; l_idx >= 0; l_idx--) { /* calculate x and y distance */ l_dx = pvals->point[l_idx].p_x - px; l_dy = pvals->point[l_idx].p_y - py; /* calculate square of the distance */ l_sq_dist = (l_dx * l_dx) + (l_dy * l_dy); if(l_sq_dist < l_sq_dist_min) { l_sq_dist_min = l_sq_dist; l_idx_min = l_idx; } if(gap_debug) { printf(" [%2d] %4d %4d %f\n", (int)l_idx, (int)pvals->point[l_idx].p_x, (int)pvals->point[l_idx].p_y, (float)l_sq_dist ); } } if(gap_debug) printf("p_pick_nearest_point: selected %d\n", (int)l_idx_min); pvals->point_idx = l_idx_min; pvals->point[pvals->point_idx].p_x = px; pvals->point[pvals->point_idx].p_y = py; } /* end p_pick_nearest_point */ static void mov_imglayer_menu_callback(GtkWidget *widget, t_mov_gui_stuff *mgp) { gint32 l_image_id; gint32 id; gint value; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value); id = value; l_image_id = gimp_drawable_get_image(id); if(!gap_image_is_alive(l_image_id)) { if(gap_debug) { printf("mov_imglayer_menu_callback: NOT ALIVE image_id=%d layer_id=%d\n", (int)l_image_id, (int)id); } return; } if(id != pvals->src_layer_id) { if(pvals->tmpsel_image_id >= 0) { gimp_image_delete(pvals->tmpsel_image_id); pvals->tmpsel_image_id = -1; } } pvals->src_layer_id = id; pvals->src_image_id = l_image_id; if(gap_debug) printf("mov_imglayer_menu_callback: image_id=%d layer_id=%d\n", (int)pvals->src_image_id, (int)pvals->src_layer_id); mov_set_instant_apply_request(mgp); } /* end mov_imglayer_menu_callback */ static gint mov_imglayer_constrain(gint32 image_id, gint32 drawable_id, gpointer data) { if(gap_debug) printf("GAP-DEBUG: mov_imglayer_constrain PROCEDURE image_id:%d drawable_id:%d\n" ,(int)image_id ,(int)drawable_id ); if(drawable_id < 0) { /* gimp 1.1 makes a first call of the constraint procedure * with drawable_id = -1, and skips the whole image if FALSE is returned */ return(TRUE); } if(!gap_image_is_alive(image_id)) { return(FALSE); } /* dont accept layers from within the destination image id * or layers within the internal used tmporary images * or layers within images of other base types * (conversions between different base_types are not supported in this version) */ return((image_id != pvals->dst_image_id) && (image_id != pvals->cache_tmp_image_id) && (image_id != pvals->apv_mlayer_image) && (image_id != pvals->tmp_image_id) && (image_id != pvals->tmp_alt_image_id) && (image_id != pvals->tmpsel_image_id) && (image_id != pvals->tween_image_id) && (image_id != pvals->trace_image_id) && (gimp_image_base_type(image_id) == gimp_image_base_type(pvals->tmp_image_id)) ); } /* end mov_imglayer_constrain */ static void mov_paintmode_menu_callback (GtkWidget *widget, t_mov_gui_stuff *mgp) { gint value; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value); pvals->src_paintmode = value; mov_set_instant_apply_request(mgp); } static void mov_handmode_menu_callback (GtkWidget *widget, t_mov_gui_stuff *mgp) { gint value; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value); pvals->src_handle = value; if(mgp == NULL) return; mov_set_instant_apply_request(mgp); } static void mov_stepmode_menu_callback (GtkWidget *widget, t_mov_gui_stuff *mgp) { gboolean l_sensitive; GtkWidget *spinbutton; gint value; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value); pvals->src_stepmode = value; if(mgp == NULL) return; l_sensitive = TRUE; if((pvals->src_stepmode == GAP_STEP_NONE) || (pvals->src_stepmode == GAP_STEP_FRAME_NONE)) { l_sensitive = FALSE; } if(mgp->step_speed_factor_adj) { spinbutton = GTK_WIDGET(g_object_get_data (G_OBJECT (mgp->step_speed_factor_adj), "spinbutton")); if(spinbutton) { gtk_widget_set_sensitive(spinbutton, l_sensitive); } } mov_set_instant_apply_request(mgp); } /* end mov_stepmode_menu_callback */ static void mov_tweenlayer_sensitivity(t_mov_gui_stuff *mgp) { gboolean l_sensitive; GtkWidget *spinbutton; l_sensitive = TRUE; if(pvals->tween_steps < 1) { l_sensitive = FALSE; } if(mgp->tween_opacity_initial_adj) { spinbutton = GTK_WIDGET(g_object_get_data (G_OBJECT (mgp->tween_opacity_initial_adj), "spinbutton")); if(spinbutton) { gtk_widget_set_sensitive(spinbutton, l_sensitive); } } if(mgp->tween_opacity_desc_adj) { spinbutton = GTK_WIDGET(g_object_get_data (G_OBJECT (mgp->tween_opacity_desc_adj), "spinbutton")); if(spinbutton) { gtk_widget_set_sensitive(spinbutton, l_sensitive); } } } /* end mov_tweenlayer_sensitivity */ static void mov_tracelayer_sensitivity(t_mov_gui_stuff *mgp) { gboolean l_sensitive; GtkWidget *spinbutton; l_sensitive = FALSE; if(pvals->tracelayer_enable) { l_sensitive = TRUE; } if(mgp->trace_opacity_initial_adj) { spinbutton = GTK_WIDGET(g_object_get_data (G_OBJECT (mgp->trace_opacity_initial_adj), "spinbutton")); if(spinbutton) { gtk_widget_set_sensitive(spinbutton, l_sensitive); } } if(mgp->trace_opacity_desc_adj) { spinbutton = GTK_WIDGET(g_object_get_data (G_OBJECT (mgp->trace_opacity_desc_adj), "spinbutton")); if(spinbutton) { gtk_widget_set_sensitive(spinbutton, l_sensitive); } } } /* end mov_tracelayer_sensitivity */ static void mov_gint_toggle_callback(GtkWidget *w, gpointer client_data) { gint *data; data = (gint*)client_data; if (GTK_TOGGLE_BUTTON (w)->active) { *data = 1; } else { *data = 0; } } /* end mov_gint_toggle_callback */ static void mov_force_visibility_toggle_callback (GtkWidget *widget, gpointer client_data) { t_mov_gui_stuff *mgp; if((widget == NULL) || (client_data == NULL)) { return; } mov_gint_toggle_callback(widget, client_data); mgp = g_object_get_data( G_OBJECT(widget), "mgp" ); mov_set_instant_apply_request(mgp); } /* end mov_force_visibility_toggle_callback */ static void mov_bluebox_callback (GtkWidget *widget, gpointer client_data) { t_mov_gui_stuff *mgp; if((widget == NULL) || (client_data == NULL)) { return; } mov_gint_toggle_callback(widget, client_data); mgp = g_object_get_data( G_OBJECT(widget), "mgp" ); if(mgp) { mov_set_instant_apply_request(mgp); } } /* end mov_bluebox_callback */ static void mov_tracelayer_callback (GtkWidget *widget, gpointer client_data) { t_mov_gui_stuff *mgp; if((widget == NULL) || (client_data == NULL)) { return; } mov_gint_toggle_callback(widget, client_data); mgp = g_object_get_data( G_OBJECT(widget), "mgp" ); if(mgp) { mov_tracelayer_sensitivity(mgp); } } /* end mov_tracelayer_callback */ static void mov_show_path_or_cursor(t_mov_gui_stuff *mgp) { if(mgp == NULL) return; if(mgp->startup) return; if(mgp->pv_ptr == NULL) return; if(mgp->pv_ptr->da_widget == NULL) return; if(mgp->drawable == NULL) return; p_point_refresh(mgp); mov_path_prevw_draw ( mgp, CURSOR | PATH_LINE ); gtk_widget_queue_draw(mgp->pv_ptr->da_widget); gdk_flush(); } /* end mov_show_path_or_cursor */ static void mov_show_path_callback(GtkWidget *widget, t_mov_gui_stuff *mgp) { mov_gint_toggle_callback(widget, &mgp->show_path); mov_show_path_or_cursor(mgp); } /* end mov_show_path_callback */ static void mov_show_cursor_callback(GtkWidget *widget, t_mov_gui_stuff *mgp) { mov_gint_toggle_callback(widget, &mgp->show_cursor); mov_show_path_or_cursor(mgp); } /* end mov_show_cursor_callback */ static void mov_show_grid_callback(GtkWidget *widget, t_mov_gui_stuff *mgp) { mov_gint_toggle_callback(widget, &mgp->show_grid); mov_show_path_or_cursor(mgp); //XX grid rendering and picking not implemented yet !!! } /* end mov_show_grid_callback */ /* -------------------------- * install / remove timer * -------------------------- */ static void mov_install_timer(t_mov_gui_stuff *mgp) { if(mgp->instant_timertag < 0) { mgp->instant_timertag = (gint32) g_timeout_add(INSTANT_TIMERINTERVAL_MILLISEC, (GtkFunction)mov_instant_timer_callback , mgp); } } /* end mov_install_timer */ static void mov_remove_timer(t_mov_gui_stuff *mgp) { if(mgp->instant_timertag >= 0) { g_source_remove(mgp->instant_timertag); mgp->instant_timertag = -1; } } /* end mov_remove_timer */ /* -------------------------- * mov_instant_timer_callback * -------------------------- * This procedure is called periodically via timer * when the instant_apply checkbox is ON */ static void mov_instant_timer_callback(gpointer user_data) { t_mov_gui_stuff *mgp; mgp = user_data; if(mgp == NULL) { return; } mov_remove_timer(mgp); if(!mov_check_valid_src_layer(mgp)) { return; } if(mgp->instant_apply_request) { if(gap_debug) printf("FIRE mov_instant_timer_callback >>>> REQUEST is TRUE\n"); mov_upvw_callback (NULL, mgp); /* the request is cleared in this procedure */ } /* restart timer for next cycle */ if(mgp->instant_apply) { mov_install_timer(mgp); } } /* end mov_instant_timer_callback */ static void mov_instant_apply_callback(GtkWidget *widget, t_mov_gui_stuff *mgp) { mov_gint_toggle_callback(widget, &mgp->instant_apply); if(mgp->instant_apply) { mov_set_instant_apply_request(mgp); mov_install_timer(mgp); } else { mov_remove_timer(mgp); } } /* end mov_instant_apply_callback */ /* ============================================================================ * procedures to handle POINTS - TABLE * ============================================================================ */ static void p_points_from_tab(t_mov_gui_stuff *mgp) { GtkWidget *scale; GtkWidget *spinbutton; mgp->p_x = pvals->point[pvals->point_idx].p_x; mgp->p_y = pvals->point[pvals->point_idx].p_y; mgp->opacity = pvals->point[pvals->point_idx].opacity; mgp->w_resize = pvals->point[pvals->point_idx].w_resize; mgp->h_resize = pvals->point[pvals->point_idx].h_resize; mgp->rotation = pvals->point[pvals->point_idx].rotation; mgp->ttlx = pvals->point[pvals->point_idx].ttlx; mgp->ttly = pvals->point[pvals->point_idx].ttly; mgp->ttrx = pvals->point[pvals->point_idx].ttrx; mgp->ttry = pvals->point[pvals->point_idx].ttry; mgp->tblx = pvals->point[pvals->point_idx].tblx; mgp->tbly = pvals->point[pvals->point_idx].tbly; mgp->tbrx = pvals->point[pvals->point_idx].tbrx; mgp->tbry = pvals->point[pvals->point_idx].tbry; mgp->sel_feather_radius = pvals->point[pvals->point_idx].sel_feather_radius; mgp->keyframe_abs = pvals->point[pvals->point_idx].keyframe_abs; if(( mgp->keyframe_adj != NULL) && (mgp->startup != TRUE)) { /* findout the gtk_widgets (scale and spinbutton) connected * to mgp->keyframe_adj * and set_sensitive to TRUE or FALSE */ scale = GTK_WIDGET(g_object_get_data (G_OBJECT (mgp->keyframe_adj), "scale")); spinbutton = GTK_WIDGET(g_object_get_data (G_OBJECT (mgp->keyframe_adj), "spinbutton")); if(spinbutton == NULL) { return; } if(gap_debug) { printf("p_points_from_tab: scale %x spinbutton %x\n", (int)scale, (int)spinbutton); } if((pvals->point_idx == 0) || (pvals->point_idx == pvals->point_idx_max)) { gtk_widget_set_sensitive(spinbutton, FALSE); if(scale) gtk_widget_set_sensitive(scale, FALSE); } else { gtk_widget_set_sensitive(spinbutton, TRUE); if(scale) gtk_widget_set_sensitive(scale, TRUE); } } } static void p_points_to_tab(t_mov_gui_stuff *mgp) { if(gap_debug) printf("p_points_to_tab: idx=%d, rotation=%f\n", (int)pvals->point_idx , (float)mgp->rotation); pvals->point[pvals->point_idx].p_x = mgp->p_x; pvals->point[pvals->point_idx].p_y = mgp->p_y; pvals->point[pvals->point_idx].opacity = mgp->opacity; pvals->point[pvals->point_idx].w_resize = mgp->w_resize; pvals->point[pvals->point_idx].h_resize = mgp->h_resize; pvals->point[pvals->point_idx].rotation = mgp->rotation; pvals->point[pvals->point_idx].ttlx = mgp->ttlx; pvals->point[pvals->point_idx].ttly = mgp->ttly; pvals->point[pvals->point_idx].ttrx = mgp->ttrx; pvals->point[pvals->point_idx].ttry = mgp->ttry; pvals->point[pvals->point_idx].tblx = mgp->tblx; pvals->point[pvals->point_idx].tbly = mgp->tbly; pvals->point[pvals->point_idx].tbrx = mgp->tbrx; pvals->point[pvals->point_idx].tbry = mgp->tbry; pvals->point[pvals->point_idx].sel_feather_radius = mgp->sel_feather_radius; pvals->point[pvals->point_idx].keyframe_abs = mgp->keyframe_abs; if((mgp->keyframe_abs > 0) && (pvals->point_idx != 0) && (pvals->point_idx != pvals->point_idx_max)) { pvals->point[pvals->point_idx].keyframe = gap_mov_exec_conv_keyframe_to_rel(mgp->keyframe_abs, pvals); } else { pvals->point[pvals->point_idx].keyframe = 0; } } void p_update_point_index_text(t_mov_gui_stuff *mgp) { g_snprintf (&mgp->point_index_text[0], POINT_INDEX_LABEL_LENGTH, _("Current Point: [ %3d ] of [ %3d ]"), pvals->point_idx + 1, pvals->point_idx_max +1); if (mgp->point_index_frame) { gtk_frame_set_label (GTK_FRAME (mgp->point_index_frame), &mgp->point_index_text[0]); } } /* ============================================================================ * p_clear_one_point * Init point table with identical 2 Points * ============================================================================ */ void p_clear_one_point(gint idx) { if((idx >= 0) && (idx <= pvals->point_idx_max)) { pvals->point[idx].opacity = 100.0; /* 100 percent (no transparecy) */ pvals->point[idx].w_resize = 100.0; /* 100% no resizize (1:1) */ pvals->point[idx].h_resize = 100.0; /* 100% no resizize (1:1) */ pvals->point[idx].rotation = 0.0; /* no rotation (0 degree) */ /* 1.0 for all perspective transform factors (== no perspective transformation) */ pvals->point[idx].ttlx = 1.0; pvals->point[idx].ttly = 1.0; pvals->point[idx].ttrx = 1.0; pvals->point[idx].ttry = 1.0; pvals->point[idx].tblx = 1.0; pvals->point[idx].tbly = 1.0; pvals->point[idx].tbrx = 1.0; pvals->point[idx].tbry = 1.0; pvals->point[idx].sel_feather_radius = 0.0; pvals->point[idx].keyframe = 0; /* 0: controlpoint is not fixed to keyframe */ pvals->point[idx].keyframe_abs = 0; /* 0: controlpoint is not fixed to keyframe */ } } /* end p_clear_one_point */ /* -------------------------- * p_mix_one_point * -------------------------- * calculate settings for one point by mixing * the settings of 2 reference points. * All settings EXCEPT the position are affected */ void p_mix_one_point(gint idx, gint ref1, gint ref2, gdouble mix_factor) { #define MIX_VALUE(factor, a, b) ((a * (1.0 - factor)) + (b * factor)) if((idx >= 0) && (idx <= pvals->point_idx_max) && (ref1 >= 0) && (ref1 <= pvals->point_idx_max) && (ref2 >= 0) && (ref2 <= pvals->point_idx_max) ) { pvals->point[idx].opacity = MIX_VALUE(mix_factor, pvals->point[ref1].opacity, pvals->point[ref2].opacity); pvals->point[idx].w_resize = MIX_VALUE(mix_factor, pvals->point[ref1].w_resize, pvals->point[ref2].w_resize); pvals->point[idx].h_resize = MIX_VALUE(mix_factor, pvals->point[ref1].h_resize, pvals->point[ref2].h_resize); pvals->point[idx].rotation = MIX_VALUE(mix_factor, pvals->point[ref1].rotation, pvals->point[ref2].rotation); pvals->point[idx].ttlx = MIX_VALUE(mix_factor, pvals->point[ref1].ttlx, pvals->point[ref2].ttlx); pvals->point[idx].ttly = MIX_VALUE(mix_factor, pvals->point[ref1].ttly, pvals->point[ref2].ttly); pvals->point[idx].ttrx = MIX_VALUE(mix_factor, pvals->point[ref1].ttrx, pvals->point[ref2].ttrx); pvals->point[idx].ttry = MIX_VALUE(mix_factor, pvals->point[ref1].ttry, pvals->point[ref2].ttry); pvals->point[idx].tblx = MIX_VALUE(mix_factor, pvals->point[ref1].tblx, pvals->point[ref2].tblx); pvals->point[idx].tbly = MIX_VALUE(mix_factor, pvals->point[ref1].tbly, pvals->point[ref2].tbly); pvals->point[idx].tbrx = MIX_VALUE(mix_factor, pvals->point[ref1].tbrx, pvals->point[ref2].tbrx); pvals->point[idx].tbry = MIX_VALUE(mix_factor, pvals->point[ref1].tbry, pvals->point[ref2].tbry); pvals->point[idx].sel_feather_radius = MIX_VALUE(mix_factor, pvals->point[ref1].sel_feather_radius, pvals->point[ref2].sel_feather_radius); pvals->point[idx].keyframe = 0; /* 0: controlpoint is not fixed to keyframe */ pvals->point[idx].keyframe_abs = 0; /* 0: controlpoint is not fixed to keyframe */ } } /* end p_mix_one_point */ /* ============================================================================ * p_reset_points * Init point table with identical 2 Points * ============================================================================ */ void p_reset_points() { pvals->point_idx = 0; /* 0 == current point */ pvals->point_idx_max = 0; /* 0 == there is only one valid point */ p_clear_one_point(0); pvals->point[0].p_x = 0; pvals->point[0].p_y = 0; } /* end p_reset_points */ /* ============================================================================ * p_load_points * load point table (from named file into global pvals) * (reset points if load failed) * ============================================================================ */ void p_load_points(char *filename) { gint l_rc; gint l_errno; l_rc = gap_mov_exec_gap_load_pointfile(filename, pvals); l_errno = errno; if (l_rc < -1) { p_reset_points(); } if (l_rc != 0) { if(l_errno != 0) { g_message(_("ERROR: Could not open controlpoints\n" "filename: '%s'\n%s") ,filename, g_strerror (l_errno)); } else { g_message(_("ERROR: Could not read controlpoints\n" "filename: '%s'\n(Is not a valid controlpoint file)") ,filename); } } } /* end p_load_points */ /* ============================================================================ * p_save_points * save point table (from global pvals into named file) * ============================================================================ */ static void p_save_points(char *filename, t_mov_gui_stuff *mgp) { gint l_rc; gint l_errno; gboolean l_wr_permission; l_wr_permission = gap_arr_overwrite_file_dialog(filename); /* quit if MovePath Mainwindow was closed */ if(mgp->shell == NULL) { gtk_main_quit (); return; } if(l_wr_permission) { l_rc = gap_mov_exec_gap_save_pointfile(filename, pvals); l_errno = errno; if(l_rc != 0) { g_message (_("Failed to write controlpointfile\n" "filename: '%s':\n%s"), filename, g_strerror (l_errno)); } } } /* end p_save_points */ /* ============================================================================ * mov_refresh_src_layer_menu * ============================================================================ */ static void mov_refresh_src_layer_menu(t_mov_gui_stuff *mgp) { gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (mgp->src_layer_combo), pvals->src_layer_id, /* initial value */ G_CALLBACK (mov_imglayer_menu_callback), mgp); } /* end mov_refresh_src_layer_menu */ /* ============================================================================ * Create new source selection table Frame, and return it. * A frame that contains: * - 2x2 menus (src_image/layer, handle, stepmode, paintmode) * ============================================================================ */ static GtkWidget * mov_src_sel_create(t_mov_gui_stuff *mgp) { GtkWidget *table; GtkWidget *sub_table; GtkWidget *combo; GtkWidget *label; GtkObject *adj; /* the table */ table = gtk_table_new (2, 4, FALSE); gtk_container_set_border_width (GTK_CONTAINER (table), 2); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_table_set_col_spacings (GTK_TABLE (table), 4); /* Source Layer menu */ label = gtk_label_new( _("Source Image/Layer:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 4, 0); gtk_widget_show(label); combo = gimp_layer_combo_box_new (mov_imglayer_constrain, NULL); gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 0, 0); gimp_help_set_help_data(combo, _("Source object to insert into destination frames of the specified range") , NULL); gtk_widget_show(combo); mgp->src_layer_combo = combo; mov_refresh_src_layer_menu(mgp); gtk_widget_show(combo); /* Paintmode combo (menu) */ label = gtk_label_new( _("Mode:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, GTK_FILL, 0, 4, 0); gtk_widget_show(label); combo = gimp_int_combo_box_new (_("Normal"), GIMP_NORMAL_MODE, _("Dissolve"), GIMP_DISSOLVE_MODE, _("Multiply"), GIMP_MULTIPLY_MODE, _("Divide"), GIMP_DIVIDE_MODE, _("Screen"), GIMP_SCREEN_MODE, _("Overlay"), GIMP_OVERLAY_MODE, _("Dodge"), GIMP_DODGE_MODE, _("Burn"), GIMP_BURN_MODE, _("Hard Light"), GIMP_HARDLIGHT_MODE, _("Soft Light"), GIMP_SOFTLIGHT_MODE, _("Grain Extract"), GIMP_GRAIN_EXTRACT_MODE, _("Grain Merge"), GIMP_GRAIN_MERGE_MODE, _("Difference"), GIMP_DIFFERENCE_MODE, _("Addition"), GIMP_ADDITION_MODE, _("Subtract"), GIMP_SUBTRACT_MODE, _("Darken Only"), GIMP_DARKEN_ONLY_MODE, _("Lighten Only"), GIMP_LIGHTEN_ONLY_MODE, _("Hue"), GIMP_HUE_MODE, _("Saturation"), GIMP_SATURATION_MODE, _("Color"), GIMP_COLOR_MODE, _("Value"), GIMP_VALUE_MODE, _("Keep Paintmode"), GAP_MOV_KEEP_SRC_PAINTMODE, NULL); gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), GIMP_NORMAL_MODE, /* initial int value */ G_CALLBACK (mov_paintmode_menu_callback), mgp); gtk_table_attach(GTK_TABLE(table), combo, 3, 4, 0, 1, GTK_EXPAND | GTK_FILL, 0, 0, 0); gimp_help_set_help_data(combo, _("Paintmode") , NULL); gtk_widget_show(combo); /* Loop Stepmode menu (Label) */ label = gtk_label_new( _("Stepmode:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 4, 0); gtk_widget_show(label); /* the sub_table (1 row) */ sub_table = gtk_table_new (1, 3, FALSE); gtk_widget_show(sub_table); gtk_container_set_border_width (GTK_CONTAINER (sub_table), 2); gtk_table_set_row_spacings (GTK_TABLE (sub_table), 0); gtk_table_set_col_spacings (GTK_TABLE (sub_table), 2); gtk_table_attach(GTK_TABLE(table), sub_table, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 0, 0); /* StepSpeedFactor */ adj = p_mov_spinbutton_new( GTK_TABLE (sub_table), 1, 0, /* table col, row */ _("SpeedFactor:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)pvals->step_speed_factor, /* initial value */ (gdouble)0.0, (gdouble)50.0, /* lower, upper */ 0.1, 1, /* step, page */ 3, /* digits */ FALSE, /* constrain */ (gdouble)0.0, (gdouble)50.0, /* lower, upper (unconstrained) */ _("Source and target frames step synchronized at value 1.0. " "A value of 0.5 will step the source half time slower. " "One source step is done only at every 2nd target frame."), NULL); /* tooltip privatetip */ g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (gimp_double_adjustment_update), &pvals->step_speed_factor); mgp->step_speed_factor_adj = GTK_ADJUSTMENT(adj); /* Loop Stepmode combo */ combo = gimp_int_combo_box_new (_("Loop"), GAP_STEP_LOOP, _("Loop Reverse"), GAP_STEP_LOOP_REV, _("Once"), GAP_STEP_ONCE, _("Once Reverse"), GAP_STEP_ONCE_REV, _("Ping Pong"), GAP_STEP_PING_PONG, _("None"), GAP_STEP_NONE, _("Frame Loop"), GAP_STEP_FRAME_LOOP, _("Frame Loop Reverse"), GAP_STEP_FRAME_LOOP_REV, _("Frame Once"), GAP_STEP_FRAME_ONCE, _("Frame Once Reverse"), GAP_STEP_FRAME_ONCE_REV, _("Frame Ping Pong"), GAP_STEP_FRAME_PING_PONG, _("Frame None"), GAP_STEP_FRAME_NONE, NULL); gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), GAP_STEP_LOOP, /* initial int value */ G_CALLBACK (mov_stepmode_menu_callback), mgp); gtk_table_attach(GTK_TABLE(sub_table), combo, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, 0, 0, 0); gimp_help_set_help_data(combo, _("How to fetch the next source layer at the next handled frame") , NULL); gtk_widget_show(combo); /* Source Image Handle menu */ label = gtk_label_new( _("Handle:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 2, 3, 1, 2, GTK_FILL, 0, 4, 0); gtk_widget_show(label); combo = gimp_int_combo_box_new (_("Left Top"), GAP_HANDLE_LEFT_TOP, _("Left Bottom"), GAP_HANDLE_LEFT_BOT, _("Right Top"), GAP_HANDLE_RIGHT_TOP, _("Right Bottom"), GAP_HANDLE_RIGHT_BOT, _("Center"), GAP_HANDLE_CENTER, NULL); gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), GAP_HANDLE_LEFT_TOP, /* initial int value */ G_CALLBACK (mov_handmode_menu_callback), mgp); gtk_table_attach(GTK_TABLE(table), combo, 3, 4, 1, 2, GTK_EXPAND | GTK_FILL, 0, 0, 0); gimp_help_set_help_data(combo, _("How to place the Source layer at controlpoint coordinates") , NULL); gtk_widget_show(combo); gtk_widget_show( table ); return table; } /* end mov_src_sel_create */ /* ============================================================================ * Create set of widgets for the advanced Move Path features * A frame that contains: * in the 1.st row * - 3x spionbutton for tween_steps, tween_opacity_init, tween_opacity_desc * in the 2.nd row * - checkbutton make_tracelayer * - 2x spinbutton for trace_opacity_initial, trace_opacity_desc * ============================================================================ */ static GtkWidget * mov_advanced_tab_create(t_mov_gui_stuff *mgp) { GtkWidget *table; GtkWidget *check_button; GtkObject *adj; guint row; guint col; /* the table (2 rows) */ table = gtk_table_new (2, 8, FALSE); gtk_container_set_border_width (GTK_CONTAINER (table), 2); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_table_set_col_spacings (GTK_TABLE (table), 4); row = 0; col = 0; /* the bluebox widgets */ { GtkWidget *check_button; GtkWidget *label; GtkWidget *color_button; /* toggle bluebox */ check_button = gtk_check_button_new_with_label ( _("Bluebox")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), pvals->src_apply_bluebox); gimp_help_set_help_data(check_button, _("Apply the bluebox filter on the moving object(s). " "The bluebox filter makes the keycolor transparent.") , NULL); gtk_widget_show (check_button); gtk_table_attach(GTK_TABLE(table), check_button, col, col+1, row, row+1 ,0 , 0, 0, 0); g_object_set_data(G_OBJECT(check_button), "mgp", mgp); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (mov_bluebox_callback), &pvals->src_apply_bluebox); /* keycolor label */ label = gtk_label_new( _("Keycolor:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, col, col+1, row+1, row+2 , 0, 0, 0, 0); gtk_widget_show(label); if(pvals->bbp_pv == NULL) { pvals->bbp_pv = gap_bluebox_bbp_new(-1); } /* keycolor button */ color_button = gimp_color_button_new (_("Move Path Bluebox Keycolor"), 25, 12, /* WIDTH, HEIGHT, */ &pvals->bbp_pv->vals.keycolor, GIMP_COLOR_AREA_FLAT); /* dont know if it is possible to remove the signal handler for the "clicked" signal * on the gimp_color_button. * WORKAROUND: * destroy the unwanted standard dialog in my private handler * mov_path_keycolorbutton_clicked */ gtk_table_attach(GTK_TABLE(table), color_button, col+1, col+2, row+1, row+2 , 0, 0, 0, 0); gtk_widget_show (color_button); gimp_help_set_help_data(color_button, _("Open dialog window to set " "parameters and keycolor for the bluebox filter") , NULL); g_signal_connect (color_button, "clicked", G_CALLBACK (mov_path_keycolorbutton_clicked), mgp); g_signal_connect (color_button, "color_changed", G_CALLBACK (mov_path_keycolorbutton_changed), mgp); } row = 0; col = 2; /* toggle Tracelayer */ check_button = gtk_check_button_new_with_label ( _("Tracelayer")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), pvals->tracelayer_enable); gimp_help_set_help_data(check_button, _("Create an additional trace layer in all handled frames") , NULL); gtk_widget_show (check_button); gtk_table_attach(GTK_TABLE(table), check_button, col, col+1, row, row+1 ,0 , 0, 0, 0); g_object_set_data(G_OBJECT(check_button), "mgp", mgp); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (mov_tracelayer_callback), &pvals->tracelayer_enable); /* TraceOpacityInitial */ adj = p_mov_spinbutton_new( GTK_TABLE (table), col+2, row, /* table col, row */ _("TraceOpacity1:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)pvals->trace_opacity_initial, /* initial value */ (gdouble)0.0, (gdouble)100, /* lower, upper */ 1, 10, /* step, page */ 1, /* digits */ FALSE, /* constrain */ (gdouble)0.0, (gdouble)100, /* lower, upper (unconstrained) */ _("Initial opacity of the trace layer"), NULL); /* tooltip privatetip */ g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (gimp_double_adjustment_update), &pvals->trace_opacity_initial); mgp->trace_opacity_initial_adj = GTK_ADJUSTMENT(adj); /* TraceOpacityDescending */ adj = p_mov_spinbutton_new( GTK_TABLE (table), col+4, row, /* table col, row */ _("TraceOpacity2:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)pvals->trace_opacity_desc, /* initial value */ (gdouble)0.0, (gdouble)100, /* lower, upper */ 1, 10, /* step, page */ 1, /* digits */ FALSE, /* constrain */ (gdouble)0.0, (gdouble)100, /* lower, upper (unconstrained) */ _("Descending opacity of the trace layer"), NULL); /* tooltip privatetip */ g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (gimp_double_adjustment_update), &pvals->trace_opacity_desc); mgp->trace_opacity_desc_adj = GTK_ADJUSTMENT(adj); row = 1; col = 2; /* TweenSteps */ adj = p_mov_spinbutton_new( GTK_TABLE (table), col, row, /* table col, row */ _("Tweensteps:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)pvals->tween_steps, /* initial value */ (gdouble)0, (gdouble)50, /* lower, upper */ 1, 2, /* step, page */ 0, /* digits */ FALSE, /* constrain */ (gdouble)0, (gdouble)50, /* lower, upper (unconstrained) */ _("Calculate n steps between 2 frames. " "The rendered tween steps are collected in a tween layer " "that will be added to the handled destination frames. " "If the tween step value is 0, no tweens are calculated " "and no tween layers are created"), NULL); /* tooltip privatetip */ mgp->tween_steps_adj = GTK_ADJUSTMENT(adj); g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_path_tween_steps_adjustment_update), &pvals->tween_steps); /* TweenOpacityInitial */ adj = p_mov_spinbutton_new( GTK_TABLE (table), col+2, row, /* table col, row */ _("TweenOpacity1:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)pvals->tween_opacity_initial, /* initial value */ (gdouble)0.0, (gdouble)100, /* lower, upper */ 1, 10, /* step, page */ 1, /* digits */ FALSE, /* constrain */ (gdouble)0.0, (gdouble)100, /* lower, upper (unconstrained) */ _("Initial opacity of the tween layer"), NULL); /* tooltip privatetip */ g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (gimp_double_adjustment_update), &pvals->tween_opacity_initial); mgp->tween_opacity_initial_adj = GTK_ADJUSTMENT(adj); /* TweenOpacityDescending */ adj = p_mov_spinbutton_new( GTK_TABLE (table), col+4, row, /* table col, row */ _("TweenOpacity2:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)pvals->tween_opacity_desc, /* initial value */ (gdouble)0.0, (gdouble)100, /* lower, upper */ 1, 10, /* step, page */ 1, /* digits */ FALSE, /* constrain */ (gdouble)0.0, (gdouble)100, /* lower, upper (unconstrained) */ _("Descending opacity of the tween layer"), NULL); /* tooltip privatetip */ g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (gimp_double_adjustment_update), &pvals->tween_opacity_desc); mgp->tween_opacity_desc_adj = GTK_ADJUSTMENT(adj); /* set initial sensitivity */ mov_tweenlayer_sensitivity(mgp); mov_tracelayer_sensitivity(mgp); gtk_widget_show( table ); return table; } /* end mov_advanced_tab_create */ /* ============================================================================ * Create new EditCtrlPoint Frame * ============================================================================ */ static GtkWidget * mov_edit_button_box_create (t_mov_gui_stuff *mgp) { GtkWidget *vbox; GtkWidget *hbox; GtkWidget *frame; GtkWidget *button_table; GtkWidget *button; gint row; /* the vbox */ vbox = gtk_vbox_new (FALSE, 3); gtk_widget_show (vbox); /* the frame */ frame = gimp_frame_new (_("Edit Controlpoints")); gtk_container_set_border_width( GTK_CONTAINER( frame ), 2 ); /* button_table 7 rows */ button_table = gtk_table_new (7, 2, TRUE); gtk_table_set_row_spacings (GTK_TABLE (button_table), 2); gtk_table_set_col_spacings (GTK_TABLE (button_table), 2); gtk_widget_show (button_table); row = 0; /* Add Controlpoint */ button = gtk_button_new_from_stock ( GAP_STOCK_ADD_POINT ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach( GTK_TABLE(button_table), button, 0, 1, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Add controlpoint at end. The last controlpoint is duplicated.") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (mov_padd_callback), mgp); /* Grab Path (Controlpoints from current GIMP Path) */ button = gtk_button_new_from_stock ( GAP_STOCK_GRAB_POINTS ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach( GTK_TABLE(button_table), button, 1, 2, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Delete all controlpoints, and replace them with " "a copy of all anchorpoints of the current path " "from the image from which 'MovePath' was invoked. " "Hold down the Shift key to create controlpoints for each handled frame, " "following the Bezier path.") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (mov_pgrab_callback), mgp); row++; /* Insert Controlpoint */ button = gtk_button_new_from_stock ( GAP_STOCK_INSERT_POINT ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach( GTK_TABLE(button_table), button, 0, 1, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Insert controlpoint. The current controlpoint is duplicated.") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (mov_pins_callback), mgp); /* Delete Controlpoint */ button = gtk_button_new_from_stock ( GAP_STOCK_DELETE_POINT ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach( GTK_TABLE(button_table), button, 1, 2, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Delete current controlpoint") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (mov_pdel_callback), mgp); row++; /* Previous Controlpoint */ button = gtk_button_new_from_stock ( GAP_STOCK_PREV_POINT ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach( GTK_TABLE(button_table), button, 0, 1, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Show previous controlpoint. Hold down the shift key to follow keyframes.") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (mov_pprev_callback), mgp); /* Next Controlpoint */ button = gtk_button_new_from_stock ( GAP_STOCK_NEXT_POINT ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach( GTK_TABLE(button_table), button, 1, 2, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Show next controlpoint. Hold down the shift key to follow keyframes.") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (mov_pnext_callback), mgp); row++; /* First Controlpoint */ button = gtk_button_new_from_stock ( GAP_STOCK_FIRST_POINT ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach( GTK_TABLE(button_table), button, 0, 1, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Show first controlpoint. Hold down the shift key to follow keyframes.") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (mov_pfirst_callback), mgp); /* Last Controlpoint */ button = gtk_button_new_from_stock ( GAP_STOCK_LAST_POINT ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach( GTK_TABLE(button_table), button, 1, 2, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Show last controlpoint. Hold down the shift key to follow keyframes.") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (mov_plast_callback), mgp); row++; /* Reset Controlpoint */ button = gtk_button_new_from_stock ( GAP_STOCK_RESET_POINT ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach( GTK_TABLE(button_table), button, 0, 1, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Reset the current controlpoint to default values") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (mov_pclr_callback), mgp); /* Reset All Controlpoints */ button = gtk_button_new_from_stock ( GAP_STOCK_RESET_ALL_POINTS ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach( GTK_TABLE(button_table), button, 1, 2, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Reset all controlpoints to default values " "but dont change the path (X/Y values). " "Hold down the shift key to copy settings " "of point1 into all other points. " "Holding down the ctrl key spreads a mix of " "the settings of point1 and the last point " "into the other points inbetween.") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (mov_pclr_all_callback), mgp); row++; /* Rotate Follow */ button = gtk_button_new_from_stock ( GAP_STOCK_ROTATE_FOLLOW ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach( GTK_TABLE(button_table), button, 0, 1, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Set rotation for all controlpoints " "to follow the shape of the path. " "Hold down the shift key to use rotation of contolpoint 1 as offset.") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (mov_prot_follow_callback), mgp); /* Delete All Controlpoints */ button = gtk_button_new_from_stock ( GAP_STOCK_DELETE_ALL_POINTS ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach( GTK_TABLE(button_table), button, 1, 2, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Delete all controlpoints") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (mov_pdel_all_callback), mgp); row++; /* Load Controlpoints */ button = gtk_button_new_from_stock (GTK_STOCK_OPEN ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach( GTK_TABLE(button_table), button, 0, 1, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Load controlpoints from file") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (mov_pload_callback), mgp); /* Save Controlpoints */ button = gtk_button_new_from_stock ( GTK_STOCK_SAVE ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_table_attach( GTK_TABLE(button_table), button, 1, 2, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Save controlpoints to file") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (mov_psave_callback), mgp); row++; gtk_widget_show(button_table); gtk_widget_show(frame); /* the hbox */ hbox = gtk_hbox_new (FALSE, 3); gtk_widget_show (hbox); gtk_box_pack_start (GTK_BOX (hbox), button_table, FALSE, FALSE, 4); gtk_container_add (GTK_CONTAINER (frame), hbox); gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 4); return vbox; } /* end mov_edit_button_box_create */ /* ============================================================================ * Create set of widgets for the framerange and layerstack widgets * ============================================================================ * vertical_layout == FALSE * +-master_table-------------------------+----------------------+ * | +-----------+--------+------------+ | +-vcbox-----------+ | * | | FromFrame | scale | spinbutton | | | | | * | +-----------+--------+------------+ | | ForceVisibility | | * | | ToFrame | scale | spinbutton | | | | | * | +-----------+--------+------------+ | | Clip To Frame | | * | | Layerstack| scale | spinbutton | | | | | * | +-----------+--------+------------+ | +-----------------+ | * +--------------------------------------+----------------------+ * * vertical_layout == TRUE * * +-master_table-------------------------+ * | +-vcbox---------------------------+ | * | | ForceVisibility | | * | | Clip To Frame | | * | +---------------------------------+ | * +--------------------------------------+ * | +-----------+--------+------------+ + * | | FromFrame | scale | spinbutton | | * | +-----------+--------+------------+ | * | | ToFrame | scale | spinbutton | | * | +-----------+--------+------------+ | * | | Layerstack| scale | spinbutton | | * | +-----------+--------+------------+ | * +--------------------------------------+ */ GtkWidget * mov_path_framerange_box_create(t_mov_gui_stuff *mgp ,gboolean vertical_layout ) { GtkWidget *vcbox; GtkWidget *master_table; GtkWidget *table; GtkObject *adj; GtkWidget *check_button; gint master_rows; gint master_cols; gint tabcol, tabrow, boxcol, boxrow; if(vertical_layout) { master_rows = 2; master_cols = 1; tabcol = 0; tabrow = 1; boxcol = 0; boxrow = 0; } else { master_rows = 1; master_cols = 2; tabcol = 0; tabrow = 0; boxcol = 1; boxrow = 0; } /* the master_table (1 row) */ master_table = gtk_table_new (master_rows, master_cols, FALSE); gtk_widget_show (master_table); /* table with 3 rows */ table = gtk_table_new (3, 3, FALSE); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_table_attach(GTK_TABLE(master_table), table, tabcol, tabcol+1, tabrow, tabrow+1 , GTK_FILL|GTK_EXPAND, GTK_FILL, 4, 0); gtk_widget_show (table); /* the start frame scale_entry */ adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 0, /* table col, row */ _("From Frame:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)pvals->dst_range_start, /* value */ (gdouble)mgp->first_nr, /* lower */ (gdouble)mgp->last_nr, /* upper */ 1, 10, /* step, page */ 0, /* digits */ TRUE, /* constrain */ (gdouble)mgp->first_nr, /* lower, (unconstrained) */ (gdouble)mgp->last_nr, /* upper (unconstrained) */ _("First handled destination frame"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (gimp_int_adjustment_update), &pvals->dst_range_start); /* the end frame scale_entry */ adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 1, /* table col, row */ _("To Frame:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)pvals->dst_range_end, /* value */ (gdouble)mgp->first_nr, /* lower */ (gdouble)mgp->last_nr, /* upper */ 1, 10, /* step, page */ 0, /* digits */ TRUE, /* constrain */ (gdouble)mgp->first_nr, /* lower, (unconstrained) */ (gdouble)mgp->last_nr, /* upper (unconstrained) */ _("Last handled destination frame"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (gimp_int_adjustment_update), &pvals->dst_range_end); /* the Layerstack scale_entry */ adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 2, /* table col, row */ _("Layerstack:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)pvals->dst_layerstack, /* value */ 0.0, 99.0, /* lower, upper */ 1, 10, /* step, page */ 0, /* digits */ FALSE, /* constrain */ 0.0, 999999.0, /* lower, upper (unconstrained) */ _("How to insert source layer into the " "layerstack of the destination frames. " "layerstack 0 means on top i.e. in front"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_instant_int_adjustment_update), &pvals->dst_layerstack); /* the vbox for checkbuttons */ vcbox = gtk_vbox_new (FALSE, 3); gtk_widget_show (vcbox); /* toggle force visibility */ check_button = gtk_check_button_new_with_label ( _("Force Visibility")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), pvals->src_force_visible); gimp_help_set_help_data(check_button, _("Force visibility for all copied source layers") , NULL); gtk_widget_show (check_button); g_object_set_data(G_OBJECT(check_button), "mgp", mgp); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (mov_force_visibility_toggle_callback), &pvals->src_force_visible); gtk_box_pack_start (GTK_BOX (vcbox), check_button, TRUE, TRUE, 0); /* toggle clip_to_image */ check_button = gtk_check_button_new_with_label ( _("Clip To Frame")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), pvals->clip_to_img); gimp_help_set_help_data(check_button, _("Clip all copied source layers at destination frame boundaries") , NULL); gtk_widget_show (check_button); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (mov_gint_toggle_callback), &pvals->clip_to_img); gtk_box_pack_start (GTK_BOX (vcbox), check_button, TRUE, TRUE, 0); gtk_table_attach(GTK_TABLE(master_table), vcbox, boxcol, boxcol+1, boxrow, boxrow+1 , GTK_FILL, GTK_FILL, 4, 0); return(master_table); } /* end mov_path_framerange_box_create */ /* ============================================================================ * Create VBox with * The VBox contains * - Resize 2x spinbutton (for resizing Width + Height in percent) * chainbutton (for constrain both resize widgets) * - Opacity spinbutton (0.0 upto 100.0 %) * - Rotation spinbutton (-360.0 to 360.0 degrees) * ============================================================================ */ static GtkWidget* mov_modify_tab_create(t_mov_gui_stuff *mgp) { GtkWidget *vbox; GtkWidget *table; GtkObject *adj; /* the vbox */ vbox = gtk_vbox_new (FALSE, 3); gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); /* the table (2 rows) */ table = gtk_table_new ( 2, 6, FALSE ); gtk_container_set_border_width (GTK_CONTAINER (table), 2 ); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); /* Width Scale */ adj = p_mov_spinbutton_new( GTK_TABLE (table), 0, 0, /* table col, row */ _("Width:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->w_resize, /* value */ (gdouble)1, (gdouble)200, /* lower, upper */ 1, 10, /* step, page */ 1, /* digits */ FALSE, /* constrain */ (gdouble)1, (gdouble)1000, /* lower, upper (unconstrained) */ _("Scale source layer's width in percent"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_path_resize_adjustment_update), &mgp->w_resize); mgp->wres_adj = GTK_ADJUSTMENT(adj); /* Height Scale */ adj = p_mov_spinbutton_new( GTK_TABLE (table), 0, 1, /* table col, row */ _("Height:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->h_resize, /* value */ (gdouble)1, (gdouble)200, /* lower, upper */ 1, 10, /* step, page */ 1, /* digits */ FALSE, /* constrain */ (gdouble)1, (gdouble)1000, /* lower, upper (unconstrained) */ _("Scale source layer's height in percent"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_path_resize_adjustment_update), &mgp->h_resize); mgp->hres_adj = GTK_ADJUSTMENT(adj); /* the constrain ratio chainbutton */ mgp->constrain = gimp_chain_button_new (GIMP_CHAIN_RIGHT); gimp_chain_button_set_active (GIMP_CHAIN_BUTTON (mgp->constrain), TRUE); gtk_table_attach (GTK_TABLE (table), mgp->constrain, 2, 3, 0, 2 , 0,0,0,0); gtk_widget_show (mgp->constrain); gimp_help_set_help_data (GIMP_CHAIN_BUTTON (mgp->constrain)->button, _("Constrain aspect ratio"), NULL); /* the state of the contrain ratio chainbutton is checked in other callbacks (where needed) * there is no need for the chainbutton to have its own callback procedure */ /* Opacity */ adj = gimp_scale_entry_new( GTK_TABLE (table), 3, 0, /* table col, row */ _("Opacity:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->opacity, /* value */ (gdouble)0, (gdouble)100, /* lower, upper */ 1, 10, /* step, page */ 1, /* digits */ TRUE, /* constrain */ (gdouble)0, (gdouble)100, /* lower, upper (unconstrained) */ _("Set the source layer's opacity in percent"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_instant_double_adjustment_update), &mgp->opacity); mgp->opacity_adj = GTK_ADJUSTMENT(adj); /* Rotation */ adj = gimp_scale_entry_new( GTK_TABLE (table), 3, 1, /* table col, row */ _("Rotate:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->rotation, /* value */ (gdouble)-360, (gdouble)360, /* lower, upper */ 1, 45, /* step, page */ 1, /* digits */ FALSE, /* constrain */ (gdouble)-3600, (gdouble)3600, /* lower, upper (unconstrained) */ _("Rotate source layer (in degrees)"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_instant_double_adjustment_update), &mgp->rotation); mgp->rotation_adj = GTK_ADJUSTMENT(adj); gtk_widget_show (table); gtk_widget_show (vbox); /* copile without MOVE_PATH_LAYOUT_frame needs less space */ return vbox; } /* end mov_modify_tab_create */ /* ============================================================================ * Create VBox with the 8 transformation factors and return it. * The VBox contains * - Transform 8x spinbutton (0.01 upto 10.0) 4-point perspective transformation * ============================================================================ */ static GtkWidget * mov_trans_tab_create (t_mov_gui_stuff *mgp) { GtkWidget *vbox; GtkWidget *table; GtkObject *adj; /* the vbox */ vbox = gtk_vbox_new (FALSE, 3); gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); /* the table (2 rows) */ table = gtk_table_new ( 2, 8, FALSE ); gtk_container_set_border_width (GTK_CONTAINER (table), 2 ); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); /* ttlx transformfactor */ adj = p_mov_spinbutton_new( GTK_TABLE (table), 0, 0, /* table col, row */ _("x1:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->ttlx, /* initial value */ (gdouble)0, (gdouble)10, /* lower, upper */ 0.1, 1, /* step, page */ 3, /* digits */ FALSE, /* constrain */ (gdouble)0, (gdouble)10, /* lower, upper (unconstrained) */ _("Transformfactor for upper left corner X coordinate"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_path_tfactor_adjustment_update), &mgp->ttlx); mgp->ttlx_adj = GTK_ADJUSTMENT(adj); /* ttly transformfactor */ adj = p_mov_spinbutton_new( GTK_TABLE (table), 2, 0, /* table col, row */ _("y1:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->ttly, /* initial value */ (gdouble)0, (gdouble)10, /* lower, upper */ 0.1, 1, /* step, page */ 3, /* digits */ FALSE, /* constrain */ (gdouble)0, (gdouble)10, /* lower, upper (unconstrained) */ _("Transformfactor for upper left corner Y coordinate"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_path_tfactor_adjustment_update), &mgp->ttly); mgp->ttly_adj = GTK_ADJUSTMENT(adj); /* ttrx transformfactor */ adj = p_mov_spinbutton_new( GTK_TABLE (table), 4, 0, /* table col, row */ _("x2:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->ttrx, /* initial value */ (gdouble)0, (gdouble)10, /* lower, upper */ 0.1, 1, /* step, page */ 3, /* digits */ FALSE, /* constrain */ (gdouble)0, (gdouble)10, /* lower, upper (unconstrained) */ _("Transformfactor for upper right corner X coordinate"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_path_tfactor_adjustment_update), &mgp->ttrx); mgp->ttrx_adj = GTK_ADJUSTMENT(adj); /* ttry transformfactor */ adj = p_mov_spinbutton_new( GTK_TABLE (table), 6, 0, /* table col, row */ _("y2:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->ttry, /* initial value */ (gdouble)0, (gdouble)10, /* lower, upper */ 0.1, 1, /* step, page */ 3, /* digits */ FALSE, /* constrain */ (gdouble)0, (gdouble)10, /* lower, upper (unconstrained) */ _("Transformfactor for upper right corner Y coordinate"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_path_tfactor_adjustment_update), &mgp->ttry); mgp->ttry_adj = GTK_ADJUSTMENT(adj); /* tblx transformfactor */ adj = p_mov_spinbutton_new( GTK_TABLE (table), 0, 1, /* table col, row */ _("x3:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->tblx, /* initial value */ (gdouble)0, (gdouble)10, /* lower, upper */ 0.1, 1, /* step, page */ 3, /* digits */ FALSE, /* constrain */ (gdouble)0, (gdouble)10, /* lower, upper (unconstrained) */ _("Transformfactor for lower left corner X coordinate"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_path_tfactor_adjustment_update), &mgp->tblx); mgp->tblx_adj = GTK_ADJUSTMENT(adj); /* tbly transformfactor */ adj = p_mov_spinbutton_new( GTK_TABLE (table), 2, 1, /* table col, row */ _("y3:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->tbly, /* initial value */ (gdouble)0, (gdouble)10, /* lower, upper */ 0.1, 1, /* step, page */ 3, /* digits */ FALSE, /* constrain */ (gdouble)0, (gdouble)10, /* lower, upper (unconstrained) */ _("Transformfactor for lower left corner Y coordinate"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_path_tfactor_adjustment_update), &mgp->tbly); mgp->tbly_adj = GTK_ADJUSTMENT(adj); /* tbrx transformfactor */ adj = p_mov_spinbutton_new( GTK_TABLE (table), 4, 1, /* table col, row */ _("x4:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->tbrx, /* initial value */ (gdouble)0, (gdouble)10, /* lower, upper */ 0.1, 1, /* step, page */ 3, /* digits */ FALSE, /* constrain */ (gdouble)0, (gdouble)10, /* lower, upper (unconstrained) */ _("Transformfactor for lower right corner X coordinate"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_path_tfactor_adjustment_update), &mgp->tbrx); mgp->tbrx_adj = GTK_ADJUSTMENT(adj); /* tbry transformfactor */ adj = p_mov_spinbutton_new( GTK_TABLE (table), 6, 1, /* table col, row */ _("y4:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->tbry, /* initial value */ (gdouble)0, (gdouble)10, /* lower, upper */ 0.1, 1, /* step, page */ 3, /* digits */ FALSE, /* constrain */ (gdouble)0, (gdouble)10, /* lower, upper (unconstrained) */ _("Transformfactor for lower right corner Y coordinate"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_path_tfactor_adjustment_update), &mgp->tbry); mgp->tbry_adj = GTK_ADJUSTMENT(adj); gtk_widget_show(table); gtk_widget_show(vbox); return vbox; } /* end mov_trans_tab_create */ /* ============================================================================ * Create VBox with the selection handling widgets and return it. * ============================================================================ */ static GtkWidget * mov_selection_handling_tab_create (t_mov_gui_stuff *mgp) { GtkWidget *combo; GtkWidget *vbox; GtkWidget *table; GtkObject *adj; /* the vbox */ vbox = gtk_vbox_new (FALSE, 3); gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); /* the table (2 rows) */ table = gtk_table_new ( 2, 3, FALSE ); gtk_container_set_border_width (GTK_CONTAINER (table), 2 ); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); /* Selection combo */ combo = gimp_int_combo_box_new (_("Ignore selection (in all source images)"), GAP_MOV_SEL_IGNORE, _("Use selection (from initial source image)"), GAP_MOV_SEL_INITIAL, _("Use selections (from all source images)"), GAP_MOV_SEL_FRAME_SPECIFIC, NULL); gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), GAP_MOV_SEL_IGNORE, /* initial int value */ G_CALLBACK (mov_selmode_menu_callback), mgp); gtk_table_attach(GTK_TABLE(table), combo, 0, 3, 0, 1, 0, 0, 0, 0); gimp_help_set_help_data(combo, _("How to handle selections in the source image") , NULL); gtk_widget_show(combo); /* ttlx transformfactor */ adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 1, /* table col, row */ _("Selection Feather Radius:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->sel_feather_radius, /* initial value */ (gdouble)0, (gdouble)100, /* lower, upper */ 1.0, 10.0, /* step, page */ 1, /* digits */ FALSE, /* constrain */ (gdouble)0, (gdouble)1000, /* lower, upper (unconstrained) */ _("Feather radius in pixels (for smoothing selection(s))"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_path_feather_adjustment_update), &mgp->sel_feather_radius); mgp->sel_feather_radius_adj = GTK_ADJUSTMENT(adj); /* for initial sensitivity */ gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), pvals->src_selmode); gtk_widget_show(table); gtk_widget_show(vbox); return vbox; } /* end mov_selection_handling_tab_create */ /* ============================================================================ * Create all Widget Blocks that represent * - The current contolpoint settings * - The Preview * - The Buttonbox for Editing Controlpoints * and attach those Blocks to the mgp->master_vbox Widget. * * One "ControlPoint" has: * - 2 spinbuttons X/Y, used for positioning * - Keyframe spinbutton integer (0 to max_frame) * - Notebook with following sub tables: * - transform SubTable 4-point perspective transformation * - modify SubTable for Resize(Scaling), Opacity and Rotation * ============================================================================ */ static void mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean vertical_layout) { GtkWidget *cpt_frame; GtkWidget *pv_frame; GtkWidget *wrap_box; GtkWidget *vbox; GtkWidget *hbox; GtkWidget *notebook; GtkWidget *table; GtkWidget *label; GtkWidget *aspect_frame; GtkWidget *da_widget; GtkWidget *pv_table; GtkWidget *pv_sub_table; GtkWidget *check_button; GtkObject *adj; GtkWidget *framerange_table; GtkWidget *edit_buttons; mgp->drawable = drawable; mgp->dwidth = gimp_drawable_width(drawable->drawable_id ); mgp->dheight = gimp_drawable_height(drawable->drawable_id ); mgp->bpp = gimp_drawable_bpp(drawable->drawable_id); if ( gimp_drawable_has_alpha(drawable->drawable_id) ) mgp->bpp--; mgp->curx = 0; mgp->cury = 0; mgp->in_call = TRUE; /* to avoid side effects while initialization */ /* the vbox */ vbox = gtk_vbox_new (FALSE, 3); gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); gtk_widget_show (vbox); gtk_box_pack_start (GTK_BOX (mgp->master_vbox), vbox, TRUE, TRUE, 0); /* the cpt_frame */ cpt_frame = gimp_frame_new (" "); /* text "Current Point: [ %3d ] of [ %3d ]" * is set later in procedure p_update_point_index_text */ gtk_container_set_border_width( GTK_CONTAINER( cpt_frame ), 2 ); mgp->point_index_frame = cpt_frame; p_update_point_index_text(mgp); gtk_box_pack_start (GTK_BOX (vbox), cpt_frame, FALSE, FALSE, 0); gtk_widget_show( mgp->master_vbox ); gtk_widget_show( cpt_frame ); /* the table (3 rows) for other controlpoint specific settings */ table = gtk_table_new ( 3, 4, FALSE ); gtk_container_set_border_width (GTK_CONTAINER (table), 2 ); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_container_add (GTK_CONTAINER (cpt_frame), table); /* X */ adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 0, /* table col, row */ _("X:"), /* label text */ SCALE_WIDTH, SPINBUTTON_WIDTH, /* scalesize spinsize */ (gdouble)mgp->p_x, /* value */ (gdouble)0, (gdouble)mgp->dwidth, /* lower, upper */ 1, 10, /* step, page */ 0, /* digits */ FALSE, /* constrain */ (gdouble)(-GIMP_MAX_IMAGE_SIZE), (gdouble)GIMP_MAX_IMAGE_SIZE, /* lower, upper (unconstrained) */ _("X coordinate"), NULL); /* tooltip privatetip */ g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_path_x_adjustment_update), mgp); mgp->x_adj = GTK_ADJUSTMENT(adj); /* Y */ adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 1, /* table col, row */ _("Y:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->p_y, /* value */ (gdouble)0, (gdouble)mgp->dheight, /* lower, upper */ 1, 10, /* step, page */ 0, /* digits */ FALSE, /* constrain */ (gdouble)(-GIMP_MAX_IMAGE_SIZE), (gdouble)GIMP_MAX_IMAGE_SIZE, /* lower, upper (unconstrained) */ _("Y coordinate"), NULL); /* tooltip privatetip */ g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_path_y_adjustment_update), mgp); mgp->y_adj = GTK_ADJUSTMENT(adj); /* Keyframe */ adj = p_mov_spinbutton_new( GTK_TABLE (table), 1, 2, /* table col, row */ _("Keyframe:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->keyframe_abs, /* value */ (gdouble)0, (gdouble)mgp->max_frame, /* lower, upper */ 1, 10, /* step, page */ 0, /* digits */ TRUE, /* constrain */ (gdouble)0, (gdouble)mgp->max_frame, /* lower, upper (unconstrained) */ _("Fix controlpoint to keyframe number where 0 == no keyframe"), NULL); /* tooltip privatetip */ g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (gimp_int_adjustment_update), &mgp->keyframe_abs); mgp->keyframe_adj = GTK_ADJUSTMENT(adj); /* the notebook */ notebook = gtk_notebook_new(); { GtkWidget *modify_table; GtkWidget *transform_table; GtkWidget *selhandling_table; /* set of modifier widgets for the current controlpoint */ modify_table = mov_modify_tab_create(mgp); /* set of perspective transformation widgets for the current controlpoint */ transform_table = mov_trans_tab_create(mgp); /* set of perspective transformation widgets for the current controlpoint */ selhandling_table = mov_selection_handling_tab_create(mgp); gtk_container_add (GTK_CONTAINER (notebook), modify_table); label = gtk_label_new(_("Scale and Modify")); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook) , gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 0) , label ); gtk_container_add (GTK_CONTAINER (notebook), transform_table); label = gtk_label_new(_("Perspective")); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook) , gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 1) , label ); gtk_container_add (GTK_CONTAINER (notebook), selhandling_table); label = gtk_label_new(_("Selection Handling")); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook) , gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 2) , label ); } gtk_table_attach(GTK_TABLE(table), notebook, 3, 4 /* column */ , 0, 3 /* all rows */ , 0, 0, 0, 0); gtk_widget_show (notebook); gtk_widget_show( table ); /* the hbox (for preview table and Edit Controlpoint Frame) */ hbox = gtk_hbox_new (FALSE, 3); gtk_widget_show (hbox); gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); /* the preview frame */ pv_frame = gimp_frame_new ( _("Preview")); gtk_container_set_border_width (GTK_CONTAINER (pv_frame), 2); gtk_box_pack_start (GTK_BOX (hbox), pv_frame, TRUE, TRUE, 0); gtk_widget_show (pv_frame); /* the preview table (3 rows) */ pv_table = gtk_table_new ( 3, 1, FALSE ); gtk_container_set_border_width (GTK_CONTAINER (pv_table), 2 ); gtk_table_set_row_spacings (GTK_TABLE (pv_table), 2); gtk_table_set_col_spacings (GTK_TABLE (pv_table), 4); gtk_container_add (GTK_CONTAINER (pv_frame), pv_table); gtk_widget_show( pv_table ); /* * Resize the greater one of dwidth and dheight to PREVIEW_SIZE */ if ( mgp->dwidth > mgp->dheight ) { mgp->pheight = mgp->dheight * PREVIEW_SIZE / mgp->dwidth; mgp->pheight = MAX (1, mgp->pheight); mgp->pwidth = PREVIEW_SIZE; } else { mgp->pwidth = mgp->dwidth * PREVIEW_SIZE / mgp->dheight; mgp->pwidth = MAX (1, mgp->pwidth); mgp->pheight = PREVIEW_SIZE; } /* preview dummy widgets */ { GtkWidget *table11; GtkWidget *dummy; gint ix; gint iy; /* aspect_frame is the CONTAINER for the preview drawing area */ aspect_frame = gtk_aspect_frame_new (NULL /* without label */ , 0.5 /* xalign center */ , 0.5 /* yalign center */ , mgp->pwidth / mgp->pheight /* ratio */ , TRUE /* obey_child */ ); /* table11 is used to center aspect_frame */ table11 = gtk_table_new (3, 3, FALSE); gtk_widget_show (table11); for(ix = 0; ix < 3; ix++) { for(iy = 0; iy < 3; iy++) { if((ix == 1) && (iy == 1)) { gtk_table_attach (GTK_TABLE (table11), aspect_frame, ix, ix+1, iy, iy+1, (GtkAttachOptions) (GTK_FILL | GTK_SHRINK | GTK_EXPAND), (GtkAttachOptions) (GTK_FILL | GTK_SHRINK | GTK_EXPAND), 0, 0); } else { /* dummy widgets to fill up table11 */ dummy = gtk_vbox_new (FALSE,3); gtk_widget_show (dummy); gtk_table_attach (GTK_TABLE (table11), dummy, ix, ix+1, iy, iy+1, (GtkAttachOptions) (GTK_FILL | GTK_SHRINK | GTK_EXPAND), (GtkAttachOptions) (GTK_FILL | GTK_SHRINK | GTK_EXPAND), 0, 0); } } } wrap_box = gtk_vbox_new (FALSE,3); gtk_box_pack_start (GTK_BOX (wrap_box), table11, FALSE, FALSE, 0); gtk_widget_show(wrap_box); gtk_table_attach (GTK_TABLE (pv_table), wrap_box, 0, 1, 0, 1, (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL), (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL), 0, 0); } /* hbox_show block */ { GtkWidget *hbox_show; hbox_show = gtk_hbox_new (FALSE, 3); gtk_widget_show (hbox_show); /* pathclor selction button */ { GtkWidget *color_button; gimp_rgb_set(&mgp->pathcolor, 1.0, 0.1, 0.1); /* startup with RED pathline color */ gimp_rgb_set_alpha(&mgp->pathcolor, 1.0); color_button = gimp_color_button_new (_("Pathline Color Picker"), 25, 12, /* WIDTH, HEIGHT, */ &mgp->pathcolor, GIMP_COLOR_AREA_FLAT); gtk_box_pack_start (GTK_BOX (hbox_show), color_button, TRUE, TRUE, 4); gtk_widget_show (color_button); gimp_help_set_help_data(color_button, _("Select the color that is used to " "draw pathlines in the preview") , NULL); g_signal_connect (color_button, "color_changed", G_CALLBACK (mov_path_colorbutton_update), mgp); } /* toggle Show path */ check_button = gtk_check_button_new_with_label ( _("Path")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), mgp->show_path); gimp_help_set_help_data(check_button, _("Show path lines and enable " "pick/drag with left button " "or move with right button") , NULL); gtk_widget_show (check_button); gtk_box_pack_start (GTK_BOX (hbox_show), check_button, TRUE, TRUE, 0); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (mov_show_path_callback), mgp); /* toggle Show cursor */ check_button = gtk_check_button_new_with_label ( _("Cursor")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), mgp->show_cursor); gimp_help_set_help_data(check_button, _("Show cursor crosslines") , NULL); gtk_widget_show (check_button); gtk_box_pack_start (GTK_BOX (hbox_show), check_button, TRUE, TRUE, 0); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (mov_show_cursor_callback), mgp); /* toggle Show Grid */ check_button = gtk_check_button_new_with_label ( _("Grid")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), mgp->show_grid); gimp_help_set_help_data(check_button, _("Show source layer as gridlines") , NULL); //XX gtk_widget_show (check_button); gtk_box_pack_start (GTK_BOX (hbox_show), check_button, TRUE, TRUE, 0); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (mov_show_grid_callback), mgp); /* toggle Instant Apply */ check_button = gtk_check_button_new_with_label ( _("Instant Apply")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), mgp->instant_apply); gimp_help_set_help_data(check_button, _("Update the preview automatically") , NULL); gtk_widget_show (check_button); gtk_box_pack_start (GTK_BOX (hbox_show), check_button, TRUE, TRUE, 0); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (mov_instant_apply_callback), mgp); gtk_table_attach(GTK_TABLE(pv_table), hbox_show, 0, 1, 1, 2, 0, 0, 16, 0); } /* the preview sub table (1 row) */ pv_sub_table = gtk_table_new ( 1, 3, FALSE ); /* the Preview Frame Number */ adj = gimp_scale_entry_new( GTK_TABLE (pv_sub_table), 0, 1, /* table col, row */ _("Frame:"), /* label text */ SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */ (gdouble)mgp->preview_frame_nr, /* value */ (gdouble)mgp->first_nr, /* lower */ (gdouble)mgp->last_nr, /* upper */ 1, 10, /* step, page */ 0, /* digits */ TRUE, /* constrain */ (gdouble)mgp->first_nr, /* lower (unconstrained)*/ (gdouble)mgp->last_nr, /* upper (unconstrained)*/ _("Frame to show when 'Refresh' button is pressed"), NULL); /* tooltip privatetip */ g_object_set_data(G_OBJECT(adj), "mgp", mgp); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (mov_instant_int_adjustment_update), &mgp->preview_frame_nr); mgp->preview_frame_nr_adj = GTK_ADJUSTMENT(adj); gtk_table_attach( GTK_TABLE(pv_table), pv_sub_table, 0, 1, 2, 3, GTK_FILL|GTK_EXPAND, 0, 0, 0 ); gtk_widget_show (pv_sub_table); /* PREVIEW DRAWING AREA */ mgp->pv_ptr = gap_pview_new(mgp->pwidth , mgp->pheight , GAP_MOV_CHECK_SIZE , aspect_frame ); da_widget = mgp->pv_ptr->da_widget; g_object_set_data( G_OBJECT(da_widget), "mgp", mgp); gtk_widget_set_events( GTK_WIDGET(da_widget), PREVIEW_MASK ); g_signal_connect_after( G_OBJECT(da_widget), "expose_event", G_CALLBACK (mov_path_prevw_preview_expose), mgp ); g_signal_connect( G_OBJECT(da_widget), "event", G_CALLBACK (mov_path_prevw_preview_events), mgp ); gtk_container_add( GTK_CONTAINER( aspect_frame ), da_widget); gtk_widget_show(da_widget); gtk_widget_show(aspect_frame); /* keep track of resizing events of the preview * for automatic preview scale when more or less layoutspace is available. */ g_signal_connect_after (G_OBJECT (wrap_box), "size_allocate", G_CALLBACK (mov_pview_size_allocate_callback), mgp); /* Draw the contents of preview, that is saved in the preview widget */ mov_path_prevw_preview_init( mgp ); /* edit buttons table */ edit_buttons = mov_edit_button_box_create(mgp); if(vertical_layout) { GtkWidget *vvbox; vvbox = gtk_vbox_new(FALSE, 3); gtk_widget_show (vvbox); framerange_table = mov_path_framerange_box_create(mgp, vertical_layout); gtk_box_pack_start (GTK_BOX (vvbox), edit_buttons, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (vvbox), framerange_table, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox), vvbox, FALSE, FALSE, 0); } else { gtk_box_pack_start (GTK_BOX (hbox), edit_buttons, FALSE, FALSE, 0); } mov_path_prevw_cursor_update( mgp ); mgp->in_call = FALSE; /* End of initialization */ if(gap_debug) printf("pvals mgp=%d,%d\n", mgp->p_x, mgp->p_y ); if(gap_debug) printf("mgp cur=%d,%d\n", mgp->curx, mgp->cury ); } /* end mov_path_prevw_create */ /* ============================================================================ * mov_path_prevw_preview_init * Initialize preview * Draw the contents into the internal buffer of the preview widget * ============================================================================ */ static void mov_path_prevw_preview_init ( t_mov_gui_stuff *mgp ) { gint32 image_id; if(gap_debug) printf ("mov_path_prevw_preview_init: START\n"); if(mgp->pv_ptr) { if(gap_debug) printf ("mov_path_prevw_preview_init:" " before gap_pview_render_from_image drawable_id:%d\n" , (int)mgp->drawable->drawable_id); image_id = gimp_drawable_get_image(mgp->drawable->drawable_id); if(gap_debug) printf ("mov_path_prevw_preview_init:" " after gap_pview_render_from_image drawable_id:%d image_id:%d\n" , (int)mgp->drawable->drawable_id , (int)image_id ); gap_pview_render_from_image(mgp->pv_ptr, image_id); } } /* ============================================================================ * mov_path_prevw_draw * Preview Rendering Util routine End * if update & PATH_LINE, draw the path lines * if update & CURSOR, draw cross cursor * ============================================================================ */ static void mov_path_prevw_draw ( t_mov_gui_stuff *mgp, gint update ) { gint l_idx; GdkColor fg; GdkColormap *cmap; guchar l_red, l_green, l_blue; if(gap_debug) printf("mov_path_prevw_draw: START update:%d\n", (int)update); if(mgp->pv_ptr == NULL) { return; } if(mgp->pv_ptr->da_widget==NULL) { return; } if(gap_debug) printf("mov_path_prevw_draw: gap_pview_repaint\n"); gap_pview_repaint(mgp->pv_ptr); /* alternate cross cursor OR path graph */ if((mgp->show_path) && ( pvals != NULL ) && (update & PATH_LINE)) { /* redraw the preview * (to clear path lines and cross cursor) */ gimp_rgb_get_uchar (&mgp->pathcolor, &l_red, &l_green, &l_blue); cmap = gtk_widget_get_colormap(mgp->pv_ptr->da_widget); fg.red = (l_red << 8) | l_red; fg.green = (l_green << 8) | l_green; fg.blue = (l_blue << 8) | l_blue; /*if(gap_debug) printf ("fg.r/g/b (%d %d %d)\n", (int)fg.red ,(int)fg.green, (int)fg.blue); */ if(cmap) { gdk_colormap_alloc_color(cmap , &fg , FALSE /* writeable */ , TRUE /* best_match */ ); } /*if(gap_debug) printf ("fg.pixel (%d)\n", (int)fg.pixel); */ gdk_gc_set_foreground (mgp->pv_ptr->da_widget->style->black_gc, &fg); p_points_to_tab(mgp); for(l_idx = 0; l_idx < pvals->point_idx_max; l_idx++) { /* draw the path line(s) */ gdk_draw_line (mgp->pv_ptr->da_widget->window, mgp->pv_ptr->da_widget->style->black_gc, (pvals->point[l_idx].p_x * mgp->pwidth) / mgp->dwidth, (pvals->point[l_idx].p_y * mgp->pheight) / mgp->dheight, (pvals->point[l_idx +1].p_x * mgp->pwidth) / mgp->dwidth, (pvals->point[l_idx +1].p_y * mgp->pheight) / mgp->dheight ); /* draw the path point(s) */ gdk_draw_arc (mgp->pv_ptr->da_widget->window, mgp->pv_ptr->da_widget->style->black_gc, TRUE, (pvals->point[l_idx +1].p_x * mgp->pwidth / mgp->dwidth) -RADIUS, (pvals->point[l_idx +1].p_y * mgp->pheight / mgp->dheight) -RADIUS, RADIUS * 2, RADIUS * 2, 0, 23040); } /* draw the start point */ gdk_draw_arc (mgp->pv_ptr->da_widget->window, mgp->pv_ptr->da_widget->style->black_gc, TRUE, (pvals->point[0].p_x * mgp->pwidth / mgp->dwidth) -RADIUS, (pvals->point[0].p_y * mgp->pheight / mgp->dheight) -RADIUS, RADIUS * 2, RADIUS * 2, 0, 23040); /* restore black gc */ fg.red = 0; fg.green = 0; fg.blue = 0; if(cmap) { gdk_colormap_alloc_color(cmap , &fg , FALSE /* writeable */ , TRUE /* best_match */ ); } gdk_gc_set_foreground (mgp->pv_ptr->da_widget->style->black_gc, &fg); } /* draw CURSOR */ if(mgp->show_cursor) { if(gap_debug) printf("mov_path_prevw_draw: draw-cursor cur=%d,%d\n" , mgp->curx , mgp->cury ); gdk_gc_set_function ( mgp->pv_ptr->da_widget->style->black_gc, GDK_INVERT); gdk_draw_line ( mgp->pv_ptr->da_widget->window, mgp->pv_ptr->da_widget->style->black_gc, mgp->curx, 1, mgp->curx, mgp->pheight-1 ); gdk_draw_line ( mgp->pv_ptr->da_widget->window, mgp->pv_ptr->da_widget->style->black_gc, 1, mgp->cury, mgp->pwidth-1, mgp->cury ); /* current position of cursor is updated */ gdk_gc_set_function ( mgp->pv_ptr->da_widget->style->black_gc, GDK_COPY); } } /* Adjustment Update Callbacks (with instant_update request) */ static void mov_instant_int_adjustment_update(GtkObject *obj, gpointer val) { t_mov_gui_stuff *mgp; gimp_int_adjustment_update(GTK_ADJUSTMENT(obj), val); mgp = g_object_get_data( G_OBJECT(obj), "mgp" ); mov_set_instant_apply_request(mgp); } /* end mov_instant_int_adjustment_update */ static void mov_instant_double_adjustment_update(GtkObject *obj, gpointer val) { t_mov_gui_stuff *mgp; gimp_double_adjustment_update(GTK_ADJUSTMENT(obj), val); mgp = g_object_get_data( G_OBJECT(obj), "mgp" ); mov_set_instant_apply_request(mgp); } /* end mov_instant_double_adjustment_update */ static void mov_path_colorbutton_update( GimpColorButton *widget, t_mov_gui_stuff *mgp ) { if(mgp) { gimp_color_button_get_color(widget, &mgp->pathcolor); mov_path_prevw_cursor_update( mgp ); mov_path_prevw_draw ( mgp, CURSOR | PATH_LINE ); } } /* end mov_path_colorbutton_update */ static void mov_path_keycolorbutton_clicked( GimpColorButton *widget, t_mov_gui_stuff *mgp ) { if(widget->dialog) { /* WORKAROUND: * we dont need the coloresction dialog for the keycolor_button, * because only the Bluebox Dioalog Window should open * when the keycolor_button is clicked. * The coloresction dialog is opened by * the standard "clicked" signal handler of the GimpColorButton Widget. * that fires always before this private signal handler. * * because i have no idea how to remove the standard signal handler * i used this Workaround, that simply destroys the unwanted dialog * immediate after its creation. * (this works fine, but the coloresction dialog may filcker up for a very short time) */ gtk_widget_destroy(widget->dialog); widget->dialog = NULL; } if(mgp) { if((pvals->bbp_pv) && (pvals->src_layer_id >= 0) && (pvals->src_image_id >= 0)) { /* use the current source layer for The Blubox Dialog * but do not perform changes here. */ pvals->bbp_pv->image_id = pvals->src_image_id; pvals->bbp_pv->drawable_id = pvals->src_layer_id; pvals->bbp_pv->layer_id = pvals->src_layer_id; pvals->bbp_pv->run_flag = FALSE; pvals->bbp_pv->run_mode = GIMP_RUN_INTERACTIVE; gap_bluebox_dialog(pvals->bbp_pv); if(mgp->shell == NULL) { /* the MovePath Main Window was closed * quit gtk main loop and return immediate * without touching any data structures and widgets * (could be freed or invalid at this point) * the only task that is left to do is to destroy * the bluebox dialog shell if it is still there */ if(pvals->bbp_pv->shell) { gtk_widget_destroy(pvals->bbp_pv->shell); } gtk_main_quit(); return; } if(pvals->bbp == NULL) { pvals->bbp = gap_bluebox_bbp_new(-1); if(pvals->bbp == NULL) { return; } } /* if Blubox dialog was left with OK button get values for rendering */ if(pvals->bbp_pv->run_flag) { memcpy(&pvals->bbp->vals, &pvals->bbp_pv->vals, sizeof(GapBlueboxVals)); } gimp_color_button_set_color(widget, &pvals->bbp->vals.keycolor); mov_set_instant_apply_request(mgp); } } } /* end mov_path_keycolorbutton_clicked */ static void mov_path_keycolorbutton_changed( GimpColorButton *widget, t_mov_gui_stuff *mgp ) { if(mgp) { gimp_color_button_get_color(widget, &pvals->bbp_pv->vals.keycolor); if(pvals->bbp == NULL) { pvals->bbp = gap_bluebox_bbp_new(-1); if(pvals->bbp == NULL) { return; } } memcpy(&pvals->bbp->vals.keycolor, &pvals->bbp_pv->vals.keycolor, sizeof(GimpRGB)); mov_set_instant_apply_request(mgp); } } /* end mov_path_keycolorbutton_changed */ /* * mov_path_xy_adjustment_update */ static void mov_path_x_adjustment_update( GtkWidget *widget, gpointer data ) { t_mov_gui_stuff *mgp; gint old_val; mgp = (t_mov_gui_stuff *)data; if(mgp == NULL) return; old_val = mgp->p_x; gimp_int_adjustment_update(GTK_ADJUSTMENT(widget), &mgp->p_x); if( old_val != mgp->p_x ) { if( !mgp->in_call ) { mov_path_prevw_cursor_update( mgp ); mov_path_prevw_draw ( mgp, CURSOR | PATH_LINE ); mov_set_instant_apply_request(mgp); } } } static void mov_path_y_adjustment_update( GtkWidget *widget, gpointer data ) { t_mov_gui_stuff *mgp; gint old_val; mgp = (t_mov_gui_stuff *)data; if(mgp == NULL) return; old_val = mgp->p_y; gimp_int_adjustment_update(GTK_ADJUSTMENT(widget), &mgp->p_y); if( old_val != mgp->p_y ) { if( !mgp->in_call ) { mov_path_prevw_cursor_update( mgp ); mov_path_prevw_draw ( mgp, CURSOR | PATH_LINE ); mov_set_instant_apply_request(mgp); } } } static void mov_path_tfactor_adjustment_update( GtkWidget *widget, gdouble *val ) { gdouble old_val; t_mov_gui_stuff *mgp; mgp = g_object_get_data( G_OBJECT(widget), "mgp" ); if(mgp == NULL) return; old_val = *val; gimp_double_adjustment_update(GTK_ADJUSTMENT(widget), (gpointer)val); if( old_val != *val ) { mov_set_instant_apply_request(mgp); if( !mgp->in_call ) { mov_path_prevw_cursor_update( mgp ); mov_path_prevw_draw ( mgp, CURSOR | PATH_LINE ); //XXX check if we need an additional GRID flag for the preview } } } /* end mov_path_tfactor_adjustment_update */ static void mov_path_feather_adjustment_update( GtkWidget *widget, gdouble *val ) { gdouble old_val; t_mov_gui_stuff *mgp; mgp = g_object_get_data( G_OBJECT(widget), "mgp" ); if(mgp == NULL) return; old_val = *val; gimp_double_adjustment_update(GTK_ADJUSTMENT(widget), (gpointer)val); if( old_val != *val ) { mov_set_instant_apply_request(mgp); } } /* end mov_path_feather_adjustment_update */ static void mov_selmode_menu_callback (GtkWidget *widget, t_mov_gui_stuff *mgp) { gboolean l_sensitive; GtkWidget *spinbutton; gint value; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value); pvals->src_selmode = value; if(mgp == NULL) return; l_sensitive = TRUE; if(pvals->src_selmode == GAP_MOV_SEL_IGNORE) { l_sensitive = FALSE; } if(mgp->sel_feather_radius_adj) { spinbutton = GTK_WIDGET(g_object_get_data (G_OBJECT (mgp->sel_feather_radius_adj), "spinbutton")); if(spinbutton) { gtk_widget_set_sensitive(spinbutton, l_sensitive); } } mov_set_instant_apply_request(mgp); } /* end mov_selmode_menu_callback */ static void mov_path_resize_adjustment_update( GtkObject *obj, gdouble *val) { gdouble old_val; t_mov_gui_stuff *mgp; mgp = g_object_get_data( G_OBJECT(obj), "mgp" ); if(mgp == NULL) return; old_val = *val; gimp_double_adjustment_update(GTK_ADJUSTMENT(obj), (gpointer)val); if( old_val != *val ) { mov_set_instant_apply_request(mgp); if (gimp_chain_button_get_active (GIMP_CHAIN_BUTTON (mgp->constrain))) { /* in the constrain mode we propagate the value * for with and height resize factors to the other one * this constrains both spinbuttons to the same factor * and keeps the original src layer proportions */ if(GTK_ADJUSTMENT(obj) == mgp->wres_adj) { gtk_adjustment_set_value(mgp->hres_adj, (gfloat)*val); } else { gtk_adjustment_set_value(mgp->wres_adj, (gfloat)*val); } } } } /* end mov_path_resize_adjustment_update */ static void mov_path_tween_steps_adjustment_update ( GtkObject *obj, gint *val) { t_mov_gui_stuff *mgp; if((obj == NULL) || (val == NULL)) { return; } gimp_int_adjustment_update(GTK_ADJUSTMENT(obj), val); mgp = g_object_get_data( G_OBJECT(obj), "mgp" ); if(mgp) { mov_tweenlayer_sensitivity(mgp); } } /* end mov_path_tween_steps_adjustment_update */ /* * Update the cross cursor's coordinates accoding to pvals->[xy]path_prevw * but not redraw it */ static void mov_path_prevw_cursor_update ( t_mov_gui_stuff *mgp ) { mgp->curx = mgp->p_x * mgp->pwidth / mgp->dwidth; mgp->cury = mgp->p_y * mgp->pheight / mgp->dheight; if( mgp->curx < 0 ) mgp->curx = 0; else if( mgp->curx >= mgp->pwidth ) mgp->curx = mgp->pwidth-1; if( mgp->cury < 0 ) mgp->cury = 0; else if( mgp->cury >= mgp->pheight) mgp->cury = mgp->pheight-1; } /* * Handle the expose event on the preview */ static gint mov_path_prevw_preview_expose( GtkWidget *widget, GdkEvent *event ) { t_mov_gui_stuff *mgp; mgp = g_object_get_data( G_OBJECT(widget), "mgp" ); if((mgp->pv_ptr == NULL) || (mgp->in_call)) { return FALSE; } if(mgp->pv_ptr->da_widget == NULL) { return FALSE; } mgp->in_call = TRUE; mov_path_prevw_draw( mgp, ALL ); mgp->in_call = FALSE; return FALSE; } /* * Handle other events on the preview */ static gint mov_path_prevw_preview_events ( GtkWidget *widget, GdkEvent *event ) { t_mov_gui_stuff *mgp; GdkEventButton *bevent; GdkEventMotion *mevent; gint upd_flag; gint mouse_button; mgp = g_object_get_data ( G_OBJECT(widget), "mgp" ); /* HINT: * smooth update of both CURSOR and PATH_LINE * on every mousemove works fine on machines with 300MHz. * for slower machines it once was better to paint just the cross cursor, * and refresh the path lines only at * button press and release events. * 2003.07.12 hof: * since we use a drawing_area that is repainted at each expose * event, we MUST force painting of the PATH_LINE. * (if we dont, the pathline disappears completely until the mouse * button is released) * The gap_pview_da repaint is faster than the old render_preview procedure * so it may work even for slower machines now. */ upd_flag = CURSOR | PATH_LINE; /* upd_flag = CURSOR; */ mouse_button = 0; switch (event->type) { case GDK_EXPOSE: break; case GDK_BUTTON_RELEASE: bevent = (GdkEventButton *) event; mouse_button = 0 - bevent->button; mov_set_instant_apply_request(mgp); goto mbuttons; case GDK_BUTTON_PRESS: bevent = (GdkEventButton *) event; mouse_button = bevent->button; mbuttons: mgp->curx = bevent->x; mgp->cury = bevent->y; upd_flag = CURSOR | PATH_LINE; goto mouse; case GDK_MOTION_NOTIFY: mevent = (GdkEventMotion *) event; if ( !mevent->state ) break; mgp->curx = mevent->x; mgp->cury = mevent->y; mov_set_instant_apply_request(mgp); mouse: if((mouse_button == 1) && (mgp->show_path)) { /* Picking of pathpoints is done only if * the left mousebutton goes down (mouse_button == 1) * and only if Path is visible */ p_points_to_tab(mgp); mgp->p_x = mgp->curx * mgp->dwidth / mgp->pwidth; mgp->p_y = mgp->cury * mgp->dheight / mgp->pheight; p_pick_nearest_point(mgp->p_x, mgp->p_y); p_point_refresh(mgp); } else { mgp->p_x = mgp->curx * mgp->dwidth / mgp->pwidth; mgp->p_y = mgp->cury * mgp->dheight / mgp->pheight; p_points_to_tab(mgp); mov_path_prevw_cursor_update( mgp ); } mov_path_prevw_draw( mgp, upd_flag); mgp->in_call = TRUE; gtk_adjustment_set_value (mgp->x_adj, (gfloat)mgp->p_x); gtk_adjustment_set_value (mgp->y_adj, (gfloat)mgp->p_y); mgp->in_call = FALSE; break; default: break; } return FALSE; } /* ============================================================================ * p_chk_keyframes * check if controlpoints and keyframe settings are OK * return TRUE if OK, * Pop Up error Dialog window and return FALSE if NOT. * ============================================================================ */ static gint p_chk_keyframes(t_mov_gui_stuff *mgp) { gchar *l_err_lbltext; p_points_to_tab(mgp); l_err_lbltext = gap_mov_exec_chk_keyframes(pvals); if(*l_err_lbltext != '\0') { g_message(_("Can't operate with current controlpoint\n" "or keyframe settings.\n\n" "Error List:\n" "%s") ,l_err_lbltext ); g_free(l_err_lbltext); return(FALSE); } g_free(l_err_lbltext); return(TRUE); } /* end p_chk_keyframes */ /* ============================================================================ * p_get_flattened_drawable * flatten the given image and return pointer to the * (only) remaining drawable. * ============================================================================ */ GimpDrawable * p_get_flattened_drawable(gint32 image_id) { GimpDrawable *l_drawable_ptr ; l_drawable_ptr = gimp_drawable_get (gap_image_merge_visible_layers(image_id, GIMP_CLIP_TO_IMAGE)); return l_drawable_ptr; } /* end p_get_flattened_drawable */ /* ============================================================================ * add the selected source layer to the temp. preview image * (modified accordung to current settings) * then flatten the temporary preview image, * and return pointer to the (only) remaining drawable. * ============================================================================ */ GimpDrawable * p_get_prevw_drawable (t_mov_gui_stuff *mgp) { GapMovCurrent l_curr; gint l_nlayers; /* check if we have a source layer (to add to the preview) */ if((pvals->src_layer_id >= 0) && (pvals->src_image_id >= 0)) { p_points_to_tab(mgp); if(!gap_image_is_alive(pvals->src_image_id)) { mov_refresh_src_layer_menu(mgp); } /* calculate current settings */ l_curr.dst_frame_nr = 0; l_curr.currX = (gdouble)mgp->p_x; l_curr.currY = (gdouble)mgp->p_y; l_curr.currOpacity = (gdouble)mgp->opacity; l_curr.currWidth = (gdouble)mgp->w_resize; l_curr.currHeight = (gdouble)mgp->h_resize; l_curr.currRotation = (gdouble)mgp->rotation; l_curr.currTTLX = (gdouble)mgp->ttlx; l_curr.currTTLY = (gdouble)mgp->ttly; l_curr.currTTRX = (gdouble)mgp->ttrx; l_curr.currTTRY = (gdouble)mgp->ttry; l_curr.currTBLX = (gdouble)mgp->tblx; l_curr.currTBLY = (gdouble)mgp->tbly; l_curr.currTBRX = (gdouble)mgp->tbrx; l_curr.currTBRY = (gdouble)mgp->tbry; l_curr.currSelFeatherRadius = (gdouble)mgp->sel_feather_radius; l_curr.src_layer_idx = 0; l_curr.src_layers = gimp_image_get_layers (pvals->src_image_id, &l_nlayers); if((l_curr.src_layers != NULL) && (l_nlayers > 0)) { l_curr.src_last_layer = l_nlayers -1; /* findout index of src_layer_id */ for(l_curr.src_layer_idx = 0; l_curr.src_layer_idx < l_nlayers; l_curr.src_layer_idx++) { if(l_curr.src_layers[l_curr.src_layer_idx] == pvals->src_layer_id) break; } } if(pvals->src_stepmode >= GAP_STEP_FRAME) { gap_mov_render_fetch_src_frame (pvals, -1); /* negative value fetches the selected frame number */ } else { if(pvals->src_selmode != GAP_MOV_SEL_IGNORE) { gint32 l_sel_channel_id; gboolean l_all_empty; l_all_empty = FALSE; if(gimp_selection_is_empty(pvals->src_image_id)) { l_all_empty = TRUE; } l_sel_channel_id = gimp_image_get_selection(pvals->src_image_id); gap_mov_render_create_or_replace_tempsel_image(l_sel_channel_id, pvals, l_all_empty); } } /* set offsets (in cur_ptr) * according to handle_mode and src_img dimension (pvals) */ gap_mov_exec_set_handle_offsets(pvals, &l_curr); /* render: add source layer to (temporary) preview image */ gap_mov_render_render(pvals->tmp_image_id, pvals, &l_curr); if(l_curr.src_layers != NULL) g_free(l_curr.src_layers); l_curr.src_layers = NULL; } mov_check_valid_src_layer(mgp); /* flatten image, and get the (only) resulting drawable */ return(p_get_flattened_drawable(pvals->tmp_image_id)); } /* end p_get_prevw_drawable */ /* --------------------------------- * mov_set_instant_apply_request * --------------------------------- */ static void mov_set_instant_apply_request(t_mov_gui_stuff *mgp) { if(mgp) { mgp->instant_apply_request = TRUE; /* request is handled by timer */ } } /* end mov_set_instant_apply_request */ /* --------------------------------- * mov_set_waiting_cursor * --------------------------------- */ static void mov_set_waiting_cursor(t_mov_gui_stuff *mgp) { if(mgp == NULL) return; gdk_window_set_cursor(GTK_WIDGET(mgp->shell)->window, mgp->cursor_wait); gdk_flush(); /* g_main_context_iteration makes sure that waiting cursor is displayed */ while(g_main_context_iteration(NULL, FALSE)); gdk_flush(); } /* end mov_set_waiting_cursor */ /* --------------------------------- * mov_set_active_cursor * --------------------------------- */ static void mov_set_active_cursor(t_mov_gui_stuff *mgp) { if(mgp == NULL) return; gdk_window_set_cursor(GTK_WIDGET(mgp->shell)->window, mgp->cursor_acitve); gdk_flush(); } /* end mov_set_active_cursor */ /* ---------------------------------- * p_mov_spinbutton_new * ---------------------------------- * create label and spinbutton and add to table * return the adjustment of the spinbutton * (for compatible parameters to gimp_scale_entry_new * there are some unused dummy parameters) */ GtkObject * p_mov_spinbutton_new(GtkTable *table ,gint col ,gint row ,gchar *label_text ,gint scale_width /* dummy, not used */ ,gint spinbutton_width ,gdouble initial_val ,gdouble lower /* dummy, not used */ ,gdouble upper /* dummy, not used */ ,gdouble sstep ,gdouble pagestep ,gint digits ,gboolean constrain ,gdouble umin ,gdouble umax ,gchar *tooltip_text ,gchar *privatetip ) { GtkObject *adj; GtkWidget *spinbutton; GtkWidget *label; label = gtk_label_new (label_text); gtk_misc_set_alignment( GTK_MISC(label), 0.0, 0.5 ); gtk_table_attach( GTK_TABLE(table), label, col, col+1, row, row+1, GTK_FILL, 0, 4, 0 ); gtk_widget_show(label); spinbutton = gimp_spin_button_new (&adj /* return value */ , initial_val , umin , umax , sstep , pagestep , 0.0 /* page_size */ , 1.0 /* climb_rate */ , digits ); gtk_widget_set_size_request(spinbutton, spinbutton_width, -1); gtk_widget_show (spinbutton); gtk_table_attach (GTK_TABLE (table), spinbutton, col+1, col+2, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (spinbutton, tooltip_text, privatetip); g_object_set_data (G_OBJECT (adj), "label", label); g_object_set_data (G_OBJECT (adj), "spinbutton", spinbutton); return(adj); } /* end p_mov_spinbutton_new */ /* -------------------------- * mov_fit_initial_shell_window * -------------------------- */ static void mov_fit_initial_shell_window(t_mov_gui_stuff *mgp) { gint width; gint height; if(mgp == NULL) { return; } if(mgp->shell_initial_width < 0) { return; } width = mgp->shell_initial_width; height = mgp->shell_initial_height; gtk_widget_set_size_request (mgp->shell, width, height); /* shrink shell window */ gtk_window_set_default_size(GTK_WINDOW(mgp->shell), width, height); /* shrink shell window */ gtk_window_resize (GTK_WINDOW(mgp->shell), width, height); /* shrink shell window */ } /* end mov_fit_initial_shell_window */ /* ----------------------------- * mov_shell_window_size_allocate * ----------------------------- */ static void mov_shell_window_size_allocate (GtkWidget *widget, GtkAllocation *allocation, gpointer user_data) { t_mov_gui_stuff *mgp; mgp = (t_mov_gui_stuff*)user_data; if((mgp == NULL) || (allocation == NULL)) { return; } if(gap_debug) printf("mov_shell_window_size_allocate: START shell_alloc: w:%d h:%d \n" , (int)allocation->width , (int)allocation->height ); if(mgp->shell_initial_width < 0) { mgp->shell_initial_width = allocation->width; mgp->shell_initial_height = allocation->height; mov_fit_initial_shell_window(mgp); /* for setting window default size */ } else { if((allocation->width < mgp->shell_initial_width) || (allocation->height < mgp->shell_initial_height)) { /* dont allow shrink below initial size */ mov_fit_initial_shell_window(mgp); } } } /* end mov_shell_window_size_allocate */ /* -------------------------------- * mov_pview_size_allocate_callback * -------------------------------- */ static void mov_pview_size_allocate_callback(GtkWidget *widget , GtkAllocation *allocation , t_mov_gui_stuff *mgp ) { gint actual_check_size; gint pwidth; gint pheight; gint psize; gboolean fit_initial; static gint ignore_inital_cnt = 2; #define PREVIEW_BORDER_X 18 #define PREVIEW_BORDER_Y 18 fit_initial = FALSE; if(ignore_inital_cnt > 0) { if(gap_debug) printf("\n\n === countdown: %d\n\n", (int)ignore_inital_cnt ); ignore_inital_cnt--; return; } if((mgp == NULL) || (allocation == NULL)) { return; } if(mgp->startup) { return; } if(mgp->pv_ptr->da_widget == NULL) { return; } if(mgp->pv_ptr->da_widget->window == NULL) { return; } /* fit preview into allocated width and adjust the height */ pwidth = allocation->width - PREVIEW_BORDER_X; pheight = (pwidth * mgp->dheight) / MAX(mgp->dwidth,1); if(pheight + PREVIEW_BORDER_Y > allocation->height) { /* fit preview into allocated height and adjust the width */ pheight = allocation->height - PREVIEW_BORDER_Y; pwidth = (pheight * mgp->dwidth) / MAX(mgp->dheight,1); } psize = MAX(pwidth, pheight); if ((allocation->width - PREVIEW_BORDER_X < PREVIEW_SIZE) || (allocation->height - PREVIEW_BORDER_Y < PREVIEW_SIZE) || (pwidth < mgp->pwidth) /* TOTAL SHRINK WORKAROUND */ || (pheight < mgp->pheight) /* TOTAL SHRINK WORKAROUND */ ) { /* do not allow shrinks smaller than PREVIEW_SIZE */ if ( mgp->dwidth > mgp->dheight ) { pheight = mgp->dheight * PREVIEW_SIZE / mgp->dwidth; pheight = MAX (1, pheight); pwidth = PREVIEW_SIZE; } else { pwidth = mgp->dwidth * PREVIEW_SIZE / mgp->dheight; pwidth = MAX (1, pwidth); pheight = PREVIEW_SIZE; } psize = PREVIEW_SIZE; ignore_inital_cnt = 1; fit_initial = TRUE; } actual_check_size = (GAP_MOV_CHECK_SIZE * psize) / PREVIEW_SIZE; if(gap_debug) { printf("allocation w:%d h:%d pwidth:%d pheight:%d preview: w:%d h:%d psize MAX:%d\n" , (int)allocation->width , (int)allocation->height , (int)pwidth , (int)pheight , (int)mgp->pwidth , (int)mgp->pheight , (int)psize ); } if(((pheight / 6) == (mgp->pheight / 6)) && ((pwidth / 6) == (mgp->pwidth / 6))) { /* skip resize if equal size or no significant change (< 6 pixel) */ if(gap_debug) printf("RET\n"); return; } mgp->pwidth = pwidth; mgp->pheight = pheight; gap_pview_set_size(mgp->pv_ptr , mgp->pwidth , mgp->pheight , actual_check_size ); mov_upvw_callback (NULL, mgp); if(fit_initial) { mov_fit_initial_shell_window(mgp); } } /* end mov_pview_size_allocate_callback */ gimp-gap-2.6.0+dfsg.orig/gap/gap_onion_base.h0000644000175000017500000000670611212030253020641 0ustar thibautthibaut/* gap_onion_base.h * 2003.05.22 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains ONION Skin Layers worker Procedures * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.16c; 2003.07.09 hof: created (as extract of the gap_onion_worker.c module) * version 1.2.2a; 2001.12.10 hof: created */ #ifndef _GAP_ONION_BASE_H #define _GAP_ONION_BASE_H #include "config.h" /* SYTEM (UNIX) includes */ #include #include #include #include #include /* #include */ #include #include #include #include #include #define GAP_ONION_PARASITE_NAME "gap_onion_skin_layer" #define GAP_ONION_VISI_FALSE 0 #define GAP_ONION_VISI_TRUE 1 #define GAP_ONION_VISI_TOGGLE 2 #define GAP_ONION_REFMODE_NORMAL 0 #define GAP_ONION_REFMODE_BIDRIECTIONAL_SINGLE 1 #define GAP_ONION_REFMODE_BIDRIECTIONAL_DOUBLE 2 typedef struct GapOnionBaseParasite_data { long timestamp; /* UTC timecode of creation time */ gint32 tattoo; /* unique tattoo */ } GapOnionBaseParasite_data; /* Function Typedefs */ typedef void (*GapOnionBaseFptrAddImageToCache)(void *gpp_void , gint32 framenr , gint32 image_id , gint32 layer_id); typedef gint32 (*GapOnionBaseFptrFindFrameInImageCache)(void *gpp_void , gint32 framenr , gint32 *image_id , gint32 *layer_id); /* onion_base procedures */ void gap_onion_base_mark_as_onionlayer(gint32 layer_id); gint32 gap_onion_base_check_is_onion_layer(gint32 layer_id); gint gap_onion_base_onionskin_visibility(gint32 image_id, gint visi_mode); gint gap_onion_base_onionskin_delete(gint32 image_id); gint gap_onion_base_onionskin_apply(gpointer gpp , gint32 image_id , GapVinVideoInfo *vin_ptr , long ainfo_curr_frame_nr , long ainfo_first_frame_nr , long ainfo_last_frame_nr , char *ainfo_basename , char *ainfo_extension , GapOnionBaseFptrAddImageToCache fptr_add_img_to_cache , GapOnionBaseFptrFindFrameInImageCache fptr_find_frame_in_img_cache , gboolean use_cache ); gboolean gap_onion_image_has_oinonlayers(gint32 image_id, gboolean only_visible); gint32 gap_onion_base_image_duplicate(gint32 image_id); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_lib.c0000644000175000017500000027242311212030253017267 0ustar thibautthibaut/* gap_lib.c * 1997.11.18 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * basic GAP types and utility procedures * * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 2.1.0a 2005/03/10 hof: added active_layer_tracking feature * 2.1.0a 2004/12/04 hof: added gap_lib (base)_shorten_filename * 2.1.0a 2004/04/18 hof: added gap_lib (base)_fprintf_gdouble * 1.3.26a 2004/02/01 hof: added: gap_lib_alloc_ainfo_from_name * 1.3.25a 2004/01/20 hof: - removed xvpics support (gap_lib_get_video_paste_name) * 1.3.21e 2003/11/04 hof: - gimprc * 1.3.18a 2003/08/23 hof: - all gap_debug messages to stdout (do not mix with stderr) * - do not save thumbnails in p_decide_save_as because it saves * to a temp filename that is renamed later after successful save * 1.3.16c 2003/07/12 hof: - triggers for automatic onionskinlayer create and remove * bugfix gap_vid_edit_paste * 1.3.14a 2003/05/27 hof: - moved basic gap operations to new module gap_base_ops * - moved procedures for thumbnail handling to gap_thumbnail * - conditional save now depends on * GIMP standard gimprc keyword "trust-dirty-flag" * (removed support for old GAP private keyword "video-unconditional-frame-save") * 1.3.12a; 2003/05/03 hof: merge into CVS-gimp-gap project, added gap_renumber, gap_lib_alloc_fname 6 digit support * 1.3.11a; 2003/01/19 hof: conditional SAVE (based on gimp_image_is_dirty), use gimp_directory * 1.3.9a; 2002/10/28 hof: minor cleanup (replace strcpy by g_strdup) * 1.3.5a; 2002/04/21 hof: gimp_palette_refresh changed name to: gimp_palettes_refresh * gap_locking (now moved to gap_lock.c) * 1.3.4b; 2002/03/15 hof: gap_lib_load_named_frame now uses gimp_displays_reconnect (removed gap_exchange_image.h) * 1.3.4a; 2002/03/11 hof: port to gimp-1.3.4 * 1.2.2a; 2001/10/21 hof: bufix # 61677 (error in duplicate frames GUI) * and disable duplicate for Unsaved/untitled Images. * (creating frames from such images with a default name may cause problems * as unexpected overwriting frames or mixing animations with different sized frames) * 1.2.1a; 2001/07/07 hof: gap_lib_file_copy use binary modes in fopen (hope that fixes bug #52890 in video/duplicate) * 1.1.29a; 2000/11/23 hof: gap locking (changed to procedures and placed here) * 1.1.28a; 2000/11/05 hof: check for GIMP_PDB_SUCCESS (not for FALSE) * 1.1.20a; 2000/04/25 hof: new: gap_lib_get_video_paste_name gap_vid_edit_clear * 1.1.17b; 2000/02/27 hof: bug/style fixes * 1.1.14a; 1999/12/18 hof: handle .xvpics on fileops (copy, rename and delete) * new: gap_lib_get_frame_nr, * 1.1.9a; 1999/09/14 hof: handle frame filenames with framenumbers * that are not the 4digit style. (like frame1.xcf) * 1.1.8a; 1999/08/31 hof: for AnimFrame Filtypes != XCF: * p_decide_save_as does save INTERACTIVE at 1.st time * and uses GIMP_RUN_WITH_LAST_VALS for subsequent calls * (this enables to set Fileformat specific save-Parameters * at least at the 1.st call, using the save dialog * of the selected (by gimp_file_save) file_save procedure. * in NONINTERACTIVE mode we have no access to * the Fileformat specific save-Parameters * 1999/07/22 hof: accept anim framenames without underscore '_' * (suggested by Samuel Meder) * 0.99.00; 1999/03/15 hof: prepared for win/dos filename conventions * 0.98.00; 1998/11/30 hof: started Port to GIMP 1.1: * exchange of Images (by next frame) is now handled in the * new module: gap_exchange_image.c * 0.96.02; 1998/07/30 hof: extended gap_dup (duplicate range instead of singele frame) * added gap_shift * 0.96.00 hof: - now using gap_arr_dialog.h * 0.95.00 hof: increased duplicate frames limit from 50 to 99 * 0.93.01 hof: fixup bug when frames are not in the current directory * 0.90.00; hof: 1.st (pre) release */ #include "config.h" /* SYSTEM (UNIX) includes */ #include #include #include #include /* for kill */ #ifdef HAVE_SYS_TIMES_H #include #endif #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include /* GIMP includes */ #include "gtk/gtk.h" #include "gap-intl.h" #include "libgimp/gimp.h" #ifdef G_OS_WIN32 #include # ifndef S_ISDIR # define S_ISDIR(m) ((m) & _S_IFDIR) # endif # ifndef S_ISREG # define S_ISREG(m) ((m) & _S_IFREG) # endif #endif #ifdef G_OS_WIN32 #include /* For _getpid() */ #endif /* GAP includes */ #include "gap_arr_dialog.h" #include "gap_image.h" #include "gap_layer_copy.h" #include "gap_lib.h" #include "gap_lock.h" #include "gap_navi_activtable.h" #include "gap_onion_base.h" #include "gap_pdb_calls.h" #include "gap_thumbnail.h" #include "gap_vin.h" typedef struct { gdouble quality; gdouble smoothing; gboolean optimize; gboolean progressive; gboolean baseline; gint subsmp; gint restart; gint dct; gboolean preview; gboolean save_exif; gboolean save_thumbnail; gboolean save_xmp; gboolean use_orig_quality; } GAPJpegSaveVals; extern int gap_debug; /* ==0 ... dont print debug infos */ /* ------------------------------------------ */ /* forward working procedures */ /* ------------------------------------------ */ gboolean p_set_active_layer_by_pos(gint32 image_id ,gint32 ref_layer_stackpos ); gboolean p_set_active_layer_by_name(gint32 image_id ,const gchar *ref_layer_name ,gint32 ref_layer_stackpos ); static gchar * p_get_active_layer_name(gint32 image_id ,gint32 *active_layer ,gint32 *stack_pos ); static void p_do_active_layer_tracking(gint32 image_id ,GapVinVideoInfo *vin_ptr ,gchar *ref_layer_name ,gint32 ref_layer_stackpos ); static int p_save_old_frame(GapAnimInfo *ainfo_ptr, GapVinVideoInfo *vin_ptr); static int p_decide_save_as(gint32 image_id, const char *sav_name, const char *final_sav_name); static gint32 p_lib_save_jpg_non_interactive(gint32 image_id, gint32 l_drawable_id, const char *sav_name, const GAPJpegSaveVals *save_vals); static gint32 p_lib_save_named_image_1(gint32 image_id, const char *sav_name, GimpRunMode run_mode, gboolean enable_thumbnailsave , const char *l_basename , const char *l_extension ); static gint32 p_lib_save_named_image2(gint32 image_id, const char *sav_name, GimpRunMode run_mode, gboolean enable_thumbnailsave, const GAPJpegSaveVals *jpg_save_vals); static char* p_gzip (char *orig_name, char *new_name, char *zip); /* --------------------------------- * p_set_active_layer_by_pos * --------------------------------- * set the layer with same stackposition as ref_layer_stackpos * as the active layer, where stackpositions of onionskin layers are not counted. * if the image has less layers than ref_layer_stackpos * then pick the top-most layer, that is no onionskin layer */ gboolean p_set_active_layer_by_pos(gint32 image_id ,gint32 ref_layer_stackpos ) { gint32 *l_layers_list; gint l_nlayers; gint l_idx; gboolean l_is_onion; gint32 l_layer_id; gint32 l_matching_layer_id; gint l_pos; if(gap_debug) { printf("p_set_active_layer_by_pos START\n"); } l_pos = 0; l_matching_layer_id = -1; l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list) { for(l_idx=0;l_idx < l_nlayers;l_idx++) { l_layer_id = l_layers_list[l_idx]; l_is_onion = gap_onion_base_check_is_onion_layer(l_layer_id); if(!l_is_onion) { l_matching_layer_id = l_layer_id; if(l_pos == ref_layer_stackpos) { break; } l_pos++; } } g_free(l_layers_list); } if(l_matching_layer_id >= 0) { gimp_image_set_active_layer(image_id, l_matching_layer_id); if(gap_debug) { char *l_name; l_name = gimp_drawable_get_name(l_matching_layer_id); printf("p_set_active_layer_by_pos SET layer_id %d '%s' as ACTIVE\n" , (int)l_matching_layer_id , l_name ); if(l_name) { g_free(l_name); } } return (TRUE); } return (FALSE); } /* end p_set_active_layer_by_pos */ /* --------------------------------- * p_set_active_layer_by_name * --------------------------------- * set active layer by picking the layer * whos name matches best with ref_layer_name. * ref_layer_stackpos is the 2nd criterium * restriction: works only for utf8 compliant layernames. */ gboolean p_set_active_layer_by_name(gint32 image_id ,const gchar *ref_layer_name ,gint32 ref_layer_stackpos ) { gint32 *l_layers_list; gint l_nlayers; gint l_idx; gboolean l_is_onion; gint32 l_layer_id; gint32 l_matching_layer_id; gint l_pos; gint l_score; gint l_case_bonus; gint l_max_score; glong l_ref_len; glong l_len; char *l_layer_name; if(gap_debug) { printf("p_set_active_layer_by_name START\n"); } l_pos = 0; l_max_score = 0; l_matching_layer_id = -1; if(ref_layer_name == NULL) { return(p_set_active_layer_by_pos(image_id, ref_layer_stackpos)); } if(!g_utf8_validate(ref_layer_name, -1, NULL)) { return(p_set_active_layer_by_pos(image_id, ref_layer_stackpos)); } l_ref_len = g_utf8_strlen(ref_layer_name, -1); l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list) { for(l_idx=0;l_idx < l_nlayers;l_idx++) { l_score = 0; l_case_bonus = 0; l_layer_id = l_layers_list[l_idx]; l_layer_name = gimp_drawable_get_name(l_layer_id); if(l_layer_name) { gint ii; if(g_utf8_validate(l_layer_name, -1, NULL)) { const char *uni_ref_ptr; const char *uni_nam_ptr; uni_ref_ptr = ref_layer_name; uni_nam_ptr = l_layer_name; /* check how many characters of the name are equal */ l_len = g_utf8_strlen(l_layer_name, -1); for(ii=0; ii < MIN(l_len, l_ref_len); ii++) { gunichar refname_char; gunichar layername_char; refname_char = g_utf8_get_char(uni_ref_ptr); layername_char = g_utf8_get_char(uni_nam_ptr); if(g_unichar_toupper(layername_char) == g_unichar_toupper(refname_char)) { /* best score for matching character */ l_score += 8; if(layername_char == refname_char) { if(ii==0) { /* prepare bonus for matching in case sensitivity */ l_case_bonus = 4; } } else { /* lost the bonus for exact matching in case sensitivity */ l_case_bonus = 0; } } else { break; } uni_ref_ptr = g_utf8_find_next_char(uni_ref_ptr, NULL); uni_nam_ptr = g_utf8_find_next_char(uni_nam_ptr, NULL); } l_score += l_case_bonus; if(l_len == l_ref_len) { /* extra score for equal length */ l_score += 2; } } g_free(l_layer_name); } if(l_score == l_max_score) { /* stackposition is checked as secondary criterium * (score +1) in case there are more names matching * in the same number of characters */ l_is_onion = gap_onion_base_check_is_onion_layer(l_layer_id); if(!l_is_onion) { if(l_pos == ref_layer_stackpos) { l_score += 1; } l_pos++; } } if(l_score > l_max_score) { l_matching_layer_id = l_layer_id; l_max_score = l_score; } } g_free(l_layers_list); } if(l_matching_layer_id >= 0) { gimp_image_set_active_layer(image_id, l_matching_layer_id); if(gap_debug) { char *l_name; l_name = gimp_drawable_get_name(l_matching_layer_id); printf("p_set_active_layer_by_name SET layer_id %d '%s' as ACTIVE\n" , (int)l_matching_layer_id , l_name ); if(l_name) { g_free(l_name); } } return (TRUE); } return (FALSE); } /* end p_set_active_layer_by_name */ /* --------------------------------- * p_get_active_layer_name * --------------------------------- * get id, name and stackposition of the * active_layer in the specified image. * (stackpostitions are counted without onionskin layers * stackposition 0 is the background layer) */ gchar * p_get_active_layer_name(gint32 image_id ,gint32 *active_layer ,gint32 *stack_pos ) { gchar *layer_name; gint32 *l_layers_list; gint l_nlayers; gint l_idx; gint l_pos; gboolean l_is_onion; gint32 l_layer_id; layer_name = NULL; *stack_pos = -1; *active_layer = gimp_image_get_active_layer(image_id); if(*active_layer >= 0) { layer_name = gimp_drawable_get_name(*active_layer); /* findout stackposition of the active layer * (ignoring onionskin layer positions) */ l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list) { l_pos = 0; for(l_idx=0;l_idx < l_nlayers;l_idx++) { l_layer_id = l_layers_list[l_idx]; if(l_layer_id == *active_layer) { *stack_pos = l_pos; break; } l_is_onion = gap_onion_base_check_is_onion_layer(l_layer_id); if(!l_is_onion) { l_pos++; } } g_free(l_layers_list); } } return (layer_name); } /* end p_get_active_layer_name */ /* --------------------------------- * p_do_active_layer_tracking * --------------------------------- * set the active layer in the specified image * due to settings of active layer tracking */ void p_do_active_layer_tracking(gint32 image_id ,GapVinVideoInfo *vin_ptr ,gchar *ref_layer_name ,gint32 ref_layer_stackpos ) { switch(vin_ptr->active_layer_tracking) { case GAP_ACTIVE_LAYER_TRACKING_BY_NAME: p_set_active_layer_by_name(image_id, ref_layer_name, ref_layer_stackpos); break; case GAP_ACTIVE_LAYER_TRACKING_BY_STACKPOS: p_set_active_layer_by_pos(image_id, ref_layer_stackpos); break; default: /* GAP_ACTIVE_LAYER_TRACKING_OFF */ break; } } /* end p_do_active_layer_tracking */ /* ============================================================================ * gap_lib_file_exists * * return 0 ... file does not exist, or is not accessable by user, * or is empty, * or is not a regular file * 1 ... file exists * ============================================================================ */ int gap_lib_file_exists(const char *fname) { struct stat l_stat_buf; long l_len; /* File Laenge ermitteln */ if (0 != g_stat(fname, &l_stat_buf)) { /* stat error (file does not exist) */ return(0); } if(!S_ISREG(l_stat_buf.st_mode)) { return(0); } l_len = (long)l_stat_buf.st_size; if(l_len < 1) { /* File is empty*/ return(0); } return(1); } /* end gap_lib_file_exists */ /* ============================================================================ * gap_lib_searchpath_for_exefile * ----------------------------- * search for executable file with given exefile name in given PATH * return NULL if not found, * else return full name of the exefile including the directorypath * (the returned string should be g_free'ed by the caller after usage) * ============================================================================ */ char * gap_lib_searchpath_for_exefile(const char *exefile, const char *path) { char *exe_fullname; char *path_copy; char *dirpath; char *pp; gboolean break_flag; path_copy = g_strdup(path); exe_fullname = NULL; break_flag = FALSE; pp = path_copy; dirpath = path_copy; while(pp && break_flag == FALSE) { if (*pp == '\0') { break_flag = TRUE; } if(*pp == G_SEARCHPATH_SEPARATOR) { *pp = '\0'; /* terminate dirpath string at separator */ } if (*pp == '\0') { exe_fullname = g_build_filename(dirpath, exefile, NULL); if(g_file_test (exe_fullname, G_FILE_TEST_IS_EXECUTABLE) ) { /* the executable was found at exe_fullname, * set break flag and keep that name as return value */ break_flag = TRUE; } else { g_free(exe_fullname); exe_fullname = NULL; } dirpath = pp; dirpath++; /* start of next directoryname in the path string */ } pp++; } g_free(path_copy); if (gap_debug) { printf("gap_lib_searchpath_for_exefile: path: %s\n", path); printf("gap_lib_searchpath_for_exefile: exe: %s\n", exefile); if(exe_fullname) { printf("gap_lib_searchpath_for_exefile: RET: %s\n", exe_fullname); } else { printf("gap_lib_searchpath_for_exefile: RET: NULL (not found)\n"); } } return(exe_fullname); } /* end gap_lib_searchpath_for_exefile */ /* ============================================================================ * gap_lib_image_file_copy * (copy the imagefile and its thumbnail) * ============================================================================ */ int gap_lib_image_file_copy(char *fname, char *fname_copy) { int l_rc; l_rc = gap_lib_file_copy(fname, fname_copy); gap_thumb_file_copy_thumbnail(fname, fname_copy); return(l_rc); } /* ============================================================================ * gap_lib_file_copy * ============================================================================ */ int gap_lib_file_copy(char *fname, char *fname_copy) { FILE *l_fp; char *l_buffer; struct stat l_stat_buf; long l_len; if(gap_debug) printf("gap_lib_file_copy src:%s dst:%s\n", fname, fname_copy); /* File Laenge ermitteln */ if (0 != g_stat(fname, &l_stat_buf)) { fprintf (stderr, "stat error on '%s'\n", fname); return -1; } l_len = (long)l_stat_buf.st_size; /* Buffer allocate */ l_buffer=(char *)g_malloc0((size_t)l_len+1); if(l_buffer == NULL) { fprintf(stderr, "file_copy: calloc error (%ld Bytes not available)\n", l_len); return -1; } /* load File into Buffer */ l_fp = g_fopen(fname, "rb"); /* open read */ if(l_fp == NULL) { fprintf (stderr, "open(read) error on '%s'\n", fname); g_free(l_buffer); return -1; } fread(l_buffer, 1, (size_t)l_len, l_fp); fclose(l_fp); l_fp = g_fopen(fname_copy, "wb"); /* open write */ if(l_fp == NULL) { fprintf (stderr, "file_copy: open(write) error on '%s' \n", fname_copy); g_free(l_buffer); return -1; } if(l_len > 0) { fwrite(l_buffer, l_len, 1, l_fp); } fclose(l_fp); g_free(l_buffer); return 0; /* all done OK */ } /* end gap_lib_file_copy */ /* ============================================================================ * gap_lib_delete_frame * ============================================================================ */ int gap_lib_delete_frame(GapAnimInfo *ainfo_ptr, long nr) { char *l_fname; int l_rc; l_fname = gap_lib_alloc_fname(ainfo_ptr->basename, nr, ainfo_ptr->extension); if(l_fname == NULL) { return(1); } if(gap_debug) printf("\nDEBUG gap_lib_delete_frame: %s\n", l_fname); l_rc = g_remove(l_fname); gap_thumb_file_delete_thumbnail(l_fname); g_free(l_fname); return(l_rc); } /* end gap_lib_delete_frame */ /* ============================================================================ * gap_lib_rename_frame * ============================================================================ */ int gap_lib_rename_frame(GapAnimInfo *ainfo_ptr, long from_nr, long to_nr) { char *l_from_fname; char *l_to_fname; int l_rc; l_from_fname = gap_lib_alloc_fname(ainfo_ptr->basename, from_nr, ainfo_ptr->extension); if(l_from_fname == NULL) { return(1); } l_to_fname = gap_lib_alloc_fname(ainfo_ptr->basename, to_nr, ainfo_ptr->extension); if(l_to_fname == NULL) { g_free(l_from_fname); return(1); } if(gap_debug) printf("\nDEBUG gap_lib_rename_frame: %s ..to.. %s\n", l_from_fname, l_to_fname); l_rc = g_rename(l_from_fname, l_to_fname); gap_thumb_file_rename_thumbnail(l_from_fname, l_to_fname); g_free(l_from_fname); g_free(l_to_fname); return(l_rc); } /* end gap_lib_rename_frame */ /* ============================================================================ * gap_lib_alloc_basename * * build the basename from an images name * Extension and trailing digits ("0000.xcf") are cut off. * return name or NULL (if malloc fails) * Output: number contains the integer representation of the stripped off * number String. (or 0 if there was none) * ============================================================================ */ char * gap_lib_alloc_basename(const char *imagename, long *number) { char *l_fname; char *l_ptr; long l_idx; *number = 0; if(imagename == NULL) return (NULL); /* copy from imagename */ l_fname = g_strdup(imagename); if(gap_debug) printf("DEBUG gap_lib_alloc_basename source: '%s'\n", l_fname); /* cut off extension */ l_ptr = &l_fname[strlen(l_fname)]; while(l_ptr != l_fname) { if((*l_ptr == G_DIR_SEPARATOR) || (*l_ptr == DIR_ROOT)) { break; } /* dont run into dir part */ if(*l_ptr == '.') { *l_ptr = '\0'; break; } l_ptr--; } if(gap_debug) printf("DEBUG gap_lib_alloc_basename (ext_off): '%s'\n", l_fname); /* cut off trailing digits (0000) */ l_ptr = &l_fname[strlen(l_fname)]; if(l_ptr != l_fname) l_ptr--; l_idx = 1; while(TRUE) { if((*l_ptr >= '0') && (*l_ptr <= '9')) { *number += ((*l_ptr - '0') * l_idx); l_idx = l_idx * 10; *l_ptr = '\0'; } else { /* do not cut off underscore any longer */ /* * if(*l_ptr == '_') * { * *l_ptr = '\0'; * } */ break; } if(l_ptr == l_fname) { break; } l_ptr--; } if(gap_debug) printf("DEBUG gap_lib_alloc_basename result:'%s'\n", l_fname); return(l_fname); } /* end gap_lib_alloc_basename */ /* ============================================================================ * gap_lib_alloc_extension * * input: a filename * returns: a copy of the filename extension (incl "." ) * if the filename has no extension, a pointer to * an empty string is returned ("\0") * NULL if allocate mem for extension failed. * ============================================================================ */ char * gap_lib_alloc_extension(const char *imagename) { int l_exlen; char *l_ext; const char *l_ptr; l_exlen = 0; l_ptr = &imagename[strlen(imagename)]; while(l_ptr != imagename) { if((*l_ptr == G_DIR_SEPARATOR) || (*l_ptr == DIR_ROOT)) { break; } /* dont run into dir part */ if(*l_ptr == '.') { l_exlen = strlen(l_ptr); break; } l_ptr--; } if(l_exlen > 0) { l_ext = g_strdup(l_ptr); } else { l_ext = g_strdup("\0"); } return(l_ext); } /* ---------------------------------- * gap_lib_alloc_fname_fixed_digits * ---------------------------------- * build the framname by concatenating basename, nr and extension. * the Number part has leading zeroes, depending * on the number of digits specified. */ char* gap_lib_alloc_fname_fixed_digits(char *basename, long nr, char *extension, long digits) { gchar *l_fname; gint l_len; if(basename == NULL) return (NULL); l_len = (strlen(basename) + strlen(extension) + 10); l_fname = (char *)g_malloc(l_len); switch(digits) { case 8: l_fname = g_strdup_printf("%s%08ld%s", basename, nr, extension); break; case 7: l_fname = g_strdup_printf("%s%07ld%s", basename, nr, extension); break; case 6: l_fname = g_strdup_printf("%s%06ld%s", basename, nr, extension); break; case 5: l_fname = g_strdup_printf("%s%05ld%s", basename, nr, extension); break; case 4: l_fname = g_strdup_printf("%s%04ld%s", basename, nr, extension); break; case 3: l_fname = g_strdup_printf("%s%03ld%s", basename, nr, extension); break; case 2: l_fname = g_strdup_printf("%s%02ld%s", basename, nr, extension); break; default: l_fname = g_strdup_printf("%s%ld%s", basename, nr, extension); break; } return(l_fname); } /* end gap_lib_alloc_fname_fixed_digits */ /* ============================================================================ * gap_lib_alloc_fname * ============================================================================ * at 1st call check environment * to findout how many digits (leading zeroes) to use in framename numbers * per default. */ char* gap_lib_alloc_fname(char *basename, long nr, char *extension) { static long default_digits = -1; if (default_digits < 0) { const char *l_env; default_digits = GAP_LIB_DEFAULT_DIGITS; l_env = g_getenv("GAP_FRAME_DIGITS"); if(l_env != NULL) { default_digits = atol(l_env); default_digits = CLAMP(default_digits, 1 , GAP_LIB_MAX_DIGITS); } } return (gap_lib_alloc_fname6(basename, nr, extension, default_digits)); } /* end gap_lib_alloc_fname */ /* ---------------------------------- * gap_lib_alloc_fname6 * ---------------------------------- * build the framname by concatenating basename, nr and extension. * the Number part has leading zeroes, depending * on filenames with the same basename and extension on disc. * * if no similar discfiles were found default_digits (with leading zeroes) * are used per default. * * if a similar discfilename is found, the number of digits/leading zeroes * is set equal to the discfile found. * example: * basename == "frame_", nr == 5, ext == ".xcf" * - discfile was found with name: "frame_00001.xcf" * return ("frame_00005.xcf"); * * - discfile was found with name: "frame_001.xcf" * return ("frame_005.xcf"); * * return the resulting framename string * (the calling program should g_free this string * after use) */ char* gap_lib_alloc_fname6(char *basename, long nr, char *extension, long default_digits) { gchar *l_fname; gint l_digits_used; gint l_len; long l_nr_chk; if(basename == NULL) return (NULL); l_len = (strlen(basename) + strlen(extension) + 10); l_fname = (char *)g_malloc(l_len); l_digits_used = default_digits; if(nr < 10000000) { /* try to figure out if the frame numbers are in * 6-digit style, with leading zeroes "frame_000001.xcf" * 4-digit style, with leading zeroes "frame_0001.xcf" * or not "frame_1.xcf" */ l_nr_chk = nr; while(l_nr_chk >= 0) { /* check if frame is on disk with 6-digit style framenumber * (we check 6-digit style first because this is the GAP default style) */ g_snprintf(l_fname, l_len, "%s%06ld%s", basename, l_nr_chk, extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 6; break; } /* check if frame is on disk with 8-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%08ld%s", basename, l_nr_chk, extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 8; break; } /* check if frame is on disk with 7-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%07ld%s", basename, l_nr_chk, extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 7; break; } /* check if frame is on disk with 4-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%04ld%s", basename, l_nr_chk, extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 4; break; } /* check if frame is on disk with 5-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%05ld%s", basename, l_nr_chk, extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 5; break; } /* check if frame is on disk with 3-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%03ld%s", basename, l_nr_chk, extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 3; break; } /* check if frame is on disk with 2-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%02ld%s", basename, l_nr_chk, extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 2; break; } /* now check for filename without leading zeroes in the framenumber */ g_snprintf(l_fname, l_len, "%s%ld%s", basename, l_nr_chk, extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 1; break; } l_nr_chk--; /* if the frames nr and nr-1 were not found * try to check frames 1 and 0 * to limit down the loop to max 4 cycles */ if((l_nr_chk == nr -2) && (l_nr_chk > 1)) { l_nr_chk = 1; } } } else { /* numbers > 10000000 have 9 digits or more */ l_digits_used = 0; } g_free(l_fname); switch(l_digits_used) { case 6: l_fname = g_strdup_printf("%s%06ld%s", basename, nr, extension); break; case 8: l_fname = g_strdup_printf("%s%08ld%s", basename, nr, extension); break; case 7: l_fname = g_strdup_printf("%s%07ld%s", basename, nr, extension); break; case 5: l_fname = g_strdup_printf("%s%05ld%s", basename, nr, extension); break; case 4: l_fname = g_strdup_printf("%s%04ld%s", basename, nr, extension); break; case 3: l_fname = g_strdup_printf("%s%03ld%s", basename, nr, extension); break; case 2: l_fname = g_strdup_printf("%s%02ld%s", basename, nr, extension); break; default: l_fname = g_strdup_printf("%s%ld%s", basename, nr, extension); break; } return(l_fname); } /* end gap_lib_alloc_fname6 */ /* ---------------------------------- * gap_lib_exists_frame_nr * ---------------------------------- * check if frame with nr does exist * and find out how much digits are used for the number part */ gboolean gap_lib_exists_frame_nr(GapAnimInfo *ainfo_ptr, long nr, long *l_has_digits) { gchar *l_fname; gint l_digits_used; gint l_len; long l_nr_chk; gboolean l_exists; l_exists = FALSE; if(ainfo_ptr->basename == NULL) return (FALSE); l_len = (strlen(ainfo_ptr->basename) + strlen(ainfo_ptr->extension) + 10); l_fname = (char *)g_malloc(l_len); l_digits_used = GAP_LIB_DEFAULT_DIGITS; l_nr_chk = nr; while(l_nr_chk >= 0) { /* check if frame is on disk with 6-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%06ld%s", ainfo_ptr->basename, l_nr_chk, ainfo_ptr->extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 6; if(l_nr_chk == nr) { l_exists = TRUE; } break; } /* check if frame is on disk with 8-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%08ld%s", ainfo_ptr->basename, l_nr_chk, ainfo_ptr->extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 8; if(l_nr_chk == nr) { l_exists = TRUE; } break; } /* check if frame is on disk with 7-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%07ld%s", ainfo_ptr->basename, l_nr_chk, ainfo_ptr->extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 7; if(l_nr_chk == nr) { l_exists = TRUE; } break; } /* check if frame is on disk with 4-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%04ld%s", ainfo_ptr->basename, l_nr_chk, ainfo_ptr->extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 4; if(l_nr_chk == nr) { l_exists = TRUE; } break; } /* check if frame is on disk with 5-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%05ld%s", ainfo_ptr->basename, l_nr_chk, ainfo_ptr->extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 5; if(l_nr_chk == nr) { l_exists = TRUE; } break; } /* check if frame is on disk with 3-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%03ld%s", ainfo_ptr->basename, l_nr_chk, ainfo_ptr->extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 3; if(l_nr_chk == nr) { l_exists = TRUE; } break; } /* check if frame is on disk with 2-digit style framenumber */ g_snprintf(l_fname, l_len, "%s%02ld%s", ainfo_ptr->basename, l_nr_chk, ainfo_ptr->extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 2; if(l_nr_chk == nr) { l_exists = TRUE; } break; } /* now check for filename without leading zeroes in the framenumber */ g_snprintf(l_fname, l_len, "%s%ld%s", ainfo_ptr->basename, l_nr_chk, ainfo_ptr->extension); if (gap_lib_file_exists(l_fname)) { l_digits_used = 1; if(l_nr_chk == nr) { l_exists = TRUE; } break; } l_nr_chk--; /* if the frames nr and nr-1 were not found * try to check frames 1 and 0 * to limit down the loop to max 4 cycles */ if((l_nr_chk == nr -2) && (l_nr_chk > 1)) { l_nr_chk = 1; } } g_free(l_fname); *l_has_digits = l_digits_used; return(l_exists); } /* end gap_lib_exists_frame_nr */ /* ============================================================================ * gap_lib_alloc_ainfo_from_name * * allocate and init an ainfo structure from the given imagename * (use this to get anim informations if none of the frame is not loaded * as image into the gimp * and no image_id is available) * The ainfo_type is just a first guess. * (check for videofiles GAP_AINFO_MOVIE is not supported here, * because this would require an video-api open attempt that would slow down) * ============================================================================ */ GapAnimInfo * gap_lib_alloc_ainfo_from_name(const char *imagename, GimpRunMode run_mode) { GapAnimInfo *l_ainfo_ptr; if(imagename == NULL) { return (NULL); } l_ainfo_ptr = (GapAnimInfo*)g_malloc(sizeof(GapAnimInfo)); if(l_ainfo_ptr == NULL) return(NULL); l_ainfo_ptr->basename = NULL; l_ainfo_ptr->new_filename = NULL; l_ainfo_ptr->extension = NULL; l_ainfo_ptr->image_id = -1; l_ainfo_ptr->old_filename = g_strdup(imagename); l_ainfo_ptr->basename = gap_lib_alloc_basename(l_ainfo_ptr->old_filename, &l_ainfo_ptr->frame_nr); if(NULL == l_ainfo_ptr->basename) { gap_lib_free_ainfo(&l_ainfo_ptr); return(NULL); } l_ainfo_ptr->ainfo_type = GAP_AINFO_IMAGE; if(l_ainfo_ptr->frame_nr > 0) { l_ainfo_ptr->ainfo_type = GAP_AINFO_FRAMES; } l_ainfo_ptr->extension = gap_lib_alloc_extension(l_ainfo_ptr->old_filename); l_ainfo_ptr->curr_frame_nr = l_ainfo_ptr->frame_nr; l_ainfo_ptr->first_frame_nr = -1; l_ainfo_ptr->last_frame_nr = -1; l_ainfo_ptr->frame_cnt = 0; l_ainfo_ptr->run_mode = run_mode; return(l_ainfo_ptr); } /* end gap_lib_alloc_ainfo_from_name */ /* ============================================================================ * gap_lib_alloc_ainfo * * allocate and init an ainfo structure from the given image. * ============================================================================ */ GapAnimInfo * gap_lib_alloc_ainfo(gint32 image_id, GimpRunMode run_mode) { GapAnimInfo *l_ainfo_ptr; l_ainfo_ptr = (GapAnimInfo*)g_malloc(sizeof(GapAnimInfo)); if(l_ainfo_ptr == NULL) return(NULL); l_ainfo_ptr->basename = NULL; l_ainfo_ptr->new_filename = NULL; l_ainfo_ptr->extension = NULL; l_ainfo_ptr->image_id = image_id; /* get current gimp images name */ l_ainfo_ptr->old_filename = gimp_image_get_filename(image_id); if(l_ainfo_ptr->old_filename == NULL) { /* note: some gimp versions > 1.2 and < 1.3.x had default filenames for new created images * gimp-1.3.14 delivers NULL for unnamed images again */ l_ainfo_ptr->old_filename = gap_lib_alloc_fname("frame_", 1, ".xcf"); /* assign a defaultname */ gimp_image_set_filename (image_id, l_ainfo_ptr->old_filename); } l_ainfo_ptr->basename = gap_lib_alloc_basename(l_ainfo_ptr->old_filename, &l_ainfo_ptr->frame_nr); if(NULL == l_ainfo_ptr->basename) { gap_lib_free_ainfo(&l_ainfo_ptr); return(NULL); } l_ainfo_ptr->ainfo_type = GAP_AINFO_IMAGE; if(l_ainfo_ptr->frame_nr > 0) { l_ainfo_ptr->ainfo_type = GAP_AINFO_FRAMES; } l_ainfo_ptr->extension = gap_lib_alloc_extension(l_ainfo_ptr->old_filename); l_ainfo_ptr->curr_frame_nr = l_ainfo_ptr->frame_nr; l_ainfo_ptr->first_frame_nr = -1; l_ainfo_ptr->last_frame_nr = -1; l_ainfo_ptr->frame_cnt = 0; l_ainfo_ptr->run_mode = run_mode; l_ainfo_ptr->frame_nr_before_curr_frame_nr = -1; /* -1 if no frame found before curr_frame_nr */ l_ainfo_ptr->frame_nr_after_curr_frame_nr = -1; /* -1 if no frame found after curr_frame_nr */ return(l_ainfo_ptr); } /* end gap_lib_alloc_ainfo */ /* ============================================================================ * gap_lib_dir_ainfo * * fill in more items into the given ainfo structure. * - first_frame_nr * - last_frame_nr * - frame_cnt * * to get this information, the directory entries have to be checked * ============================================================================ */ int gap_lib_dir_ainfo(GapAnimInfo *ainfo_ptr) { char *l_dirname; char *l_dirname_ptr; char *l_ptr; const char *l_exptr; char *l_dummy; GDir *l_dirp; const gchar *l_entry; long l_nr; long l_maxnr; long l_minnr; short l_dirflag; char dirname_buff[1024]; ainfo_ptr->frame_cnt = 0; l_dirp = NULL; l_minnr = 99999999; l_maxnr = 0; l_dirname = g_strdup(ainfo_ptr->basename); l_ptr = &l_dirname[strlen(l_dirname)]; while(l_ptr != l_dirname) { if ((*l_ptr == G_DIR_SEPARATOR) || (*l_ptr == DIR_ROOT)) { *l_ptr = '\0'; /* split the string into dirpath 0 basename */ l_ptr++; break; /* stop at char behind the slash */ } l_ptr--; } if(gap_debug) printf("DEBUG gap_lib_dir_ainfo: BASENAME:%s\n", l_ptr); if (l_ptr == l_dirname) { l_dirname_ptr = "."; l_dirflag = 0; } else if (*l_dirname == '\0') { l_dirname_ptr = G_DIR_SEPARATOR_S ; l_dirflag = 1; } else { l_dirname_ptr = l_dirname; l_dirflag = 2; } if(gap_debug) printf("DEBUG gap_lib_dir_ainfo: DIRNAME:%s\n", l_dirname_ptr); l_dirp = g_dir_open( l_dirname_ptr, 0, NULL ); if(!l_dirp) fprintf(stderr, "ERROR gap_lib_dir_ainfo: can't read directory %s\n", l_dirname_ptr); else { while ( (l_entry = g_dir_read_name( l_dirp )) != NULL ) { /* if(gap_debug) printf("DEBUG gap_lib_dir_ainfo: l_entry:%s\n", l_entry); */ /* findout extension of the directory entry name */ l_exptr = &l_entry[strlen(l_entry)]; while(l_exptr != l_entry) { if(*l_exptr == G_DIR_SEPARATOR) { break; } /* dont run into dir part */ if(*l_exptr == '.') { break; } l_exptr--; } /* l_exptr now points to the "." of the direntry (or to its begin if has no ext) */ /* now check for equal extension */ if((*l_exptr == '.') && (0 == strcmp(l_exptr, ainfo_ptr->extension))) { /* build full pathname (to check if file exists) */ switch(l_dirflag) { case 0: g_snprintf(dirname_buff, sizeof(dirname_buff), "%s", l_entry); break; case 1: g_snprintf(dirname_buff, sizeof(dirname_buff), "%c%s", G_DIR_SEPARATOR, l_entry); break; default: /* UNIX: "/dir/file" * DOS: "drv:\dir\file" */ g_snprintf(dirname_buff, sizeof(dirname_buff), "%s%c%s", l_dirname_ptr, G_DIR_SEPARATOR, l_entry); break; } if(1 == gap_lib_file_exists(dirname_buff)) /* check for regular file */ { /* get basename and frame number of the directory entry */ l_dummy = gap_lib_alloc_basename(l_entry, &l_nr); if(l_dummy != NULL) { /* check for files, with equal basename (frames) * (length must be greater than basepart+extension * because of the frame_nr part "0000") */ if((0 == strcmp(l_ptr, l_dummy)) && ( strlen(l_entry) > strlen(l_dummy) + strlen(l_exptr) )) { ainfo_ptr->frame_cnt++; if(gap_debug) { printf("DEBUG gap_lib_dir_ainfo: %s NR=%ld Curr:%ld\n", l_entry, l_nr, ainfo_ptr->curr_frame_nr); } if (l_nr > l_maxnr) l_maxnr = l_nr; if (l_nr < l_minnr) l_minnr = l_nr; if ((l_nr < ainfo_ptr->curr_frame_nr) && (l_nr > ainfo_ptr->frame_nr_before_curr_frame_nr)) { ainfo_ptr->frame_nr_before_curr_frame_nr = l_nr; } if (l_nr > ainfo_ptr->curr_frame_nr) { if ((ainfo_ptr->frame_nr_after_curr_frame_nr < 0) || (l_nr < ainfo_ptr->frame_nr_after_curr_frame_nr)) { ainfo_ptr->frame_nr_after_curr_frame_nr = l_nr; } } } g_free(l_dummy); } } } } g_dir_close( l_dirp ); } g_free(l_dirname); /* set first_frame_nr and last_frame_nr (found as "_0099" in diskfile namepart) */ ainfo_ptr->last_frame_nr = l_maxnr; ainfo_ptr->first_frame_nr = MIN(l_minnr, l_maxnr); return 0; /* OK */ } /* end gap_lib_dir_ainfo */ /* ============================================================================ * gap_lib_free_ainfo * * free ainfo and its allocated stuff * ============================================================================ */ void gap_lib_free_ainfo(GapAnimInfo **ainfo) { GapAnimInfo *aptr; if((aptr = *ainfo) == NULL) return; if(aptr->basename) g_free(aptr->basename); if(aptr->extension) g_free(aptr->extension); if(aptr->new_filename) g_free(aptr->new_filename); if(aptr->old_filename) g_free(aptr->old_filename); g_free(aptr); } /* ============================================================================ * gap_lib_get_frame_nr * ============================================================================ */ long gap_lib_get_frame_nr_from_name(char *fname) { long number; int len; char *basename; if(fname == NULL) return(-1); basename = gap_lib_alloc_basename(fname, &number); if(basename == NULL) return(-1); len = strlen(basename); g_free(basename); if(number > 0) return(number); if(fname[len] == '0') return(number); /* * if(fname[len] == '_') * { * if(fname[len+1] == '0') return(TRUE); * } */ return(-1); } /* ------------------------------- * gap_lib_get_frame_nr * ------------------------------- * return -1 if the specified image is * NOT a gimp-gap typical frame image (e.g. has no number part in its filename) * return the number part in case of valid frame image. */ long gap_lib_get_frame_nr(gint32 image_id) { char *fname; long number; number = -1; if (gap_image_is_alive(image_id)) { fname = gimp_image_get_filename(image_id); if(fname) { number = gap_lib_get_frame_nr_from_name(fname); g_free(fname); } } return (number); } /* ============================================================================ * gap_lib_chk_framechange * * check if the current frame nr has changed. * useful after dialogs, because the user may have renamed the current image * (using save as) * while the gap-plugin's dialog was open. * return: 0 .. OK * -1 .. Changed (or error occurred) * ============================================================================ */ int gap_lib_chk_framechange(GapAnimInfo *ainfo_ptr) { int l_rc; GapAnimInfo *l_ainfo_ptr; l_rc = -1; l_ainfo_ptr = gap_lib_alloc_ainfo(ainfo_ptr->image_id, ainfo_ptr->run_mode); if(l_ainfo_ptr != NULL) { if(ainfo_ptr->curr_frame_nr == l_ainfo_ptr->curr_frame_nr ) { l_rc = 0; } else { gap_arr_msg_win(ainfo_ptr->run_mode, _("Operation cancelled.\n" "Current frame was changed while dialog was open.")); } gap_lib_free_ainfo(&l_ainfo_ptr); } return l_rc; } /* end gap_lib_chk_framechange */ /* ============================================================================ * gap_lib_chk_framerange * * check ainfo struct if there is a framerange (of at least one frame) * return: 0 .. OK * -1 .. No frames there (print error) * ============================================================================ */ int gap_lib_chk_framerange(GapAnimInfo *ainfo_ptr) { if(ainfo_ptr->frame_cnt == 0) { gap_arr_msg_win(ainfo_ptr->run_mode, _("Operation cancelled.\n" "GAP video plug-ins only work with filenames\n" "that end in numbers like _000001.xcf.\n" "==> Rename your image, then try again.")); return -1; } return 0; } /* end gap_lib_chk_framerange */ /* ============================================================================ * p_gzip * gzip or gunzip the file to a temporary file. * zip == "zip" compress * zip == "unzip" decompress * return a pointer to the temporary created (by gzip) file. * NULL in case of errors * ============================================================================ */ char * p_gzip (char *orig_name, char *new_name, char *zip) { gchar* l_cmd; gchar* l_tmpname; gint l_rc, l_rc2; if(zip == NULL) return NULL; l_cmd = NULL; l_tmpname = new_name; /* used gzip options: * -c --stdout --to-stdout * Write output on standard output * -d --decompress --uncompress * Decompress. * -f --force * Force compression or decompression even if the file */ if(*zip == 'u') { l_cmd = g_strdup_printf("gzip -cfd <\"%s\" >\"%s\"", orig_name, l_tmpname); } else { l_cmd = g_strdup_printf("gzip -cf <\"%s\" >\"%s\"", orig_name, l_tmpname); } if(gap_debug) printf("system: %s\n", l_cmd); l_rc = system(l_cmd); if(l_rc != 0) { /* Shift 8 Bits gets Retcode of the executed Program */ l_rc2 = l_rc >> 8; fprintf(stderr, "ERROR system: %s\nreturncodes %d %d", l_cmd, l_rc, l_rc2); l_tmpname = NULL; } g_free(l_cmd); return l_tmpname; } /* end p_gzip */ /* ============================================================================ * p_decide_save_as * decide what to do on attempt to save a frame in any image format * (other than xcf) * Let the user decide if the frame is to save "as it is" or "flattened" * ("as it is" will save only the backround layer in most fileformat types) * The SAVE_AS_MODE is stored , and reused * (without displaying the dialog again) * on subsequent calls of the same frame-basename and extension * in the same GIMP-session. * * return -1 ... CANCEL (do not save) * 0 ... save the image (may be flattened) * ============================================================================ */ int p_decide_save_as(gint32 image_id, const char *sav_name, const char *final_sav_name) { gchar *l_key_save_as_mode; gchar *l_extension; gchar *l_ext; gchar *l_basename; long l_number; int l_sav_rc; static GapArrButtonArg l_argv[3]; int l_argc; int l_save_as_mode; GimpRunMode l_run_mode; /* check if there are SAVE_AS_MODE settings (from privious calls within one gimp session) */ l_save_as_mode = -1; l_sav_rc = -1; l_extension = gap_lib_alloc_extension(final_sav_name); l_basename = gap_lib_alloc_basename(final_sav_name, &l_number); l_key_save_as_mode = g_strdup_printf("GIMP_GAP_SAVE_MODE_%s%s" ,l_basename ,l_extension ); gimp_get_data (l_key_save_as_mode, &l_save_as_mode); if(gap_debug) { printf("DEBUG: p_decide_save_as l_save_as_mode: %d\n" , l_save_as_mode ); } if(l_save_as_mode == -1) { gchar *l_key_gimprc; gchar *l_val_gimprc; gboolean l_ask; /* no defined value found (this is the 1.st call for this animation in the current session) * check for gimprc configuration to decide how to continue: * open a dialog (if no configuration value was found, * or configuration says "ask" (== other value than "yes" or "no" ) */ l_ext = l_extension; if(*l_ext == '.') { l_ext++; } l_key_gimprc = g_strdup_printf("video-save-flattened-%s", l_ext); if(gap_debug) { printf("GIMPRC KEY:%s:\n", l_key_gimprc); } l_val_gimprc = gimp_gimprc_query(l_key_gimprc); l_ask = TRUE; if(l_val_gimprc) { if(gap_debug) { printf("GIMPRC VAL:%s:\n", l_val_gimprc); } if(strcmp(l_val_gimprc, "yes") == 0) { l_save_as_mode = 1; l_ask = FALSE; } if(strcmp(l_val_gimprc, "no") == 0) { l_save_as_mode = 0; l_ask = FALSE; } g_free(l_val_gimprc); } else { if(gap_debug) { printf("GIMPRC VAL:\n"); } } if(l_ask) { gchar *l_msg; l_argv[0].but_txt = GTK_STOCK_CANCEL; l_argv[0].but_val = -1; l_argv[1].but_txt = _("Save Flattened"); l_argv[1].but_val = 1; l_argv[2].but_txt = _("Save As Is"); l_argv[2].but_val = 0; l_argc = 3; l_msg = g_strdup_printf(_("You are using another file format than xcf.\n" "Save operations may result in loss of layer information.\n\n" "To configure flattening for this fileformat\n" "(permanent for all further sessions) please add the line:\n" "(%s %s)\n" "to your gimprc file.") , l_key_gimprc , "\"yes\"" ); l_save_as_mode = gap_arr_buttons_dialog (_("Fileformat Warning") ,l_msg , l_argc, l_argv, -1); g_free(l_msg); } g_free(l_key_gimprc); if(gap_debug) { printf("DEBUG: decide SAVE_AS_MODE %d\n", (int)l_save_as_mode); } l_run_mode = GIMP_RUN_INTERACTIVE; } else { l_run_mode = GIMP_RUN_WITH_LAST_VALS; } gimp_set_data (l_key_save_as_mode, &l_save_as_mode, sizeof(l_save_as_mode)); g_free(l_key_save_as_mode); if(l_save_as_mode < 0) { l_sav_rc = -1; } else { if(l_save_as_mode == 1) { gimp_image_flatten (image_id); } l_sav_rc = p_lib_save_named_image_1(image_id , sav_name , l_run_mode , FALSE /* do not enable_thumbnailsave */ , l_basename , l_extension ); } g_free(l_basename); g_free(l_extension); return l_sav_rc; } /* end p_decide_save_as */ /* ============================================================================ * gap_lib_gap_check_save_needed * ============================================================================ */ gint32 gap_lib_gap_check_save_needed(gint32 image_id) { const char *value_string; if (gimp_image_is_dirty(image_id)) { if(gap_debug) printf("gap_lib_gap_check_save_needed: GAP need save, caused by dirty image id: %d\n", (int)image_id); return(TRUE); } else { value_string = gimp_gimprc_query("trust-dirty-flag"); if(value_string != NULL) { if(gap_debug) printf("gap_lib_gap_check_save_needed:GAP gimprc FOUND relevant LINE: trust-dirty-flag %s\n", value_string); { if((*value_string != 'y') && (*value_string != 'Y')) { if(gap_debug) printf("gap_lib_gap_check_save_needed: GAP need save, forced by gimprc trust-dirty-flag %s\n", value_string); return(TRUE); } } } } if(gap_debug) printf("gap_lib_gap_check_save_needed: GAP can SKIP save\n"); return(FALSE); } /* end gap_lib_gap_check_save_needed */ /* ------------------------------------------ * p_lib_save_jpg_non_interactive * ------------------------------------------ * this procedure handles NON-Interactive save of a frame * in the lossy but widly spread JPEG fileformat. * The quality settings have to be provided via jpg_save_parasite * paramteter that has the structure GAPJpegSaveVals. * NOTE: the structure GAPJpegSaveVals must match with * the structure JpegSaveVals (as defined by the jpeg file save plugin * in file jpeg-save.h of the GIMP distribution) */ static gint32 p_lib_save_jpg_non_interactive(gint32 image_id, gint32 l_drawable_id, const char *sav_name, const GAPJpegSaveVals *save_vals) { gint32 l_rc; gint l_retvals; l_rc = FALSE; if(gap_debug) { printf("DEBUG: p_lib_save_jpg_non_interactive: '%s' imageId:%d, drawableID:%d\n" " jpg quality:%f\n" " jpg smoothing:%f\n" " jpg optimize:%d\n" " jpg progressive:%d\n" " jpg subsmp:%d\n" " jpg baseline:%d\n" " jpg restart:%d\n" " jpg dct:%d\n" , sav_name , (int)image_id , (int)l_drawable_id , (float)save_vals->quality , (float)save_vals->smoothing , (int)save_vals->optimize , (int)save_vals->progressive , (int)save_vals->subsmp , (int)save_vals->baseline , (int)save_vals->restart , (int)save_vals->dct ); } /* save specified layer of current frame as jpg image */ GimpParam *l_params; l_params = gimp_run_procedure ("file_jpeg_save", &l_retvals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, image_id, GIMP_PDB_DRAWABLE, l_drawable_id, GIMP_PDB_STRING, sav_name, GIMP_PDB_STRING, sav_name, /* raw name ? */ GIMP_PDB_FLOAT, save_vals->quality / 100.0, GIMP_PDB_FLOAT, save_vals->smoothing, GIMP_PDB_INT32, save_vals->optimize, GIMP_PDB_INT32, save_vals->progressive, GIMP_PDB_STRING, "GIMP-GAP Frame", /* comment */ GIMP_PDB_INT32, save_vals->subsmp, GIMP_PDB_INT32, save_vals->baseline, GIMP_PDB_INT32, save_vals->restart, GIMP_PDB_INT32, save_vals->dct, GIMP_PDB_END); if (l_params[0].data.d_status == GIMP_PDB_SUCCESS) { if(gap_debug) { printf("DEBUG: p_lib_save_jpg_non_interactive: GIMP_PDB_SUCCESS '%s\n" ,sav_name ); } l_rc = TRUE; } gimp_destroy_params (l_params, l_retvals); return (l_rc); } /* end p_lib_save_jpg_non_interactive */ static gboolean p_extension_is_jpeg(const char *extension) { if (extension != NULL) { const char *ext; ext = extension; if (*ext == '.') { ext++; } if ((*ext == 'j') || (*ext == 'J')) { ext++; if ((*ext == 'p') || (*ext == 'P')) { return (TRUE); } } } return (FALSE); } /* ------------------------------------- * p_lib_save_named_image_1 * ------------------------------------- * save non xcf frames/images. * This procedure handles special case if frames have to be * saved as JPEG files. */ static gint32 p_lib_save_named_image_1(gint32 image_id, const char *sav_name, GimpRunMode run_mode, gboolean enable_thumbnailsave , const char *l_basename , const char *l_extension ) { GAPJpegSaveVals *jpg_save_vals; gint32 l_sav_rc; char *l_key_save_vals_jpg; l_sav_rc = -1; jpg_save_vals = NULL; l_key_save_vals_jpg = g_strdup_printf("GIMP_GAP_SAVE_VALS_JPG_%s%s" ,l_basename ,l_extension ); if(gap_debug) { printf("p_lib_save_named_image_1: runmode:%d sav_name:%s\n .. l_key_save_vals_jpg:%s\n .. base:%s\n .. ext:%s\n" ,run_mode ,sav_name ,l_key_save_vals_jpg ,l_basename ,l_extension ); } /* before non interactive save options check if we have already jpeg-save-options * for the handled frames with the same basename and extension */ if (run_mode != GIMP_RUN_INTERACTIVE) { int jpg_parsize; jpg_parsize = gimp_get_data_size(l_key_save_vals_jpg); if(gap_debug) { printf("p_lib_save_named_image_1: jpg_parsize=%d\n" ,jpg_parsize ); } if (jpg_parsize > 0) { jpg_save_vals = g_malloc(jpg_parsize); gimp_get_data (l_key_save_vals_jpg, jpg_save_vals); run_mode = GIMP_RUN_NONINTERACTIVE; } } l_sav_rc = p_lib_save_named_image2(image_id , sav_name , run_mode , FALSE /* do not enable_thumbnailsave */ , jpg_save_vals ); if (jpg_save_vals != NULL) { g_free(jpg_save_vals); } /* check for jpeg specific save options after INTERACTIVE save operation * (recent versions of JPEG save plugin shall store the save options * in parasite data.) */ if ((run_mode == GIMP_RUN_INTERACTIVE) && (p_extension_is_jpeg(l_extension))) { GimpParasite *jpg_save_parasite; jpg_save_parasite = gimp_image_parasite_find (image_id, "jpeg-save-options"); if(gap_debug) { printf("DEBUG: jpg_save_parasite %d\n", (int)jpg_save_parasite); } if (jpg_save_parasite) { const GAPJpegSaveVals *const_jpg_save_vals; const_jpg_save_vals = gimp_parasite_data (jpg_save_parasite); /* store the jpeg save options for the handled frame basename and extension in this session */ gimp_set_data (l_key_save_vals_jpg, const_jpg_save_vals, sizeof(GAPJpegSaveVals)); gimp_parasite_free (jpg_save_parasite); } } g_free(l_key_save_vals_jpg); return (l_sav_rc); } /* end p_lib_save_named_image_1 */ /* ============================================================================ * gap_lib_save_named_image / 2 * ============================================================================ * this procedure is typically used to save frame images in other image formats than * gimp native XCF format. */ static gint32 p_lib_save_named_image2(gint32 image_id, const char *sav_name, GimpRunMode run_mode, gboolean enable_thumbnailsave ,const GAPJpegSaveVals *jpg_save_vals) { gint32 l_drawable_id; gint l_nlayers; gint32 *l_layers_list; gboolean l_rc; if(gap_debug) { printf("DEBUG: before p_lib_save_named_image2: '%s'\n", sav_name); } l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list == NULL) { printf("ERROR: gap_lib.c.p_lib_save_named_image2: failed to save '%s' because has no layers\n" , sav_name ); return -1; } l_drawable_id = l_layers_list[l_nlayers -1]; /* use the background layer */ if ((jpg_save_vals != NULL) && (run_mode != GIMP_RUN_INTERACTIVE)) { /* Special case: save JPG noninteractive * Since GIMP-2.4.x jpeg file save plugin changed behaviour: * when saved in GIMP_RUN_WITH_LAST_VALS mode it acts the same way * as interactive mode (e.q. opens a dialog) * this behaviour is not acceptable when saving lots of frames. * therefore GAP tries to figure out the jpeg save paramters that * are available as parasite data, and perform a non interactive * save operation. * (This way the GIMP_GAP code gets a dependency to all future * changes of JPEG file save parameter changes, * but at least works for GIMP-2.4.x again) */ l_rc = p_lib_save_jpg_non_interactive(image_id, l_drawable_id, sav_name, jpg_save_vals ); } else { l_rc = gimp_file_save(run_mode, image_id, l_drawable_id, sav_name, sav_name /* raw name ? */ ); } if(gap_debug) { printf("DEBUG: after p_lib_save_named_image2: '%s' nlayers=%d image=%d drawable_id=%d run_mode=%d\n" , sav_name , (int)l_nlayers , (int)image_id , (int)l_drawable_id , (int)run_mode ); } if(enable_thumbnailsave) { gchar *l_sav_name; l_sav_name = g_strdup(sav_name); gap_thumb_cond_gimp_file_save_thumbnail(image_id, l_sav_name); g_free(l_sav_name); } if(gap_debug) { printf("DEBUG: after thumbmail save\n"); } g_free (l_layers_list); if (l_rc != TRUE) { printf("ERROR: p_lib_save_named_image2 gimp_file_save failed '%s' rc:%d\n" , sav_name ,(int)l_rc ); return -1; } return image_id; } /* end p_lib_save_named_image2 */ gint32 gap_lib_save_named_image(gint32 image_id, const char *sav_name, GimpRunMode run_mode) { gchar *l_extension; gchar *l_basename; gint32 l_rc; long l_number; l_extension = gap_lib_alloc_extension(sav_name); l_basename = gap_lib_alloc_basename(sav_name, &l_number); l_rc = p_lib_save_named_image_1(image_id , sav_name , run_mode , TRUE /* enable_thumbnailsave */ , l_basename , l_extension ); g_free(l_extension); g_free(l_basename); return (l_rc); } /* ============================================================================ * gap_lib_save_named_frame * save frame into temporary image, * on success rename it to desired framename. * (this is done, to avoid corrupted frames on disk in case of * crash in one of the save procedures) * ============================================================================ */ int gap_lib_save_named_frame(gint32 image_id, char *sav_name) { GimpParam *l_params; gchar *l_ext; char *l_tmpname; gint l_retvals; int l_gzip; int l_xcf; int l_rc; l_tmpname = NULL; l_rc = -1; l_gzip = 0; /* dont zip */ l_xcf = 0; /* assume no xcf format */ /* check extension to decide if savd file will be zipped */ l_ext = gap_lib_alloc_extension(sav_name); if(l_ext == NULL) { printf("gap_lib_save_named_frame failed for file:%s (because it has no extension)\n" ,sav_name ); return -1; } gimp_image_set_filename(image_id, sav_name); if(0 == strcmp(l_ext, ".xcf")) { l_xcf = 1; } else if(0 == strcmp(l_ext, ".xcfgz")) { l_gzip = 1; /* zip it */ l_xcf = 1; } else if(0 == strcmp(l_ext, ".gz")) { l_gzip = 1; /* zip it */ } /* find a temp name * that resides on the same filesystem as sav_name * and has the same extension as the original sav_name */ l_tmpname = g_strdup_printf("%s.gtmp%s", sav_name, l_ext); if(1 == gap_lib_file_exists(l_tmpname)) { /* FILE exists: let gimp find another temp name */ l_tmpname = gimp_temp_name(&l_ext[1]); } g_free(l_ext); if(gap_debug) { char *env_no_save; env_no_save = (gchar *) g_getenv("GAP_NO_SAVE"); if(env_no_save != NULL) { printf("DEBUG: GAP_NO_SAVE is set: save is skipped: '%s'\n", l_tmpname); g_free(l_tmpname); /* free if it was a temporary name */ return 0; } } if(l_xcf != 0) { if(gap_debug) { printf("DEBUG: gap_lib_save_named_frame before gimp_xcf_save on file: '%s'\n" , l_tmpname ); } /* save current frame as xcf image * xcf_save does operate on the complete image, * the drawable is ignored. (we can supply a dummy value) */ l_params = gimp_run_procedure ("gimp_xcf_save", &l_retvals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, image_id, GIMP_PDB_DRAWABLE, 0, GIMP_PDB_STRING, l_tmpname, GIMP_PDB_STRING, l_tmpname, /* raw name ? */ GIMP_PDB_END); if(gap_debug) { printf("DEBUG: after xcf gap_lib_save_named_frame: '%s'\n", l_tmpname); } if (l_params[0].data.d_status == GIMP_PDB_SUCCESS) { l_rc = image_id; } gimp_destroy_params (l_params, l_retvals); } else { if(gap_debug) { printf("DEBUG: gap_lib_save_named_frame before save NON-XCF file: '%s'\n" , l_tmpname ); } /* let gimp try to save (and detect filetype by extension) * Note: the most imagefileformats do not support multilayer * images, and extra channels * the result may not contain the whole imagedata * * To Do: Should warn the user at 1.st attempt to do this. */ l_rc = p_decide_save_as(image_id, l_tmpname, sav_name); if(gap_debug) { printf("DEBUG: gap_lib_save_named_frame after save NON-XCF file: '%s' rc:%d\n" , l_tmpname , (int)l_rc ); } } if(l_rc < 0) { g_remove(l_tmpname); g_free(l_tmpname); /* free temporary name */ return l_rc; } if(l_gzip == 0) { /* remove sav_name, then rename tmpname ==> sav_name */ g_remove(sav_name); if (0 != g_rename(l_tmpname, sav_name)) { /* if tempname is located on another filesystem (errno == EXDEV) * rename will not work. * so lets try a copy ; remove sequence */ if(gap_debug) { printf("DEBUG: gap_lib_save_named_frame: RENAME 2nd try\n"); } if(0 == gap_lib_file_copy(l_tmpname, sav_name)) { g_remove(l_tmpname); } else { printf("ERROR in gap_lib_save_named_frame: can't rename %s to %s\n" , l_tmpname , sav_name ); return -1; } } } else { /* ZIP tmpname ==> sav_name */ if(NULL != p_gzip(l_tmpname, sav_name, "zip")) { /* OK zip created compressed file named sav_name * now delete the uncompressed l_tempname */ g_remove(l_tmpname); } } if(gap_debug) { printf("DEBUG: gap_lib_save_named_frame: before gap_thumb_cond_gimp_file_save_thumbnail\n"); } gap_thumb_cond_gimp_file_save_thumbnail(image_id, sav_name); if(gap_debug) { printf("DEBUG: gap_lib_save_named_frame: after gap_thumb_cond_gimp_file_save_thumbnail\n"); } g_free(l_tmpname); /* free temporary name */ return l_rc; } /* end gap_lib_save_named_frame */ /* ============================================================================ * p_save_old_frame * ============================================================================ */ int p_save_old_frame(GapAnimInfo *ainfo_ptr, GapVinVideoInfo *vin_ptr) { /* SAVE of old image image if it has unsaved changes * (or if Unconditional frame save is forced by gimprc setting) */ if(gap_lib_gap_check_save_needed(ainfo_ptr->image_id)) { if(gap_debug) { printf("p_save_old_frame Save required for file:%s\n" , ainfo_ptr->old_filename ); } /* check and perform automatic onionskinlayer remove */ if(vin_ptr) { if((vin_ptr->auto_delete_before_save) && (vin_ptr->onionskin_auto_enable)) { gap_onion_base_onionskin_delete(ainfo_ptr->image_id); } } return (gap_lib_save_named_frame(ainfo_ptr->image_id, ainfo_ptr->old_filename)); } else { if(gap_debug) { printf("p_save_old_frame No save needed for file:%s OK\n" , ainfo_ptr->old_filename ); } } return 0; } /* end p_save_old_frame */ /* ============================================================================ * gap_lib_load_image * load image of any type by filename, and return its image id * (or -1 in case of errors) * ============================================================================ */ gint32 gap_lib_load_image (char *lod_name) { char *l_ext; char *l_tmpname; gint32 l_tmp_image_id; int l_rc; l_rc = 0; l_tmpname = NULL; l_ext = gap_lib_alloc_extension(lod_name); if(l_ext != NULL) { if((0 == strcmp(l_ext, ".xcfgz")) || (0 == strcmp(l_ext, ".gz"))) { /* find a temp name and */ /* try to unzip file, before loading it */ l_tmpname = p_gzip(lod_name, gimp_temp_name(&l_ext[1]), "unzip"); } else l_tmpname = lod_name; g_free(l_ext); } if(l_tmpname == NULL) { return -1; } if(gap_debug) printf("DEBUG: before gap_lib_load_image: '%s'\n", l_tmpname); l_tmp_image_id = gimp_file_load(GIMP_RUN_NONINTERACTIVE, l_tmpname, l_tmpname /* raw name ? */ ); if(gap_debug) printf("DEBUG: after gap_lib_load_image: '%s' id=%d\n\n", l_tmpname, (int)l_tmp_image_id); if(l_tmpname != lod_name) { g_remove(l_tmpname); g_free(l_tmpname); /* free if it was a temporary name */ } return l_tmp_image_id; } /* end gap_lib_load_image */ /* ============================================================================ * gap_lib_load_named_frame * load new frame, * reconnect displays from old existing image to the new loaded frame * and delete the old image. * returns: new_image_id (or -1 on errors) * ============================================================================ */ gint32 gap_lib_load_named_frame (gint32 old_image_id, char *lod_name) { gint32 l_new_image_id; l_new_image_id = gap_lib_load_image(lod_name); if(gap_debug) { printf("DEBUG: after gap_lib_load_named_frame: '%s' old_id=%d new_id=%d\n\n", lod_name, (int)old_image_id, (int)l_new_image_id); } if(l_new_image_id < 0) { return -1; } if (gap_pdb_gimp_displays_reconnect(old_image_id, l_new_image_id)) { /* deleteing the old image if it is still alive * (maybe still required gimp-2.2.x prior to gimp-2.2.11 * gimp-2.2.11 still accepts the delete, but the old image becomes invalid after * reconnecting the display. * gimp-2.3.8 even complains and breaks gimp-gap if we attempt to delete * the old image. (see #339840) * GAP has no more chance for explicite delete the old image * (hope that this is already done implicite by gimp_reconnect_displays ?) */ if(gap_image_is_alive(old_image_id)) { gimp_image_delete(old_image_id); } gimp_image_undo_disable(l_new_image_id); /* use the original lod_name */ gimp_image_set_filename (l_new_image_id, lod_name); /* dont consider image dirty after load */ gimp_image_clean_all(l_new_image_id); /* Update the active_image table for the Navigator Dialog * (TODO: replace the active-image table by real Event handling) */ gap_navat_update_active_image(old_image_id, l_new_image_id); gimp_image_undo_enable(l_new_image_id); return l_new_image_id; } printf("GAP: Error: PDB call of gimp_displays_reconnect failed\n"); return (-1); } /* end gap_lib_load_named_frame */ /* ============================================================================ * gap_lib_replace_image * * make new_filename of next file to load, check if that file does exist on disk * then save current image and replace it, by loading the new_filename * this includes automatic onionskin layer handling and * active layer tracking * * return image_id (of the new loaded frame) on success * or -1 on errors * ============================================================================ */ gint32 gap_lib_replace_image(GapAnimInfo *ainfo_ptr) { gint32 image_id; GapVinVideoInfo *vin_ptr; gboolean do_onionskin_crate; gint32 ref_active_layer; gint32 ref_layer_stackpos; gchar *ref_layer_name; int save_rc; do_onionskin_crate = FALSE; if(gap_debug) { printf("gap_lib_replace_image START\n"); } ref_layer_name = p_get_active_layer_name(ainfo_ptr->image_id ,&ref_active_layer ,&ref_layer_stackpos ); if(ainfo_ptr->new_filename != NULL) { g_free(ainfo_ptr->new_filename); } ainfo_ptr->new_filename = gap_lib_alloc_fname(ainfo_ptr->basename, ainfo_ptr->frame_nr, ainfo_ptr->extension); if(ainfo_ptr->new_filename == NULL) { if(gap_debug) { printf("gap_lib_replace_image (1) return because ainfo_ptr->new_filename == NULL\n"); } return -1; } if(0 == gap_lib_file_exists(ainfo_ptr->new_filename )) { if(gap_debug) { printf("gap_lib_replace_image (2) return because %s does not exist (or is empty)\n" , ainfo_ptr->new_filename ); } return -1; } if(gap_debug) { printf("gap_lib_replace_image (3) ainfo_ptr->new_filename:%s OK\n" , ainfo_ptr->new_filename ); } vin_ptr = gap_vin_get_all(ainfo_ptr->basename); save_rc = p_save_old_frame(ainfo_ptr, vin_ptr); if(gap_debug) { printf("gap_lib_replace_image (4) automatic save: save_rc:%d, old_filename:%s\n" , (int)save_rc , ainfo_ptr->old_filename ); } if(save_rc < 0) { if(vin_ptr) { g_free(vin_ptr); } printf("gap_lib_replace_image (5) automatic save failed: save_rc:%d, old_filename:%s\n" , (int)save_rc , ainfo_ptr->old_filename ); return -1; } if((vin_ptr->auto_replace_after_load) && (vin_ptr->onionskin_auto_enable)) { do_onionskin_crate = TRUE; /* check if directoryscan is needed */ if((ainfo_ptr->first_frame_nr < 0) || (ainfo_ptr->last_frame_nr < 0)) { /* perform directoryscan to findout first_frame_nr and last_frame_nr * that is needed for onionskin creation */ gap_lib_dir_ainfo(ainfo_ptr); } } image_id = gap_lib_load_named_frame(ainfo_ptr->image_id, ainfo_ptr->new_filename); /* check and peroform automatic onionskinlayer creation */ if(vin_ptr) { if(do_onionskin_crate) { /* create onionskinlayers without keeping the handled images cached * (passing NULL pointers for the chaching structures and functions) */ gap_onion_base_onionskin_apply(NULL /* dummy pointer gpp */ , image_id /* apply on the newly loaded image_id */ , vin_ptr , ainfo_ptr->frame_nr /* the new current frame_nr */ , ainfo_ptr->first_frame_nr , ainfo_ptr->last_frame_nr , ainfo_ptr->basename , ainfo_ptr->extension , NULL /* fptr_add_img_to_cache */ , NULL /* fptr_find_frame_in_img_cache */ , FALSE /* use_cache */ ); } p_do_active_layer_tracking(image_id ,vin_ptr ,ref_layer_name ,ref_layer_stackpos ); g_free(vin_ptr); } if(ref_layer_name) { g_free(ref_layer_name); } if(gap_debug) { printf("gap_lib_replace_image ENDED regular\n"); } return(image_id); } /* end gap_lib_replace_image */ /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ /* ============================================================================ * gap_video_paste Buffer procedures * ============================================================================ */ static gchar * p_get_video_paste_basename(void) { gchar *l_basename; l_basename = gimp_gimprc_query("video-paste-basename"); if(l_basename == NULL) { l_basename = g_strdup("gap_video_pastebuffer_"); } return(l_basename); } static gchar * p_get_video_paste_dir(void) { gchar *l_dir; gint l_len; l_dir = gimp_gimprc_query("video-paste-dir"); if(l_dir == NULL) { l_dir = g_strdup("/tmp"); } /* if dir is configured with trailing dir seprator slash * then cut it off */ l_len = strlen(l_dir); if((l_dir[l_len -1] == G_DIR_SEPARATOR) && (l_len > 1)) { l_dir[l_len -1] = '\0'; } return(l_dir); } gchar * gap_lib_get_video_paste_name(void) { gchar *l_dir; gchar *l_basename; gchar *l_video_name; l_dir = p_get_video_paste_dir(); l_basename = p_get_video_paste_basename(); l_video_name = g_strdup_printf("%s%s%s", l_dir, G_DIR_SEPARATOR_S, l_basename); g_free(l_dir); g_free(l_basename); if(gap_debug) printf("gap_lib_get_video_paste_name: %s\n", l_video_name); return(l_video_name); } static gint32 p_clear_or_count_video_paste(gint delete_flag) { gchar *l_dir; gchar *l_basename; gchar *l_filename; gint l_len; gint32 l_framecount; GDir *l_dirp; const char *l_entry; l_dir = p_get_video_paste_dir(); l_dirp = g_dir_open(l_dir, 0, NULL); l_framecount = 0; if(!l_dirp) { printf("ERROR gap_vid_edit_clear: can't read directory %s\n", l_dir); l_framecount = -1; } else { l_basename = p_get_video_paste_basename(); l_len = strlen(l_basename); while ( (l_entry = g_dir_read_name( l_dirp )) != NULL ) { if(strncmp(l_basename, l_entry, l_len) == 0) { l_filename = g_strdup_printf("%s%s%s", l_dir, G_DIR_SEPARATOR_S, l_entry); if(1 == gap_lib_file_exists(l_filename)) /* check for regular file */ { /* delete all files in the video paste directory * with names matching the basename part */ l_framecount++; if(delete_flag) { if(gap_debug) printf("gap_vid_edit_clear: remove file %s\n", l_filename); g_remove(l_filename); /* also delete thumbnail */ gap_thumb_file_delete_thumbnail(l_filename); } } g_free(l_filename); } } g_dir_close( l_dirp ); g_free(l_basename); } g_free(l_dir); return(l_framecount); } gint32 gap_vid_edit_clear(void) { return(p_clear_or_count_video_paste(TRUE)); /* delete frames */ } gint32 gap_vid_edit_framecount() { return (p_clear_or_count_video_paste(FALSE)); /* delete_flag is off, just count frames */ } /* ============================================================================ * gap_vid_edit_copy * ============================================================================ * copy frames to the vid paste directory * (always using 6 digit framenumbers in the vid paste dir) */ gint gap_vid_edit_copy(GimpRunMode run_mode, gint32 image_id, long range_from, long range_to) { int rc; GapAnimInfo *ainfo_ptr; gchar *l_curr_name; gchar *l_fname ; gchar *l_fname_copy; gchar *l_basename; gint32 l_frame_nr; gint32 l_cnt_range; gint32 l_cnt2; gint32 l_idx; gint32 l_tmp_image_id; ainfo_ptr = gap_lib_alloc_ainfo(image_id, run_mode); if(ainfo_ptr == NULL) { return (-1); } rc = 0; if((ainfo_ptr->curr_frame_nr >= MIN(range_to, range_from)) && (ainfo_ptr->curr_frame_nr <= MAX(range_to, range_from))) { /* current frame is in the affected range * so we have to save current frame to file */ l_curr_name = gap_lib_alloc_fname(ainfo_ptr->basename, ainfo_ptr->curr_frame_nr, ainfo_ptr->extension); gap_lib_save_named_frame(ainfo_ptr->image_id, l_curr_name); g_free(l_curr_name); } l_basename = gap_lib_get_video_paste_name(); l_cnt2 = gap_vid_edit_framecount(); /* count frames in the video paste buffer */ l_frame_nr = 1 + l_cnt2; /* start at one, or continue (append) at end +1 */ l_cnt_range = 1 + MAX(range_to, range_from) - MIN(range_to, range_from); for(l_idx = 0; l_idx < l_cnt_range; l_idx++) { if(rc < 0) { break; } l_fname = gap_lib_alloc_fname(ainfo_ptr->basename, MIN(range_to, range_from) + l_idx, ainfo_ptr->extension); l_fname_copy = g_strdup_printf("%s%06ld.xcf", l_basename, (long)l_frame_nr); if(strcmp(ainfo_ptr->extension, ".xcf") == 0) { rc = gap_lib_image_file_copy(l_fname, l_fname_copy); } else { /* convert other fileformats to xcf before saving to video paste buffer */ l_tmp_image_id = gap_lib_load_image(l_fname); rc = gap_lib_save_named_frame(l_tmp_image_id, l_fname_copy); gimp_image_delete(l_tmp_image_id); } g_free(l_fname); g_free(l_fname_copy); l_frame_nr++; } gap_lib_free_ainfo(&ainfo_ptr); return(rc); } /* end gap_vid_edit_copy */ /* ============================================================================ * p_custom_palette_file * write a gimp palette file * ============================================================================ */ static gint p_custom_palette_file(char *filename, guchar *rgb, gint count) { FILE *l_fp; l_fp= g_fopen(filename, "w"); if (l_fp == NULL) { return -1; } fprintf(l_fp, "GIMP Palette\n"); fprintf(l_fp, "# this file will be overwritten each time when video frames are converted to INDEXED\n"); while (count > 0) { fprintf(l_fp, "%d %d %d\tUnknown\n", rgb[0], rgb[1], rgb[2]); rgb+= 3; --count; } fclose (l_fp); return 0; } /* end p_custom_palette_file */ /* ============================================================================ * gap_vid_edit_paste * * return image_id (of the new loaded current frame) on success * or -1 on errors * ============================================================================ * copy frames from the vid paste directory * (always using 6 digit framenumbers in the vid paste dir) */ gint32 gap_vid_edit_paste(GimpRunMode run_mode, gint32 image_id, long paste_mode) { #define CUSTOM_PALETTE_NAME "gap_cmap.gpl" gint32 rc; GapAnimInfo *ainfo_ptr; gchar *l_curr_name; gchar *l_fname ; gchar *l_fname_copy; gchar *l_basename; gint32 l_frame_nr; gint32 l_dst_frame_nr; gint32 l_cnt2; gint32 l_lo, l_hi; gint32 l_insert_frame_nr; gint32 l_tmp_image_id; gint l_rc; GimpImageBaseType l_orig_basetype; l_cnt2 = gap_vid_edit_framecount(); if(gap_debug) { printf("gap_vid_edit_paste: paste_mode %d found %d frames to paste, image_id: %d\n" , (int)paste_mode , (int)l_cnt2 , (int)image_id ); } if (l_cnt2 < 1) { return(0); /* video paste buffer is empty */ } ainfo_ptr = gap_lib_alloc_ainfo(image_id, run_mode); if(ainfo_ptr == NULL) { return (-1); } if (0 != gap_lib_dir_ainfo(ainfo_ptr)) { return (-1); } if(gap_debug) { printf("gap_vid_edit_paste: ainfo: basename: %s, extension:%s curr:%d first:%d last: %d\n" , ainfo_ptr->basename , ainfo_ptr->extension , (int) ainfo_ptr->curr_frame_nr , (int) ainfo_ptr->first_frame_nr , (int) ainfo_ptr->last_frame_nr ); } rc = 0; l_insert_frame_nr = ainfo_ptr->curr_frame_nr; if(paste_mode != GAP_VID_PASTE_INSERT_AFTER) { /* we have to save current frame to file */ l_curr_name = gap_lib_alloc_fname(ainfo_ptr->basename, ainfo_ptr->curr_frame_nr, ainfo_ptr->extension); gap_lib_save_named_frame(ainfo_ptr->image_id, l_curr_name); g_free(l_curr_name); } if(paste_mode != GAP_VID_PASTE_REPLACE) { if(paste_mode == GAP_VID_PASTE_INSERT_AFTER) { l_insert_frame_nr = ainfo_ptr->curr_frame_nr +1; } /* rename (renumber) all frames with number greater (or greater equal) than current */ l_lo = ainfo_ptr->last_frame_nr; l_hi = l_lo + l_cnt2; if(gap_debug) { printf("gap_vid_edit_paste: l_insert_frame_nr %d l_lo:%d l_hi:%d\n" , (int)l_insert_frame_nr, (int)l_lo, (int)l_hi); } while(l_lo >= l_insert_frame_nr) { if(0 != gap_lib_rename_frame(ainfo_ptr, l_lo, l_hi)) { gchar *tmp_errtxt; tmp_errtxt = g_strdup_printf(_("Error: could not rename frame %ld to %ld"), (long int)l_lo, (long int)l_hi); gap_arr_msg_win(ainfo_ptr->run_mode, tmp_errtxt); g_free(tmp_errtxt); return -1; } l_lo--; l_hi--; } } l_basename = gap_lib_get_video_paste_name(); l_dst_frame_nr = l_insert_frame_nr; for(l_frame_nr = 1; l_frame_nr <= l_cnt2; l_frame_nr++) { l_fname = gap_lib_alloc_fname(ainfo_ptr->basename, l_dst_frame_nr, ainfo_ptr->extension); l_fname_copy = g_strdup_printf("%s%06ld.xcf", l_basename, (long)l_frame_nr); l_tmp_image_id = gap_lib_load_image(l_fname_copy); /* delete onionskin layers (if there are any) before paste */ gap_onion_base_onionskin_delete(l_tmp_image_id); /* check size and resize if needed */ if((gimp_image_width(l_tmp_image_id) != gimp_image_width(image_id)) || (gimp_image_height(l_tmp_image_id) != gimp_image_height(image_id))) { gint32 l_size_x, l_size_y; l_size_x = gimp_image_width(image_id); l_size_y = gimp_image_height(image_id); if(gap_debug) printf("DEBUG: scale to size %d %d\n", (int)l_size_x, (int)l_size_y); gimp_image_scale(l_tmp_image_id, l_size_x, l_size_y); } /* check basetype and convert if needed */ l_orig_basetype = gimp_image_base_type(image_id); if(gimp_image_base_type(l_tmp_image_id) != l_orig_basetype) { switch(l_orig_basetype) { gchar *l_palette_filename; guchar *l_cmap; gint l_ncolors; /* convert tmp image to dest type */ case GIMP_INDEXED: l_cmap = gimp_image_get_colormap(image_id, &l_ncolors); if(gap_debug) printf("DEBUG: convert to INDEXED %d colors\n", (int)l_ncolors); l_palette_filename = g_strdup_printf("%s%spalettes%s%s" , gimp_directory() , G_DIR_SEPARATOR_S , G_DIR_SEPARATOR_S , CUSTOM_PALETTE_NAME); l_rc = p_custom_palette_file(l_palette_filename, l_cmap, l_ncolors); if(l_rc == 0) { gimp_palettes_refresh(); gimp_image_convert_indexed(l_tmp_image_id, GIMP_FS_DITHER, /* dither floyd-steinberg */ GIMP_CUSTOM_PALETTE, l_ncolors, /* number of colors */ FALSE, /* No alpha_dither */ FALSE, /* dont remove_unused */ CUSTOM_PALETTE_NAME ); } else { printf("ERROR: gap_vid_edit_paste: could not save custom palette %s\n", l_palette_filename); } g_free(l_cmap); g_free(l_palette_filename); break; case GIMP_GRAY: if(gap_debug) printf("DEBUG: convert to GRAY'\n"); gimp_image_convert_grayscale(l_tmp_image_id); break; case GIMP_RGB: if(gap_debug) printf("DEBUG: convert to RGB'\n"); gimp_image_convert_rgb(l_tmp_image_id); break; default: printf( "DEBUG: unknown image type\n"); return -1; break; } } if(gap_debug) printf("DEBUG: before gap_lib_save_named_frame l_fname:%s l_tmp_image_id:%d'\n" , l_fname , (int) l_tmp_image_id); gimp_image_set_filename (l_tmp_image_id, l_fname); rc = gap_lib_save_named_frame(l_tmp_image_id, l_fname); gimp_image_delete(l_tmp_image_id); g_free(l_fname); g_free(l_fname_copy); l_dst_frame_nr++; } if(paste_mode == GAP_VID_PASTE_INSERT_AFTER) { /* we pasted successful after the current image, * keep the calling image_id as active image_id return value */ if(rc >= 0) { rc = image_id; } } else { if(rc >= 0) { /* load from the "new" current frame */ if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename); ainfo_ptr->new_filename = gap_lib_alloc_fname(ainfo_ptr->basename, ainfo_ptr->curr_frame_nr, ainfo_ptr->extension); if(gap_debug) printf("gap_vid_edit_paste: before load: %s basename: %s, extension:%s curr:%d first:%d last: %d\n" , ainfo_ptr->new_filename , ainfo_ptr->basename , ainfo_ptr->extension , (int) ainfo_ptr->curr_frame_nr , (int) ainfo_ptr->first_frame_nr , (int) ainfo_ptr->last_frame_nr ); rc = gap_lib_load_named_frame(ainfo_ptr->image_id, ainfo_ptr->new_filename); } } if(rc < 0) { rc = -1; } if(gap_debug) printf("gap_vid_edit_paste: rc: %d\n", (int)rc); gap_lib_free_ainfo(&ainfo_ptr); return(rc); } /* end gap_vid_edit_paste */ gimp-gap-2.6.0+dfsg.orig/gap/gap_vin.c0000644000175000017500000002441311212030253017307 0ustar thibautthibaut/* gap_vin.c * * This module handles GAP video info files (_vin.gap) * _vin.gap files store global informations about an animation */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 2.1.0a; 2004/06/03 hof: added onionskin setting ref_mode * version 1.3.25b; 2004/01/23 hof: bugfix: gap_val_load_textfile set correct line_nr * version 1.3.18b; 2003/08/23 hof: gap_vin_get_all: force timezoom value >= 1 (0 results in divison by zero) * version 1.3.18a; 2003/08/23 hof: bugfix: gap_vin_get_all must clear (g_malloc0) vin_ptr struct at creation * version 1.3.16c; 2003/07/12 hof: support onionskin settings in video_info files * key/value/datatype is now managed by GapValKeyList * version 1.3.14b; 2003/06/03 hof: using setlocale independent float conversion procedures * g_ascii_strtod() and g_ascii_dtostr() * version 1.3.14a; 2003/05/24 hof: created (splitted off from gap_pdb_calls module) * write now keeps unkown keyword lines in _vin.gap files */ #include #include #include #include /* GIMP includes */ #include "libgimp/gimp.h" /* GAP includes */ #include "gap_val_file.h" #include "gap_vin.h" extern int gap_debug; /* -------------------------- * p_set_master_keywords * -------------------------- */ static void p_set_master_keywords(GapValKeyList *keylist, GapVinVideoInfo *vin_ptr) { gap_val_set_keyword(keylist, "(framerate ", &vin_ptr->framerate, GAP_VAL_GDOUBLE, 0, "# 1.0 upto 100.0 frames per sec"); gap_val_set_keyword(keylist, "(timezoom ", &vin_ptr->timezoom, GAP_VAL_GINT32, 0, "# 1 upto 100 frames"); gap_val_set_keyword(keylist, "(active_layer_tracking ", &vin_ptr->active_layer_tracking, GAP_VAL_GINT32, 0, "# 0:OFF 1 by name 2 by stackpos"); } /* end p_set_master_keywords */ /* -------------------------- * p_set_onion_keywords * -------------------------- */ static void p_set_onion_keywords(GapValKeyList *keylist, GapVinVideoInfo *vin_ptr) { gap_val_set_keyword(keylist, "(onion_auto_enable ", &vin_ptr->onionskin_auto_enable, GAP_VAL_GBOOLEAN, 0, "\0"); gap_val_set_keyword(keylist, "(onion_auto_replace_after_load ", &vin_ptr->auto_replace_after_load, GAP_VAL_GBOOLEAN, 0, "\0"); gap_val_set_keyword(keylist, "(onion_auto_delete_before_save ", &vin_ptr->auto_delete_before_save, GAP_VAL_GBOOLEAN, 0, "\0"); gap_val_set_keyword(keylist, "(onion_number_of_layers ", &vin_ptr->num_olayers, GAP_VAL_GINT32, 0, "\0"); gap_val_set_keyword(keylist, "(onion_ref_mode ", &vin_ptr->ref_mode, GAP_VAL_GINT32, 0, "\0"); gap_val_set_keyword(keylist, "(onion_ref_delta ", &vin_ptr->ref_delta, GAP_VAL_GINT32, 0, "\0"); gap_val_set_keyword(keylist, "(onion_ref_cycle ", &vin_ptr->ref_cycle, GAP_VAL_GBOOLEAN, 0, "\0"); gap_val_set_keyword(keylist, "(onion_stack_pos ", &vin_ptr->stack_pos, GAP_VAL_GINT32, 0, "\0"); gap_val_set_keyword(keylist, "(onion_stack_top ", &vin_ptr->stack_top, GAP_VAL_GBOOLEAN, 0, "\0"); gap_val_set_keyword(keylist, "(onion_opacity_initial ", &vin_ptr->opacity, GAP_VAL_GDOUBLE, 0, "\0"); gap_val_set_keyword(keylist, "(onion_opacity_delta ", &vin_ptr->opacity_delta, GAP_VAL_GDOUBLE, 0, "\0"); gap_val_set_keyword(keylist, "(onion_ignore_botlayers ", &vin_ptr->ignore_botlayers, GAP_VAL_GINT32, 0, "\0"); gap_val_set_keyword(keylist, "(onion_select_mode ", &vin_ptr->select_mode, GAP_VAL_GINT32, 0, "\0"); gap_val_set_keyword(keylist, "(onion_select_casesensitive ", &vin_ptr->select_case, GAP_VAL_GBOOLEAN, 0, "\0"); gap_val_set_keyword(keylist, "(onion_select_invert ", &vin_ptr->select_invert, GAP_VAL_GBOOLEAN, 0, "\0"); gap_val_set_keyword(keylist, "(onion_select_string ", &vin_ptr->select_string[0], GAP_VAL_STRING, sizeof(vin_ptr->select_string), "\0"); gap_val_set_keyword(keylist, "(onion_ascending_opacity ", &vin_ptr->asc_opacity, GAP_VAL_GBOOLEAN, 0, "\0"); } /* end p_set_onion_keywords */ /* -------------------------- * gap_vin_alloc_name * -------------------------- * to get the name of the the video_info_file * (the caller should g_free the returned name after use) */ char * gap_vin_alloc_name(char *basename) { char *l_str; if(basename == NULL) { return(NULL); } l_str = g_strdup_printf("%svin.gap", basename); return(l_str); } /* end gap_vin_alloc_name */ /* -------------------------- * gap_vin_set_common_keylist * -------------------------- * (re)write the current video info to .vin file * only the values for the keywords in the passed keylist * are created (or replaced) in the file. * all other lines are left unchanged. * if the file is empty a header is added. */ static int gap_vin_set_common_keylist(GapValKeyList *keylist, GapVinVideoInfo *vin_ptr, char *basename) { char *l_vin_filename; int l_rc; l_rc = -1; l_vin_filename = gap_vin_alloc_name(basename); if(l_vin_filename) { l_rc = gap_val_rewrite_file(keylist ,l_vin_filename ,"# GIMP / GAP Videoinfo file" /* hdr_text */ ,")" /* terminate char */ ); g_free(l_vin_filename); } return(l_rc); } /* end gap_vin_set_common_keylist */ /* -------------------------- * gap_vin_get_all_keylist * -------------------------- * get video info from .vin file */ static void gap_vin_get_all_keylist(GapValKeyList *keylist, GapVinVideoInfo *vin_ptr, char *basename) { char *l_vin_filename; GapValTextFileLines *txf_ptr_root; GapVinVideoInfo *l_vin_ptr; l_vin_ptr = g_malloc(sizeof(GapVinVideoInfo)); /* init wit defaults (for the case where no video_info file available) */ l_vin_ptr->timezoom = 1; l_vin_ptr->framerate = 24.0; l_vin_ptr->active_layer_tracking = GAP_ACTIVE_LAYER_TRACKING_OFF; l_vin_ptr->onionskin_auto_enable = TRUE; l_vin_ptr->auto_replace_after_load = FALSE; l_vin_ptr->auto_delete_before_save = FALSE; l_vin_ptr->num_olayers = 2; l_vin_ptr->ref_delta = -1; l_vin_ptr->ref_cycle = FALSE; l_vin_ptr->stack_pos = 1; l_vin_ptr->stack_top = FALSE; l_vin_ptr->asc_opacity = FALSE; l_vin_ptr->opacity = 80.0; l_vin_ptr->opacity_delta = 80.0; l_vin_ptr->ignore_botlayers = 1; l_vin_ptr->select_mode = 6; /* GAP_MTCH_ALL_VISIBLE */ l_vin_ptr->select_case = 0; /* 0 .. ignore case, 1..case sensitve */ l_vin_ptr->select_invert = 0; /* 0 .. no invert, 1 ..invert */ l_vin_ptr->select_string[0] = '\0'; l_vin_filename = gap_vin_alloc_name(basename); if(l_vin_filename) { gap_val_scann_filevalues(keylist, l_vin_filename); txf_ptr_root = gap_val_load_textfile(l_vin_filename); g_free(l_vin_filename); } } /* end gap_vin_get_all_keylist */ /* -------------------------- * gap_vin_get_all * -------------------------- * get video info from .vin file * get does always fetch all values for all known keywords */ GapVinVideoInfo * gap_vin_get_all(char *basename) { GapVinVideoInfo *vin_ptr; GapValKeyList *keylist; keylist = gap_val_new_keylist(); vin_ptr = g_new0 (GapVinVideoInfo, 1); vin_ptr->timezoom = 1; p_set_master_keywords(keylist, vin_ptr); p_set_onion_keywords(keylist, vin_ptr); gap_vin_get_all_keylist(keylist, vin_ptr, basename); vin_ptr->timezoom = MAX(1,vin_ptr->timezoom); gap_val_free_keylist(keylist); if(gap_debug) { printf("gap_vin_get_all: RETURN with vin_ptr content:\n"); printf(" num_olayers: %d\n", (int)vin_ptr->num_olayers); printf(" ref_delta: %d\n", (int)vin_ptr->ref_delta); printf(" ref_cycle: %d\n", (int)vin_ptr->ref_cycle); printf(" stack_pos: %d\n", (int)vin_ptr->stack_pos); printf(" stack_top: %d\n", (int)vin_ptr->stack_top); printf(" opacity: %f\n", (float)vin_ptr->opacity); printf(" opacity_delta: %f\n", (float)vin_ptr->opacity_delta); printf(" ignore_botlayers: %d\n", (int)vin_ptr->ignore_botlayers); printf(" asc_opacity: %d\n", (int)vin_ptr->asc_opacity); printf(" onionskin_auto_enable: %d\n", (int)vin_ptr->onionskin_auto_enable); printf(" auto_replace_after_load: %d\n", (int)vin_ptr->auto_replace_after_load); printf(" auto_delete_before_save: %d\n", (int)vin_ptr->auto_delete_before_save); } return(vin_ptr); } /* end gap_vin_get_all */ /* -------------------------- * gap_vin_set_common * -------------------------- * (re)write the current video info file (_vin.gap file) * IMPORTANT: this Procedure affects only * the master values for framerate and timezoom. * (other settings like the onionskin specific Settings. * are left unchanged) */ int gap_vin_set_common(GapVinVideoInfo *vin_ptr, char *basename) { GapValKeyList *keylist; int l_rc; keylist = gap_val_new_keylist(); p_set_master_keywords(keylist, vin_ptr); l_rc = gap_vin_set_common_keylist(keylist, vin_ptr, basename); gap_val_free_keylist(keylist); return(l_rc); } /* end gap_vin_set_common */ /* -------------------------- * gap_vin_set_common_onion * -------------------------- * (re)write the onionskin specific values * to the video info file */ int gap_vin_set_common_onion(GapVinVideoInfo *vin_ptr, char *basename) { GapValKeyList *keylist; int l_rc; keylist = gap_val_new_keylist(); p_set_onion_keywords(keylist, vin_ptr); l_rc = gap_vin_set_common_keylist(keylist, vin_ptr, basename); gap_val_free_keylist(keylist); return(l_rc); } /* end gap_vin_set_common_onion */ gimp-gap-2.6.0+dfsg.orig/gap/gap_dbbrowser_utils.c0000644000175000017500000010014311212030253021717 0ustar thibautthibaut/* * gap_dbbrowser_utils.c (most parts of the code are copied from * GIMP DB-Browser Code by Thomas NOEL */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 2.1.0b; 2004/11/12 hof: use same renderprocedures as official DBBROWSER plug-in * (copied render code from: * gimp-2.1.7/plug-ins/dbbrowser/gimpprocbrowser.c) * gimp 2.1.0b; 2004/11/11 hof: added help button (gap_db_browser_dialog added help_id param) * gimp 1.3.20b; 2003/09/20 hof: gap_db_browser_dialog and constraint procedures added new param image_id * DEBUG MODE: made iterator code generation working again. * gimp 1.3.20a; 2003/09/14 hof: merged in changes of the file * gimp-1.3.20/plug-ins/dbbrowser/dbbrowser_utils.c * now uses GtkTreeView and gtk+2.2 compatible coding * added menu path and Search by Menu Path Button * 27. jan .1999 hof: update for GIMP 1.1.1 (show help) * 09. dec .1998 hof: update for GIMP 1.1 * 12. jan .1998 hof: added "Gen Code" button * * 23. dec .1997 hof: created GAP specific variant of DBbrowser * removed apply_callback * added constraint_procedure, * added 2 buttons * added return type */ #include "config.h" #include #include #include #include /* GAP includes */ #include "gap_filter.h" #include "gap_match.h" #include "gap_pdb_calls.h" #include "gap_dbbrowser_utils.h" #include "gap-intl.h" #define DBL_LIST_WIDTH 220 #define DBL_WIDTH (DBL_LIST_WIDTH + 500) #define DBL_HEIGHT 250 extern int gap_debug; typedef struct { GtkWidget *dialog; GtkWidget *search_entry; GtkWidget *name_button; GtkWidget *blurb_button; GtkWidget *descr_vbox; GtkWidget *description; GtkListStore *store; GtkWidget *tv; GtkTreeSelection *sel; /* the currently selected procedure */ gchar *selected_proc_name; gchar *selected_scheme_proc_name; gchar *selected_proc_blurb; gchar *selected_proc_help; gchar *selected_proc_author; gchar *selected_proc_copyright; gchar *selected_proc_date; GimpPDBProcType selected_proc_type; gint selected_nparams; gint selected_nreturn_vals; GimpParamDef *selected_params; GimpParamDef *selected_return_vals; /* GAP DB-Browser specific items */ gchar *selected_menu_path; GtkWidget* app_const_button; GtkWidget* app_vary_button; GtkWidget* menupath_button; t_constraint_func constraint_func; t_constraint_func constraint_func_sel1; t_constraint_func constraint_func_sel2; GapDbBrowserResult *result; gint codegen_flag; gint32 current_image_id; const char *help_id; } dbbrowser_t; /* local functions */ static const gchar * GParamType_to_string (GimpPDBArgType type); static const gchar * GimpPDBProcType_to_string (GimpPDBProcType type); static void procedure_select_callback (GtkTreeSelection *sel, dbbrowser_t *dbbrowser); static void dialog_search_callback (GtkWidget *widget, dbbrowser_t *dbbrowser); static void dialog_select (dbbrowser_t *dbbrowser, gchar *proc_name); static void dialog_close_callback (GtkWidget *widget, dbbrowser_t *dbbrowser); static void dialog_help_callback (GtkWidget *widget, dbbrowser_t *dbbrowser); static void convert_string (gchar *str); /* GAP specific extra callbacks */ static void dialog_num_button_callback (dbbrowser_t* dbbrowser, gint button_nr); static void dialog_button_1_callback (GtkWidget *widget, dbbrowser_t* dbbrowser); static void dialog_button_2_callback (GtkWidget *widget, dbbrowser_t* dbbrowser); static void dialog_button_3_callback (GtkWidget *widget, dbbrowser_t* dbbrowser); static void p_create_action_area_buttons (dbbrowser_t *dbbrowser, char *button_1_txt, char *button_2_txt, const char *help_id ); /* create and perform the dialog */ int gap_db_browser_dialog(char *title_txt, char *button_1_txt, char *button_2_txt, t_constraint_func constraint_func, t_constraint_func constraint_func_sel1, t_constraint_func constraint_func_sel2, GapDbBrowserResult *result, gint32 image_id, const char *help_id) { dbbrowser_t *dbbrowser; GtkWidget *hpaned; GtkWidget *searchhbox; GtkWidget *vbox; GtkWidget *label; GtkWidget *scrolled_window; GtkCellRenderer *renderer; gimp_ui_init ("gap-animated-filter-apply", FALSE); dbbrowser = g_new0 (dbbrowser_t, 1); /* store pointers to gap constraint procedures */ dbbrowser->constraint_func = constraint_func; dbbrowser->constraint_func_sel1 = constraint_func_sel1; dbbrowser->constraint_func_sel2 = constraint_func_sel2; dbbrowser->result = result; dbbrowser->codegen_flag = 0; /* default: no code generation */ dbbrowser->current_image_id = image_id; /* the dialog box */ dbbrowser->dialog = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (dbbrowser->dialog), title_txt); gtk_window_set_position (GTK_WINDOW (dbbrowser->dialog), GTK_WIN_POS_MOUSE); g_signal_connect (dbbrowser->dialog, "destroy", G_CALLBACK (dialog_close_callback), dbbrowser); /* hpaned : left=list ; right=description */ hpaned = gtk_hpaned_new (); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dbbrowser->dialog)->vbox), hpaned, TRUE, TRUE, 0); gtk_widget_show (hpaned); /* left = vbox : the list and the search entry */ vbox = gtk_vbox_new (FALSE, 4); gtk_paned_pack1 (GTK_PANED (hpaned), vbox, FALSE, TRUE); gtk_widget_show (vbox); /* list : list in a scrolled_win */ scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0); gtk_widget_show (scrolled_window); dbbrowser->tv = gtk_tree_view_new (); renderer = gtk_cell_renderer_text_new (); gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (dbbrowser->tv), -1, NULL, renderer, "text", 0, NULL); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dbbrowser->tv), FALSE); gtk_widget_set_size_request (dbbrowser->tv, DBL_LIST_WIDTH, DBL_HEIGHT); gtk_container_add (GTK_CONTAINER (scrolled_window), dbbrowser->tv); gtk_widget_show (dbbrowser->tv); dbbrowser->sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (dbbrowser->tv)); g_signal_connect (dbbrowser->sel, "changed", G_CALLBACK (procedure_select_callback), dbbrowser); /* search entry */ searchhbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), searchhbox, FALSE, FALSE, 2); gtk_widget_show (searchhbox); label = gtk_label_new_with_mnemonic (_("_Search:")); gtk_box_pack_start (GTK_BOX (searchhbox), label, FALSE, FALSE, 2); gtk_widget_show (label); dbbrowser->search_entry = gtk_entry_new (); gtk_entry_set_activates_default (GTK_ENTRY (dbbrowser->search_entry), TRUE); gtk_box_pack_start (GTK_BOX (searchhbox), dbbrowser->search_entry, TRUE, TRUE, 0); gtk_widget_show (dbbrowser->search_entry); gtk_label_set_mnemonic_widget (GTK_LABEL (label), dbbrowser->search_entry); /* right = description */ scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_widget_set_size_request (scrolled_window, DBL_WIDTH - DBL_LIST_WIDTH, -1); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_paned_pack2 (GTK_PANED (hpaned), scrolled_window, TRUE, TRUE); gtk_widget_show (scrolled_window); dbbrowser->descr_vbox = gtk_vbox_new (FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (dbbrowser->descr_vbox), 4); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), dbbrowser->descr_vbox); gtk_widget_show (dbbrowser->descr_vbox); /* GAP specific buttons in dialog->action_aera */ p_create_action_area_buttons(dbbrowser, button_1_txt, button_2_txt, help_id); /* now build the list */ gtk_widget_show (dbbrowser->dialog); /* initialize the "return" value (for "apply") */ dbbrowser->description = NULL; dbbrowser->selected_proc_name = NULL; dbbrowser->selected_scheme_proc_name = NULL; dbbrowser->selected_proc_blurb = NULL; dbbrowser->selected_proc_help = NULL; dbbrowser->selected_proc_author = NULL; dbbrowser->selected_proc_copyright = NULL; dbbrowser->selected_proc_date = NULL; dbbrowser->selected_proc_type = 0; dbbrowser->selected_nparams = 0; dbbrowser->selected_nreturn_vals = 0; dbbrowser->selected_params = NULL; dbbrowser->selected_return_vals = NULL; dbbrowser->selected_menu_path = NULL; dbbrowser->result->selected_proc_name[0] = '\0'; dbbrowser->result->button_nr = -1; /* first search (all procedures) */ dialog_search_callback (NULL, dbbrowser); /* GTK Main Loop */ gtk_main (); gdk_flush (); return (dbbrowser->result->button_nr); } /* end gap_db_browser_dialog */ static void p_create_action_area_buttons(dbbrowser_t *dbbrowser, char *button_1_txt, char *button_2_txt, const char *help_id ) { GtkWidget *table; GtkWidget *button; gint row; gint cof; cof = 2; /* 5 cols, 3rows */ table = gtk_table_new(1,1,TRUE); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_table_set_row_spacing (GTK_TABLE (table), 0, 4); row = 0; /* Button GenCode (conditional in DEBUG mode only for developers) */ if (gap_debug) { button = gtk_button_new_with_label ( _("Gen Code by name")); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (dialog_button_3_callback), dbbrowser ); gtk_table_attach (GTK_TABLE (table), button, cof, cof+1, row, row + 1, GTK_FILL, 0, 0, 0); gtk_widget_show (button); row++; } /* Button Search by Name */ dbbrowser->name_button = gtk_button_new_with_label ( _("Search by Name")); GTK_WIDGET_SET_FLAGS (dbbrowser->name_button, GTK_CAN_DEFAULT); g_signal_connect (G_OBJECT (dbbrowser->name_button), "clicked", G_CALLBACK (dialog_search_callback), dbbrowser); gtk_table_attach (GTK_TABLE (table), dbbrowser->name_button, cof, cof+1, row, row + 1, GTK_FILL, 0, 0, 0); gtk_widget_show(dbbrowser->name_button); /* Button Search by Blurb */ dbbrowser->blurb_button = gtk_button_new_with_label ( _("Search by Blurb")); GTK_WIDGET_SET_FLAGS (dbbrowser->blurb_button, GTK_CAN_DEFAULT); g_signal_connect (G_OBJECT (dbbrowser->blurb_button), "clicked", G_CALLBACK (dialog_search_callback), dbbrowser); gtk_table_attach (GTK_TABLE (table), dbbrowser->blurb_button, cof+1, cof+2, row, row + 1, GTK_FILL, 0, 0, 0); gtk_widget_show(dbbrowser->blurb_button); /* Button Search by Menupath */ dbbrowser->menupath_button = gtk_button_new_with_label ( _("Search by Menu Path")); GTK_WIDGET_SET_FLAGS (dbbrowser->menupath_button, GTK_CAN_DEFAULT); g_signal_connect (G_OBJECT (dbbrowser->menupath_button), "clicked", G_CALLBACK (dialog_search_callback), dbbrowser); gtk_table_attach (GTK_TABLE (table), dbbrowser->menupath_button, cof+2, cof+3, row, row + 1, GTK_FILL, 0, 0, 0); gtk_widget_show(dbbrowser->menupath_button); row++; /* Button1 (Apply Constant) */ if (button_1_txt) { dbbrowser->app_const_button = gtk_button_new_with_label (button_1_txt); GTK_WIDGET_SET_FLAGS (dbbrowser->app_const_button, GTK_CAN_DEFAULT); g_signal_connect (G_OBJECT (dbbrowser->app_const_button), "clicked", G_CALLBACK (dialog_button_1_callback), dbbrowser ); gtk_table_attach (GTK_TABLE (table), dbbrowser->app_const_button, cof, cof+1, row, row + 1, GTK_FILL, 0, 0, 0); gtk_widget_set_sensitive (dbbrowser->app_const_button, FALSE); gtk_widget_show (dbbrowser->app_const_button); } else dbbrowser->app_const_button = NULL; /* Button1 (Apply Varying) */ if (button_2_txt) { dbbrowser->app_vary_button = gtk_button_new_with_label (button_2_txt); GTK_WIDGET_SET_FLAGS (dbbrowser->app_vary_button, GTK_CAN_DEFAULT); g_signal_connect (G_OBJECT (dbbrowser->app_vary_button), "clicked", G_CALLBACK (dialog_button_2_callback), dbbrowser ); gtk_table_attach (GTK_TABLE (table), dbbrowser->app_vary_button, cof+1, cof+2, row, row + 1, GTK_FILL, 0, 0, 0); gtk_widget_set_sensitive (dbbrowser->app_vary_button, FALSE); gtk_widget_show (dbbrowser->app_vary_button); } else dbbrowser->app_vary_button = NULL; /* Button Cancel */ button = gtk_button_new_from_stock ( GTK_STOCK_CANCEL); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (dialog_close_callback), dbbrowser); gtk_table_attach (GTK_TABLE (table), button, cof+2, cof+3, row, row + 1, GTK_FILL, 0, 0, 0); gtk_widget_show (button); if((help_id) && (dbbrowser) && gimp_show_help_button ()) { /* Button HELP */ button = gtk_button_new_from_stock ( GTK_STOCK_HELP); gtk_widget_show (button); dbbrowser->help_id = help_id; g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (dialog_help_callback), dbbrowser); gtk_table_attach (GTK_TABLE (table), button, 0, 1, row, row + 1, GTK_FILL, 0, 0, 0); } gtk_widget_show (table); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dbbrowser->dialog)->action_area), table, TRUE, TRUE, 0); } /* end p_create_action_area_buttons */ static void procedure_select_callback (GtkTreeSelection *sel, dbbrowser_t *dbbrowser) { GtkTreeIter iter; gchar *func; g_return_if_fail (sel != NULL); g_return_if_fail (dbbrowser != NULL); if (gtk_tree_selection_get_selected (sel, NULL, &iter)) { gtk_tree_model_get (GTK_TREE_MODEL (dbbrowser->store), &iter, 1, &func, -1); dialog_select (dbbrowser, func); if(dbbrowser->app_const_button) { gtk_widget_set_sensitive (dbbrowser->app_const_button, TRUE); } g_free (func); } } /* update the description box (right) */ static void dialog_select (dbbrowser_t *dbbrowser, gchar *proc_name) { GtkWidget *old_description; g_free (dbbrowser->selected_proc_name); dbbrowser->selected_proc_name = g_strdup (proc_name); g_free (dbbrowser->selected_scheme_proc_name); dbbrowser->selected_scheme_proc_name = g_strdup (proc_name); convert_string (dbbrowser->selected_scheme_proc_name); g_free (dbbrowser->selected_proc_blurb); g_free (dbbrowser->selected_proc_help); g_free (dbbrowser->selected_proc_author); g_free (dbbrowser->selected_proc_copyright); g_free (dbbrowser->selected_proc_date); g_free (dbbrowser->selected_params); g_free (dbbrowser->selected_return_vals); g_free (dbbrowser->selected_menu_path); dbbrowser->selected_menu_path = gap_db_get_plugin_menupath(proc_name); if(dbbrowser->selected_menu_path == NULL) dbbrowser->selected_menu_path = g_strdup(_("** not available **")); gimp_procedural_db_proc_info (proc_name, &dbbrowser->selected_proc_blurb, &dbbrowser->selected_proc_help, &dbbrowser->selected_proc_author, &dbbrowser->selected_proc_copyright, &dbbrowser->selected_proc_date, &dbbrowser->selected_proc_type, &dbbrowser->selected_nparams, &dbbrowser->selected_nreturn_vals, &dbbrowser->selected_params, &dbbrowser->selected_return_vals); /* save the "old" table */ old_description = dbbrowser->description; /* render the new description */ dbbrowser->description = gimp_proc_view_new (proc_name, dbbrowser->selected_menu_path, dbbrowser->selected_proc_blurb, dbbrowser->selected_proc_help, dbbrowser->selected_proc_author, dbbrowser->selected_proc_copyright, dbbrowser->selected_proc_date, dbbrowser->selected_proc_type, dbbrowser->selected_nparams, dbbrowser->selected_nreturn_vals, dbbrowser->selected_params, dbbrowser->selected_return_vals); if (old_description) gtk_container_remove (GTK_CONTAINER (dbbrowser->descr_vbox), old_description); gtk_box_pack_start (GTK_BOX (dbbrowser->descr_vbox), dbbrowser->description, FALSE, FALSE, 0); gtk_widget_show (dbbrowser->description); /* call GAP constraint functions to check sensibility for the apply buttons */ if(dbbrowser->app_const_button != NULL) { if(0 != (dbbrowser->constraint_func_sel1)(dbbrowser->selected_proc_name, dbbrowser->current_image_id)) { gtk_widget_set_sensitive (dbbrowser->app_const_button, TRUE); } else { gtk_widget_set_sensitive (dbbrowser->app_const_button, FALSE); } } if(dbbrowser->app_vary_button != NULL) { if(0 != (dbbrowser->constraint_func_sel2)(dbbrowser->selected_proc_name, dbbrowser->current_image_id)) { gtk_widget_set_sensitive (dbbrowser->app_vary_button, TRUE); } else { gtk_widget_set_sensitive (dbbrowser->app_vary_button, FALSE); } } } static void dialog_show_message (dbbrowser_t *dbbrowser, const gchar *message) { if (dbbrowser->description && GTK_IS_LABEL (dbbrowser->description)) { gtk_label_set_text (GTK_LABEL (dbbrowser->description), message); } else { if (dbbrowser->description) gtk_container_remove (GTK_CONTAINER (dbbrowser->descr_vbox), dbbrowser->description); dbbrowser->description = gtk_label_new (message); gtk_box_pack_start (GTK_BOX (dbbrowser->descr_vbox), dbbrowser->description, FALSE, FALSE, 0); gtk_widget_show (dbbrowser->description); } while (gtk_events_pending ()) gtk_main_iteration (); } /* the HELP dialog */ static void dialog_help_callback (GtkWidget *widget, dbbrowser_t *dbbrowser) { if(dbbrowser) { if(dbbrowser->help_id) { gimp_standard_help_func(dbbrowser->help_id, dbbrowser->dialog); } } } /* end of the dialog */ static void dialog_close_callback (GtkWidget *widget, dbbrowser_t *dbbrowser) { GtkWidget *dlg; if(dbbrowser) { dlg = dbbrowser->dialog; dbbrowser->dialog = NULL; if(dlg) { gtk_widget_destroy (GTK_WIDGET (dlg)); /* close & destroy dialog window */ gtk_main_quit (); } } else { gtk_main_quit (); } } /* GAP dialog_num_button_callback (end of the dialog) */ static void dialog_num_button_callback (dbbrowser_t* dbbrowser, gint button_nr) { if (dbbrowser->selected_proc_name==NULL) { return; } strcpy(dbbrowser->result->selected_proc_name, dbbrowser->selected_proc_name); dbbrowser->result->button_nr = button_nr; gtk_widget_hide(dbbrowser->dialog); dialog_close_callback(NULL, dbbrowser); } /* end dialog_num_button_callback */ /* GAP APPLY const callback */ static void dialog_button_1_callback (GtkWidget *widget, dbbrowser_t* dbbrowser) { dialog_num_button_callback(dbbrowser, 0); } /* GAP APPLY varying callback */ static void dialog_button_2_callback (GtkWidget *widget, dbbrowser_t* dbbrowser) { dialog_num_button_callback(dbbrowser, 1); } /* CODEGEN callback (does not close the dialog) */ static void dialog_button_3_callback (GtkWidget *widget, dbbrowser_t* dbbrowser) { gap_codegen_remove_codegen_files(); /* remove old versions of generated CODE */ dbbrowser->codegen_flag = 1; /* let dialog_search_callback generate */ dialog_search_callback(dbbrowser->name_button, (gpointer)dbbrowser ); dbbrowser->codegen_flag = 0; } /* end dialog_button_3_callback */ /* search in the whole db */ static void dialog_search_callback (GtkWidget *widget, dbbrowser_t *dbbrowser) { gchar **proc_list; gint num_procs; gint i; gint i_added; gchar *label; const gchar *query_text; GString *query; GtkTreeIter iter; const char *pattern; gtk_tree_view_set_model (GTK_TREE_VIEW (dbbrowser->tv), NULL); /* search */ if (widget == dbbrowser->name_button) { dialog_show_message (dbbrowser, _("Searching by name - please wait")); query = g_string_new (""); query_text = gtk_entry_get_text (GTK_ENTRY (dbbrowser->search_entry)); while (*query_text) { if ((*query_text == '_') || (*query_text == '-')) g_string_append (query, "[-_]"); else g_string_append_c (query, *query_text); query_text++; } gimp_procedural_db_query (query->str, ".*", ".*", ".*", ".*", ".*", ".*", &num_procs, &proc_list); g_string_free (query, TRUE); } else if (widget == dbbrowser->blurb_button) { dialog_show_message (dbbrowser, _("Searching by blurb - please wait")); gimp_procedural_db_query (".*", (gchar *) gtk_entry_get_text (GTK_ENTRY (dbbrowser->search_entry)), ".*", ".*", ".*", ".*", ".*", &num_procs, &proc_list); } else { if (widget == dbbrowser->menupath_button) { dialog_show_message (dbbrowser, _("Searching by menupath - please wait")); } else { dialog_show_message (dbbrowser, _("Searching - please wait")); } gimp_procedural_db_query (".*", ".*", ".*", ".*", ".*", ".*", ".*", &num_procs, &proc_list); } dbbrowser->store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); gtk_tree_view_set_model (GTK_TREE_VIEW (dbbrowser->tv), GTK_TREE_MODEL (dbbrowser->store)); g_object_unref (dbbrowser->store); pattern = NULL; query_text = gtk_entry_get_text (GTK_ENTRY (dbbrowser->search_entry)); if (query_text && strlen (query_text)) pattern = query_text; i_added = 0; for (i = 0; i < num_procs; i++) { gboolean pre_selection; pre_selection = FALSE; if (widget == dbbrowser->menupath_button) { gchar *menu_path; menu_path = gap_db_get_plugin_menupath(proc_list[i]); if(menu_path) { if(pattern) { if(gap_match_name(menu_path , pattern , GAP_MTCH_ANYWHERE /* gint32 mode */ , FALSE /* NOT case_sensitive */ )) { pre_selection = TRUE; /* select matching menupath */ } } else { pre_selection = TRUE; /* if we dont have a pattern select all */ } } g_free(menu_path); } else { /* for all other cases than menupath_button * the pre_selection was already done at gimp_procedural_db_query */ pre_selection = TRUE; } if (pre_selection) { /* the filter constraint_function checks if the * PDB-proc has a typical interface to operate on a single drawable. * all other PDB-procedures are not listed in the GAP-dbbrowser */ if (0 != (dbbrowser->constraint_func)((char *)proc_list[i], dbbrowser->current_image_id)) { i_added++; if((dbbrowser->codegen_flag != 0) && (gap_debug)) { gap_codegen_gen_forward_iter_ALT(proc_list[i]); gap_codegen_gen_tab_iter_ALT(proc_list[i]); gap_codegen_gen_code_iter_ALT(proc_list[i]); } label = g_strdup (proc_list[i]); convert_string (label); gtk_list_store_append (dbbrowser->store, &iter); gtk_list_store_set (dbbrowser->store, &iter, 0, label, 1, proc_list[i], -1); g_free (label); } } g_free (proc_list[i]); } g_free (proc_list); /* now sort the store */ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (dbbrowser->store), 0, GTK_SORT_ASCENDING); if (i_added > 0) { gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dbbrowser->store), &iter); gtk_tree_selection_select_iter (dbbrowser->sel, &iter); } else { dialog_show_message (dbbrowser, _("No matches")); } } /* utils ... */ static void convert_string (gchar *str) { while (*str) { if (*str == '_') *str = '-'; str++; } } static const gchar * GParamType_to_string (GimpPDBArgType type) { switch (type) { case GIMP_PDB_INT32: return "INT32"; case GIMP_PDB_INT16: return "INT16"; case GIMP_PDB_INT8: return "INT8"; case GIMP_PDB_FLOAT: return "FLOAT"; case GIMP_PDB_STRING: return "STRING"; case GIMP_PDB_INT32ARRAY: return "INT32ARRAY"; case GIMP_PDB_INT16ARRAY: return "INT16ARRAY"; case GIMP_PDB_INT8ARRAY: return "INT8ARRAY"; case GIMP_PDB_FLOATARRAY: return "FLOATARRAY"; case GIMP_PDB_STRINGARRAY: return "STRINGARRAY"; case GIMP_PDB_COLOR: return "COLOR"; case GIMP_PDB_REGION: return "REGION"; case GIMP_PDB_DISPLAY: return "DISPLAY"; case GIMP_PDB_IMAGE: return "IMAGE"; case GIMP_PDB_LAYER: return "LAYER"; case GIMP_PDB_CHANNEL: return "CHANNEL"; case GIMP_PDB_DRAWABLE: return "DRAWABLE"; case GIMP_PDB_SELECTION: return "SELECTION"; case GIMP_PDB_BOUNDARY: return "BOUNDARY"; case GIMP_PDB_PATH: return "PATH"; case GIMP_PDB_PARASITE: return "PARASITE"; case GIMP_PDB_STATUS: return "STATUS"; case GIMP_PDB_END: return "END"; default: return "UNKNOWN?"; } } static const gchar * GimpPDBProcType_to_string (GimpPDBProcType type) { switch (type) { case GIMP_INTERNAL: return _("Internal GIMP procedure"); case GIMP_PLUGIN: return _("GIMP Plug-In"); case GIMP_EXTENSION: return _("GIMP Extension"); case GIMP_TEMPORARY: return _("Temporary Procedure"); default: return "UNKNOWN"; } } /* search for menupath * return NULL if menupath for plugin name was not found. * return menupath if name was found * the caller should g_free the rturned string. */ gchar* gap_db_get_plugin_menupath (const gchar *search_text) { static GimpParam *return_vals = NULL; static gboolean initialized = FALSE; gint nreturn_vals; gchar **menu_strs; gchar **accel_strs; gchar **prog_strs; gchar **types_strs; gchar **realname_strs; gint *time_ints; gchar *menu_path; menu_path = NULL; if (!initialized) { /* query for all elements (only at 1.st call in this process) * if we apply the search string to gimp_plugins_query * we get no result, because the search will query MenuPath * and not for the realname of the plug-in) */ return_vals = gimp_run_procedure ("gimp_plugins_query", &nreturn_vals, GIMP_PDB_STRING, "", /* search all elements*/ GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { initialized = TRUE; } } if (initialized) { int loop; int num_plugins; num_plugins = return_vals[1].data.d_int32; menu_strs = return_vals[2].data.d_stringarray; accel_strs = return_vals[4].data.d_stringarray; prog_strs = return_vals[6].data.d_stringarray; types_strs = return_vals[8].data.d_stringarray; time_ints = return_vals[10].data.d_int32array; realname_strs = return_vals[12].data.d_stringarray; for (loop = 0; loop < return_vals[1].data.d_int32; loop++) { if(strcmp(search_text, realname_strs[loop]) == 0) { menu_path = g_strdup (menu_strs[loop]); break; /* stop at 1st match */ } } } /* Dont Destroy, but Keep the Returned Parameters for the lifetime of this process */ /* gimp_destroy_params (return_vals, nreturn_vals); */ return (menu_path); } /* end gap_db_get_plugin_menupath */ gimp-gap-2.6.0+dfsg.orig/gap/gap_main.c0000644000175000017500000027547011212030253017452 0ustar thibautthibaut/* gap_main.c * 1997.11.05 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Package * * This Module contains: * - MAIN of the most GAP_Plugins * - query registration of GAP Procedures (Video Menu) in the PDB * - run invoke the selected GAP procedure by its PDB name * * * GAP provides Animation Functions for the gimp, * working on a series of Images stored on disk in gimps .xcf Format. * * Frames are Images with naming convention like this: * Imagename_. * Example: snoopy_000001.xcf, snoopy_000002.xcf, snoopy_000003.xcf * * if gzip is installed on your system you may optional * use gziped xcf frames with extensions ".xcfgz" * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 2.1.0a; 2004/04/05 hof: - Move Path added option to keep the original paintmode of the src_layer * gimp 1.3.24a; 2004/01/17 hof: - get main version from config.h, fixed PDB docs for plug_in_gap_modify * gimp 1.3.23b; 2003/12/06 hof: - updated main version * gimp 1.3.22a; 2003/10/09 hof: - updated main version * gimp 1.3.21a; 2003/10/09 hof: - updated main version * gimp 1.3.20d; 2003/10/09 hof: - bluebox filter for movepath * gimp 1.3.20d; 2003/10/09 hof: - sourcecode cleanup * gimp 1.3.20d; 2003/10/06 hof: - updates for move path extended non-interactive PDB API * gimp 1.3.20c; 2003/09/28 hof: - updates for move path * gimp 1.3.20b; 2003/09/20 hof: - updated main version * gimp 1.3.17b; 2003/07/31 hof: - updated main version, message text fixes for translators (# 118392) * gimp 1.3.17a; 2003/07/29 hof: - updated main version, * - param types GimpPlugInInfo.run procedure * gimp 1.3.16c; 2003/07/09 hof: - updated main version, * gimp 1.3.16b; 2003/07/04 hof: - added frame_density plugin, updated main version, * gimp 1.3.15a; 2003/06/21 hof: - updated main version, * gimp 1.3.14a; 2003/05/27 hof: include gap_base_ops.h * Split Image To frame: added parameter "digits" and "only_visible" * gimp 1.3.12a; 2003/05/03 hof: merge into CVS-gimp-gap project, updated main version, added gap_renumber * gimp 1.3.11a; 2003/01/19 hof: - updated main version, * gimp 1.3.5a; 2002/04/21 hof: - updated main version, * according to the internal use of gimp_reconnect_displays * most gap procedures do return the new image_id on frame changes. * (with the old layer_stealing strategy the image_id did not change) * gimp 1.3.4a; 2002/02/24 hof: - updated main version * gimp 1.1.29b; 2000/11/30 hof: - GAP locks do check (only on UNIX) if locking Process is still alive * - NONINTERACTIVE PDB Interface(s) for MovePath * plug_in_gap_get_animinfo, plug_in_gap_set_framerate * - updated main version, e-mail adress * gimp 1.1.20a; 2000/04/25 hof: NON_INTERACTIVE PDB-Interfaces video_edit_copy/paste/clear * gimp 1.1.14a; 2000/01/01 hof: bugfix params for gap_dup in noninteractive mode * gimp 1.1.13a; 1999/11/26 hof: splitted frontends for external programs (mpeg encoders) * to gap_frontends_main.c * gimp 1.1.11a; 1999/11/15 hof: changed Menunames (AnimFrames to Video, Submenu Encode) * gimp 1.1.10a; 1999/10/22 hof: extended dither options for gap_range_convert * gimp 1.1.8a; 1999/08/31 hof: updated main version * version 0.99.00; 1999/03/17 hof: updated main version * version 0.98.02; 1999/01/27 hof: updated main version * version 0.98.01; 1998/12/21 hof: updated main version, e-mail adress * version 0.98.00; 1998/11/27 hof: updated main version, started port to GIMP 1.1 interfaces * Use no '_' (underscore) in menunames. (has special function in 1.1) * version 0.96.03; 1998/08/31 hof: updated main version, * gap_range_to_multilayer now returns image_id * gap_split_image now returns image_id * version 0.96.02; 1998/08/05 hof: updated main version, * added gap_shift * version 0.96.00; 1998/06/27 hof: added gap animation sizechange plugins * gap_split_image * gap_mpeg_encode * version 0.94.01; 1998/04/28 hof: updated main version, * added flatten_mode to plugin: gap_range_to_multilayer * version 0.94.00; 1998/04/25 hof: updated main version * version 0.93.01; 1998/02/03 hof: * version 0.92.00; hof: set gap_debug from environment * version 0.91.00; 1997/12/22 hof: * version 0.90.00; hof: 1.st (pre) release */ #include "config.h" /* SYTEM (UNIX) includes */ #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" #include "libgimp/gimpui.h" /* GAP includes */ #include "gap_lib.h" #include "gap_base_ops.h" #include "gap_lock.h" #include "gap_match.h" #include "gap_range_ops.h" #include "gap_split.h" #include "gap_mov_exec.h" #include "gap_mod_layer.h" #include "gap_arr_dialog.h" #include "gap_pdb_calls.h" #include "gap_vin.h" #include "gap_image.h" #include "gap-intl.h" /* ------------------------ * global gap DEBUG switch * ------------------------ */ /* int gap_debug = 1; */ /* print debug infos */ /* int gap_debug = 0; */ /* 0: dont print debug infos */ int gap_debug = 0; #define PLUGIN_NAME_GAP_NEXT "plug_in_gap_next" #define PLUGIN_NAME_GAP_PREV "plug_in_gap_prev" #define PLUGIN_NAME_GAP_FIRST "plug_in_gap_first" #define PLUGIN_NAME_GAP_LAST "plug_in_gap_last" #define PLUGIN_NAME_GAP_GOTO "plug_in_gap_goto" #define PLUGIN_NAME_GAP_DEL "plug_in_gap_del" #define PLUGIN_NAME_GAP_DUP "plug_in_gap_dup" #define PLUGIN_NAME_GAP_DENSITY "plug_in_gap_density" #define PLUGIN_NAME_GAP_EXCHG "plug_in_gap_exchg" #define PLUGIN_NAME_GAP_MOVE "plug_in_gap_move" #define PLUGIN_NAME_GAP_MOVE_PATH_EXT "plug_in_gap_move_path_ext" #define PLUGIN_NAME_GAP_MOVE_PATH_EXT2 "plug_in_gap_move_path_ext2" #define PLUGIN_NAME_GAP_RANGE_TO_MULTILAYER "plug_in_gap_range_to_multilayer" #define PLUGIN_NAME_GAP_RANGE_FLATTEN "plug_in_gap_range_flatten" #define PLUGIN_NAME_GAP_RANGE_LAYER_DEL "plug_in_gap_range_layer_del" #define PLUGIN_NAME_GAP_RANGE_CONVERT "plug_in_gap_range_convert" #define PLUGIN_NAME_GAP_RANGE_CONVERT2 "plug_in_gap_range_convert2" #define PLUGIN_NAME_GAP_ANIM_RESIZE "plug_in_gap_anim_resize" #define PLUGIN_NAME_GAP_ANIM_CROP "plug_in_gap_anim_crop" #define PLUGIN_NAME_GAP_ANIM_SCALE "plug_in_gap_anim_scale" #define PLUGIN_NAME_GAP_SPLIT "plug_in_gap_split" #define PLUGIN_NAME_GAP_SHIFT "plug_in_gap_shift" #define PLUGIN_NAME_GAP_REVERSE "plug_in_gap_reverse" #define PLUGIN_NAME_GAP_RENUMBER "plug_in_gap_renumber" #define PLUGIN_NAME_GAP_MODIFY "plug_in_gap_modify" #define PLUGIN_NAME_GAP_VIDEO_EDIT_COPY "plug_in_gap_video_edit_copy" #define PLUGIN_NAME_GAP_VIDEO_EDIT_PASTE "plug_in_gap_video_edit_paste" #define PLUGIN_NAME_GAP_VIDEO_EDIT_CLEAR "plug_in_gap_video_edit_clear" #define PLUGIN_NAME_GAP_GET_ANIMINFO "plug_in_gap_get_animinfo" #define PLUGIN_NAME_GAP_SET_FRAMERATE "plug_in_gap_set_framerate" static void query(void); static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; static GimpParamDef args_std[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (current one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, }; static int nargs_std = G_N_ELEMENTS (args_std); static GimpParamDef return_std[] = { { GIMP_PDB_IMAGE, "curr_frame_image", "the resulting current frame image id" } }; static int nreturn_std = G_N_ELEMENTS(return_std) ; static GimpParamDef *return_nothing = NULL; static int nreturn_nothing = 0; static GimpParamDef args_goto[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (current one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "nr", "frame nr where to go"}, }; static int nargs_goto = G_N_ELEMENTS (args_goto); static GimpParamDef args_del[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (current one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "nr", "number of frames to delete (delete starts at current frame)"}, }; static int nargs_del = G_N_ELEMENTS (args_del); static GimpParamDef args_dup[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (current one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "nr", "how often to copy current frame"}, {GIMP_PDB_INT32, "range_from", "frame nr to start"}, {GIMP_PDB_INT32, "range_to", "frame nr to stop (can be lower than range_from)"}, }; static int nargs_dup = G_N_ELEMENTS (args_dup); static GimpParamDef args_density[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (current one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "range_from", "frame nr to start"}, {GIMP_PDB_INT32, "range_to", "frame nr to stop"}, {GIMP_PDB_FLOAT, "density_factor", "valid value is 1 upto 100 (where 1.0 has no effect)"}, {GIMP_PDB_INT32, "density_grow", "TRUE: number of frames in the sel. range is multiplied by density factor (does duplicate frames), FALSE: nuber is divided by density factor (this does delete frames)"}, }; static int nargs_density = G_N_ELEMENTS (args_density); static GimpParamDef args_exchg[] = { {GIMP_PDB_INT32, "run_mode", "non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (current one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "nr", "nr of frame to exchange with current frame"}, }; static int nargs_exchg = G_N_ELEMENTS (args_exchg); static GimpParamDef args_mov[] = { {GIMP_PDB_INT32, "run_mode", "Interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, }; static GimpParamDef args_mov_path_ext[] = { {GIMP_PDB_INT32, "run_mode", "non-interactive"}, {GIMP_PDB_IMAGE, "dst_image", "Destination image (one of the video frames), where to insert the animated source layers"}, {GIMP_PDB_DRAWABLE, "drawable", "drawable (unused)"}, {GIMP_PDB_INT32, "range_from", "destination frame nr to start"}, {GIMP_PDB_INT32, "range_to", "destination frame nr to stop (can be lower than range_from)"}, {GIMP_PDB_INT32, "nr", "layerstack position where to insert source layer (0 == on top)"}, /* source specs */ { GIMP_PDB_LAYER, "src_layer_id", "starting LayerID of SourceObject. (use any Multilayeranimated Image, or a video frame of anoter Animation)"}, { GIMP_PDB_INT32, "src_stepmode", "0-5 derive inserted object as copy of one layer from a multilayer src_image \n" "100-105 derive inserted object as copy of merged visible layers of a source video frame \n" "0: Layer Loop 1: Layer Loop reverse 2: Layer Once 3: Layer Once reverse 4: Layer PingPong \n" "5: None (use onle the selected src_layer)\n" "100: Frame Loop 101: Frame Loop reverse 102: Frame Once 103: Frame Once reverse 104: Frame PingPong \n" "105: Frame None (use onle the flat copy of the selected frame)\n" }, { GIMP_PDB_INT32, "src_handle", "0: handle left top 1: handle left bottom \n" "2: handle right top 3: handle right bottom \n" "4: handle center"}, { GIMP_PDB_INT32, "src_paintmode", "4444: keep original paintmode of src_layer 0: GIMP_NORMAL_MODE (see GimpLayerModeEffects -- libgimp/gimpenums.h -- for more information)"}, { GIMP_PDB_INT32, "src_force_visible", "1: Set inserted layres visible, 0: insert layers as is"}, { GIMP_PDB_INT32, "clip_to_img", "1: Clip inserted layers to Image size of the destination video frame, 0: dont clip"}, /* extras */ { GIMP_PDB_INT32, "rotation_follow", "0: NO automatic calculation (use the rotation array parameters as it is) \n" "1: Automatic calculation of rotation, following the path vectors, (Ignore rotation array parameters)\n"}, { GIMP_PDB_FLOAT, "startangle", "start angle for the first contolpoint (only used if rotation-follow is on)"}, /* new features of the _ext[ended] API */ {GIMP_PDB_FLOAT, "step_speed_factor", "Allows stepping Source and Destination at different speed. (0.1 upto 50 where 1.0 does step snychron, 2.0 Src makes 2 Steps while Destination makes 1 step) "}, {GIMP_PDB_INT32, "tween_steps", "0 upto 50, Number of virtual Frames to calculate between 2 destination Frames. (use value 0 if no tween processing should be done)"}, {GIMP_PDB_FLOAT, "tween_opacity_initial", "opacity 0.0 upto 100.0 for the tween step that is nearest to the (next) real frame"}, {GIMP_PDB_FLOAT, "tween_opacity_desc", "descending opacity 0.0 upto 100.0 for the othertween steps"}, {GIMP_PDB_INT32, "tracelayer_enable", "TRUE: calculate a tracelayer (with all steps of the moving objects since first step)"}, {GIMP_PDB_FLOAT, "trace_opacity_initial", "opacity 0.0 upto 100.0 for the nearest tracestep to the actual destination frame"}, {GIMP_PDB_FLOAT, "trace_opacity_desc", "descending opacity 0.0 upto 100.0 for fading out older positions (that are done before the actual step)"}, {GIMP_PDB_INT32, "apply_bluebox", "TRUE: apply blubox filter (using bluebox param VALUES of last successful bluebox run)"}, {GIMP_PDB_INT32, "src_selmode", "0: ignore selections in all source images\n" "1: use one selection (from the inital source image) for all handled src layers \n" "2: use selections in all source images (for stepmodes 0-5 there is only one source image)"}, /* CONTROLPOINT Arrays (the _ext API uses FLOAT arrays for more precision) */ { GIMP_PDB_INT32, "argc_p_x", "number of controlpoints"}, { GIMP_PDB_INT32ARRAY, "p_x", "Controlpoint x-koordinate"}, { GIMP_PDB_INT32, "argc_p_y", "number of controlpoints"}, { GIMP_PDB_INT32ARRAY, "p_y", "Controlpoint y-koordinate"}, { GIMP_PDB_INT32, "argc_opacity", "number of controlpoints"}, { GIMP_PDB_FLOATARRAY, "opacity", "Controlpoint opacity value 0 <= value <= 100"}, { GIMP_PDB_INT32, "argc_w_resize", "number of controlpoints"}, { GIMP_PDB_FLOATARRAY, "w_resize", "width scaling in percent"}, { GIMP_PDB_INT32, "argc_h_resize", "number of controlpoints"}, { GIMP_PDB_FLOATARRAY, "h_resize", "height scaling in percent"}, { GIMP_PDB_INT32, "argc_rotation", "number of controlpoints"}, { GIMP_PDB_FLOATARRAY, "rotation", "rotation in degrees"}, { GIMP_PDB_INT32, "argc_keyframe_abs", "number of controlpoints"}, { GIMP_PDB_INT32ARRAY, "keyframe_abs", "n: fix controlpoint to this frame number, 0: for controlpoints that are not fixed to a frame."}, /* new CONTROLPOINT ARRAY items of the _ext[ended] API */ { GIMP_PDB_INT32, "argc_ttlx", "number of controlpoints"}, { GIMP_PDB_FLOATARRAY, "ttlx", "perspective transformfactor for top left X Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"}, { GIMP_PDB_INT32, "argc_ttly", "number of controlpoints"}, { GIMP_PDB_FLOATARRAY, "ttly", "perspective transformfactor for top left Y Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"}, { GIMP_PDB_INT32, "argc_ttrx", "number of controlpoints"}, { GIMP_PDB_FLOATARRAY, "ttrx", "perspective transformfactor for top right X Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"}, { GIMP_PDB_INT32, "argc_ttry", "number of controlpoints"}, { GIMP_PDB_FLOATARRAY, "ttry", "perspective transformfactor for top right Y Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"}, { GIMP_PDB_INT32, "argc_tblx", "number of controlpoints"}, { GIMP_PDB_FLOATARRAY, "tblx", "perspective transformfactor for bottom left X Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"}, { GIMP_PDB_INT32, "argc_tbly", "number of controlpoints"}, { GIMP_PDB_FLOATARRAY, "tbly", "perspective transformfactor for bottom left Y Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"}, { GIMP_PDB_INT32, "argc_tbrx", "number of controlpoints"}, { GIMP_PDB_FLOATARRAY, "tbrx", "perspective transformfactor for bottom right X Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"}, { GIMP_PDB_INT32, "argc_tbry", "number of controlpoints"}, { GIMP_PDB_FLOATARRAY, "tbry", "perspective transformfactor for bottom right Y Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"}, { GIMP_PDB_INT32, "argc_sel", "number of controlpoints"}, { GIMP_PDB_FLOATARRAY, "sel_feather_radius", "feather radius for selections"}, }; static int nargs_mov_path_ext = G_N_ELEMENTS (args_mov_path_ext); static GimpParamDef args_mov_path_ext2[] = { {GIMP_PDB_INT32, "run_mode", "non-interactive"}, {GIMP_PDB_IMAGE, "dst_image", "Destination image (one of the video frames), where to insert the animated source layers"}, {GIMP_PDB_DRAWABLE, "drawable", "drawable (unused)"}, {GIMP_PDB_INT32, "range_from", "destination frame nr to start"}, {GIMP_PDB_INT32, "range_to", "destination frame nr to stop (can be lower than range_from)"}, {GIMP_PDB_INT32, "nr", "layerstack position where to insert source layer (0 == on top)"}, /* source specs */ { GIMP_PDB_LAYER, "src_layer_id", "starting LayerID of SourceObject. (use any Multilayeranimated Image, or an video frame of anoter Animation)"}, { GIMP_PDB_INT32, "src_stepmode", "0-5 derive inserted object as copy of one layer from a multilayer src_image \n" "100-105 derive inserted object as copy of merged visible layers of a source video frame \n" "0: Layer Loop 1: Layer Loop reverse 2: Layer Once 3: Layer Once reverse 4: Layer PingPong \n" "5: None (use onle the selected src_layer)\n" "100: Frame Loop 101: Frame Loop reverse 102: Frame Once 103: Frame Once reverse 104: Frame PingPong \n" "105: Frame None (use onle the flat copy of the selected frame)\n" }, { GIMP_PDB_INT32, "src_handle", "0: handle left top 1: handle left bottom \n" "2: handle right top 3: handle right bottom \n" "4: handle center"}, { GIMP_PDB_INT32, "src_paintmode", "4444: keep original paintmode of src_layer 0: GIMP_NORMAL_MODE (see GimpLayerModeEffects -- libgimp/gimpenums.h -- for more information)"}, { GIMP_PDB_INT32, "src_force_visible", "1: Set inserted layres visible, 0: insert layers as is"}, { GIMP_PDB_INT32, "clip_to_img", "1: Clip inserted layers to Image size of the destination video frame, 0: dont clip"}, /* extras */ { GIMP_PDB_INT32, "rotation_follow", "0: NO automatic calculation (use the rotation array parameters as it is) \n" "1: Automatic calculation of rotation, following the path vectors, (Ignore rotation array parameters)\n"}, { GIMP_PDB_FLOAT, "startangle", "start angle for the first contolpoint (only used if rotation-follow is on)"}, /* new features of the _ext[ended] API */ {GIMP_PDB_FLOAT, "step_speed_factor", "Allows stepping Source and Destination at different speed. (0.1 upto 50 where 1.0 does step snychron, 2.0 Src makes 2 Steps while Destination makes 1 step) "}, {GIMP_PDB_INT32, "tween_steps", "0 upto 50, Number of virtual Frames to calculate between 2 destination Frames. (use value 0 if no tween processing should be done)"}, {GIMP_PDB_FLOAT, "tween_opacity_initial", "opacity 0.0 upto 100.0 for the tween step that is nearest to the (next) real frame"}, {GIMP_PDB_FLOAT, "tween_opacity_desc", "descending opacity 0.0 upto 100.0 for the othertween steps"}, {GIMP_PDB_INT32, "tracelayer_enable", "TRUE: calculate a tracelayer (with all steps of the moving objects since first step)"}, {GIMP_PDB_FLOAT, "trace_opacity_initial", "opacity 0.0 upto 100.0 for the nearest tracestep to the actual destination frame"}, {GIMP_PDB_FLOAT, "trace_opacity_desc", "descending opacity 0.0 upto 100.0 for fading out older positions (that are done before the actual step)"}, {GIMP_PDB_INT32, "apply_bluebox", "TRUE: apply blubox filter (using bluebox param VALUES of last successful bluebox run)"}, /* CONTROLPOINTs from file */ { GIMP_PDB_STRING, "pointfile", "a file with contolpoints (readable text file with one line per controlpoint)"}, }; static int nargs_mov_path_ext2 = G_N_ELEMENTS (args_mov_path_ext2); static GimpParamDef args_f2multi[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "range_from", "frame nr to start"}, {GIMP_PDB_INT32, "range_to", "frame nr to stop (can be lower than range_from)"}, {GIMP_PDB_INT32, "flatten_mode", "{ expand-as-necessary(0), CLIP-TO_IMG(1), CLIP-TO-BG-LAYER(2), FLATTEN(3) }"}, {GIMP_PDB_INT32, "bg_visible", "{ BG_NOT_VISIBLE (0), BG_VISIBLE(1) }"}, {GIMP_PDB_INT32, "framerate", "frame delaytime in ms"}, {GIMP_PDB_STRING, "frame_basename", "basename for all generated layers"}, {GIMP_PDB_INT32, "select_mode", "Mode how to identify a layer: 0-3 by layername 0=equal, 1=prefix, 2=suffix, 3=contains, 4=layerstack_numberslist, 5=inv_layerstack, 6=all_visible"}, {GIMP_PDB_INT32, "select_case", "0: ignore case 1: select_string is case sensitive"}, {GIMP_PDB_INT32, "select_invert", "0: select normal 1: invert (select all unselected layers)"}, {GIMP_PDB_STRING, "select_string", "string to match with layername (how to match is defined by select_mode)"}, {GIMP_PDB_INT32, "regionselect_mode", "How to picup layers: 0: use full layersize, ignore selection,\n" " 1=pick only selected regions (use a fix selection of the invoking frame in all handled frames)\n" " 2=pick only selected regions (use individual selction as it is in each handled frame)"}, }; static int nargs_f2multi = G_N_ELEMENTS (args_f2multi); static GimpParamDef return_f2multi[] = { { GIMP_PDB_IMAGE, "new_image", "Output image" } }; static int nreturn_f2multi = G_N_ELEMENTS (return_f2multi); static GimpParamDef args_rflatt[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "range_from", "frame nr to start"}, {GIMP_PDB_INT32, "range_to", "frame nr to stop (can be lower than range_from)"}, }; static int nargs_rflatt = G_N_ELEMENTS (args_rflatt); static GimpParamDef args_rlayerdel[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "range_from", "frame nr to start"}, {GIMP_PDB_INT32, "range_to", "frame nr to stop (can be lower than range_from)"}, {GIMP_PDB_INT32, "nr", "layerstack position (0 == on top)"}, }; static int nargs_rlayerdel = G_N_ELEMENTS (args_rlayerdel); static GimpParamDef args_rconv[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "range_from", "frame nr to start"}, {GIMP_PDB_INT32, "range_to", "frame nr to stop (can be lower than range_from)"}, {GIMP_PDB_INT32, "flatten", "0 .. dont flatten image before save"}, {GIMP_PDB_INT32, "dest_type", "0=RGB, 1=GRAY, 2=INDEXED"}, {GIMP_PDB_INT32, "dest_colors", "1 upto 256 (used only for dest_type INDEXED)"}, {GIMP_PDB_INT32, "dest_dither", "0=no, 1=floyd-steinberg 2=fs/low-bleed, 3=fixed (used only for dest_type INDEXED)"}, {GIMP_PDB_STRING, "extension", "extension for the destination filetype (jpg, tif ...or any other gimp supported type)"}, {GIMP_PDB_STRING, "basename", "(optional parameter) here you may specify the basename of the destination frames \"/my_dir/myframe\" _0001.ext is added)"}, }; static int nargs_rconv = G_N_ELEMENTS (args_rconv); static GimpParamDef args_rconv2[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "range_from", "frame nr to start"}, {GIMP_PDB_INT32, "range_to", "frame nr to stop (can be lower than range_from)"}, {GIMP_PDB_INT32, "flatten", "0 .. dont flatten image before save"}, {GIMP_PDB_INT32, "dest_type", "0=RGB, 1=GRAY, 2=INDEXED"}, {GIMP_PDB_INT32, "dest_colors", "1 upto 256 (used only for dest_type INDEXED)"}, {GIMP_PDB_INT32, "dest_dither", "0=no, 1=floyd-steinberg 2=fs/low-bleed, 3=fixed(used only for dest_type INDEXED)"}, {GIMP_PDB_STRING, "extension", "extension for the destination filetype (jpg, tif ...or any other gimp supported type)"}, {GIMP_PDB_STRING, "basename", "(optional parameter) here you may specify the basename of the destination frames \"/my_dir/myframe\" _0001.ext is added)"}, {GIMP_PDB_INT32, "palette_type", "0 == MAKE_PALETTE, 2 == WEB_PALETTE, 3 == MONO_PALETTE (bw) 4 == CUSTOM_PALETTE (used only for dest_type INDEXED)"}, {GIMP_PDB_INT32, "alpha_dither", "dither transparency to fake partial opacity (used only for dest_type INDEXED)"}, {GIMP_PDB_INT32, "remove_unused", "remove unused or double colors from final palette (used only for dest_type INDEXED)"}, {GIMP_PDB_STRING, "palette", "name of the custom palette to use (used only for dest_type INDEXED and palette_type == CUSTOM_PALETTE) "}, }; static int nargs_rconv2 = G_N_ELEMENTS (args_rconv2); static GimpParamDef return_rconv[] = { { GIMP_PDB_IMAGE, "frame_image", "the image_id of the converted frame with lowest frame numer (of the converted range)" } }; static int nreturn_rconv = G_N_ELEMENTS(return_rconv) ; /* resize and crop share the same parameters */ static GimpParamDef args_resize[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "new_width", "width of the resulting video frame images in pixels"}, {GIMP_PDB_INT32, "new_height", "height of the resulting video frame images in pixels"}, {GIMP_PDB_INT32, "offset_x", "X offset in pixels"}, {GIMP_PDB_INT32, "offset_y", "Y offset in pixels"}, }; static int nargs_resize = G_N_ELEMENTS (args_resize); static GimpParamDef args_scale[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "new_width", "width of the resulting video frame images in pixels"}, {GIMP_PDB_INT32, "new_height", "height of the resulting video frame images in pixels"}, }; static int nargs_scale = G_N_ELEMENTS (args_scale); static GimpParamDef args_split[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (NO video frame allowed)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "inverse_order", "True/False"}, {GIMP_PDB_INT32, "no_alpha", "True: remove alpha channel(s) in the destination frames"}, {GIMP_PDB_STRING, "extension", "extension for the destination filetype (jpg, tif ...or any other gimp supported type)"}, {GIMP_PDB_INT32, "only visible", "TRUE: Handle only visible layers, FALSE: Handle all layers and force visibility"}, {GIMP_PDB_INT32, "digits", "Number of digits for the number part in the frames filenames"}, {GIMP_PDB_INT32, "copy_properties", "True: copy image properties (channels, paths, guides ...)" " to all created frame images (algorithm based on gimp_image_duplicate)" "False: copy only layers (faster)"}, }; static int nargs_split = G_N_ELEMENTS (args_split); static GimpParamDef return_split[] = { { GIMP_PDB_IMAGE, "new_image", "Output image (first or last resulting frame)" } }; static int nreturn_split = G_N_ELEMENTS (return_split); static GimpParamDef args_shift[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (current one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "nr", "how many framenumbers to shift the Frame Sequence"}, {GIMP_PDB_INT32, "range_from", "frame nr to start"}, {GIMP_PDB_INT32, "range_to", "frame nr to stop"}, }; static int nargs_shift = G_N_ELEMENTS (args_shift); static GimpParamDef args_reverse[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (current one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "range_from", "frame nr to start"}, {GIMP_PDB_INT32, "range_to", "frame nr to stop"}, }; static int nargs_reverse = G_N_ELEMENTS (args_reverse); static GimpParamDef args_renumber[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (current one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "nr", "start frame number for the first frame (usual value is 1)"}, {GIMP_PDB_INT32, "digits", "how many digits to use for the framenumber part (1 upto 8)"}, }; static int nargs_renumber = G_N_ELEMENTS (args_renumber); static GimpParamDef args_modify[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (current one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "range_from", "frame nr to start"}, {GIMP_PDB_INT32, "range_to", "frame nr to stop"}, {GIMP_PDB_INT32, "action_mode", "0:set_visible" ", 1:set_invisible" ", 2:set_linked" ", 3:set_unlinked" ", 4:raise" ", 5:lower" ", 6:merge_expand" ", 7:merge_img" ", 8:merge_bg" ", 9:apply_filter" ", 10:duplicate" ", 11:delete" ", 12:rename" ", 13:replace selection" ", 14:add selection" ", 15:sbtract selection" ", 16:intersect selection" ", 17:selection none" ", 18:selection all" ", 19:selection invert" ", 20:save selection to channel" ", 21:load selection from channel" ", 22:delete channel (by name)" ", 23:add alpha channel" ", 24:add white layermask (opaque)" ", 25:add black layermask (transparent)" ", 26:add alpha layermask" ", 27:add alpha transfer layermask" ", 28:add selection as layermask" ", 29:add bw copy as layermask" ", 30:delete layermask" ", 31:apply layermask" ", 32:copy layermask from layer above" ", 33:copy layermask from layer below" ", 34:invert layermask" ", 35:set layer mode to normal" ", 36:set layer mode to dissolve" ", 37:set layer mode to multiply" ", 38:set layer mode to divide" ", 39:set layer mode to screen" ", 40:set layer mode to overlay" ", 41:set layer mode to difference" ", 42:set layer mode to addition" ", 43:set layer mode to subtract" ", 44:set layer mode to darken_only" ", 45:set layer mode to lighten_only" ", 46:set layer mode to dodge" ", 47:set layer mode to burn" ", 48:set layer mode to hardlight" ", 49:set layer mode to softlight" ", 50:set layer mode to color_erase" ", 51:set layer mode to grain_extract_mode" ", 52:set layer mode to grain_merge_mode" ", 53:set layer mode to hue_mode" ", 54:set layer mode to saturation_mode" ", 55:set layer mode to color_mode" ", 56:set layer mode to value_mode" ", 57:apply filter on layermask" ", 58:set selection from alphachannel" }, {GIMP_PDB_INT32, "select_mode", "Mode how to identify a layer: 0-3 by layername 0=equal, 1=prefix, 2=suffix, 3=contains, 4=layerstack_numberslist, 5=inv_layerstack, 6=all_visible"}, {GIMP_PDB_INT32, "select_case", "0: ignore case 1: select_string is case sensitive"}, {GIMP_PDB_INT32, "select_invert", "0: select normal 1: invert (select all unselected layers)"}, {GIMP_PDB_STRING, "select_string", "string to match with layername (how to match is defined by select_mode)"}, {GIMP_PDB_STRING, "new_layername", "is only used at action rename. [####] is replaced by the framnumber"}, }; static int nargs_modify = G_N_ELEMENTS (args_modify); static GimpParamDef args_video_copy[] = { {GIMP_PDB_INT32, "run_mode", "always non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (current one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "range_from", "frame nr to start"}, {GIMP_PDB_INT32, "range_to", "frame nr to stop"}, }; static int nargs_video_copy = G_N_ELEMENTS (args_video_copy); static GimpParamDef args_video_paste[] = { {GIMP_PDB_INT32, "run_mode", "always non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (current one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "paste_mode", "0 .. paste at current frame (replacing current and following frames)" "1 .. paste insert before current frame " "2 .. paste insert after current frame"}, }; static int nargs_video_paste = G_N_ELEMENTS (args_video_paste); static GimpParamDef args_video_clear[] = { {GIMP_PDB_INT32, "run_mode", "always non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (is ignored)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, }; static GimpParamDef return_ainfo[] = { { GIMP_PDB_INT32, "first_frame_nr", "lowest frame number of all video frame discfiles" }, { GIMP_PDB_INT32, "last_frame_nr", "highest frame number of all video frame discfiles" }, { GIMP_PDB_INT32, "curr_frame_nr", "current frame number (extracted from the imagename)" }, { GIMP_PDB_INT32, "frame_cnt", "total number of all video frame discfiles that belong to the passed image" }, { GIMP_PDB_STRING, "basename", "basename of the video frame (without frame number and extension)\n" " may also include path (depending how the current frame image was opened)" }, { GIMP_PDB_STRING, "extension", "extension of the video frames (.xcf)" }, { GIMP_PDB_FLOAT, "framerate", "framerate in frames per second" } }; static int nreturn_ainfo = G_N_ELEMENTS (return_ainfo); static GimpParamDef args_setrate[] = { {GIMP_PDB_INT32, "run_mode", "non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (current one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_FLOAT, "framerate", "framerate in frames per second" } }; static int nargs_setrate = G_N_ELEMENTS (args_setrate); MAIN () static void query () { gchar *l_help_str; gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); gimp_install_procedure(PLUGIN_NAME_GAP_NEXT, "This plugin exchanges current image with (next numbered) image from disk.", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Next Frame"), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_std, nreturn_std, args_std, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_PREV, "This plugin exchanges current image with (previous numbered) image from disk.", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Previous Frame"), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_std, nreturn_std, args_std, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_FIRST, "This plugin exchanges current image with (lowest numbered) image from disk.", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("First Frame"), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_std, nreturn_std, args_std, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_LAST, "This plugin exchanges current image with (highest numbered) image from disk.", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Last Frame"), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_std, nreturn_std, args_std, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_GOTO, "This plugin exchanges current image with requested image (nr) from disk.", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Any Frame..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_goto, nreturn_std, args_goto, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_DEL, "This plugin deletes the given number of frames from disk including the current frame.", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Delete Frames..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_del, nreturn_std, args_del, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_DUP, "This plugin duplicates the current frames on disk n-times.", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Duplicate Frames..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_dup, nreturn_std, args_dup, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_DENSITY, "This plugin changes the number of frames (density) on disk to match a" " new target framerate that is densty_factor times higher" " than the origianl framerate." " (or 1/density_factor lower if density_grow is FALSE)" " changing of density results in duplicating (or deleting)" " of frames on disk", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Frames Density..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_dup, nreturn_std, args_dup, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_EXCHG, "This plugin exchanges content of the current with destination frame.", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Exchange Frame..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_exchg, nreturn_std, args_exchg, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_MOVE, "This plugin copies layer(s) from one sourceimage to multiple frames on disk, varying position, size and opacity.", "For NONINTERACTIVE PDB interfaces see also (plug_in_gap_move_path_ext, plug_in_gap_move_path_ext2)", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Move Path..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, G_N_ELEMENTS (args_mov), nreturn_std, args_mov, return_std); l_help_str = g_strdup_printf( "This plugin inserts one layer in each frame of the selected frame range of an Animation\n" " (specified by the dst_image parameter).\n" " An Animation is a series of numbered video frame images on disk where only the current\n" " Frame is opened in the gimp\n" " The inserted layer is derived from another (multilayer)image\n" " or from another Animation (as merged copy of the visible layers in a source frame)\n" " the affected destination frame range is selected by the range_from and range_to parameters\n" " the src_stepmode parameter controls how to derive the layer that is to be inserted.\n" " With the Controlpoint Parameters you can control position (coordinates),\n" " size, rotation, perspective and opacity values of the inserted layer\n" " If you want to move an Object from position AX/AY to BX/BY in a straight line within the range of 24 frames\n" " you need 2 Contolpoints, if you want the object to move folowing a path\n" " you need some more Controlpoints to do that.\n" " With the rotation_follow Parameter you can force automatic calculation of the rotation for the inserted\n" " layer according to the path vectors it is moving along.\n" " A controlpoint can be fixed to a special framenumber using the keyframe_abs controlpoint-parameter.\n" " Restictions:\n" " - keyframe_abs numbers must be 0 (== not fixed) or a frame_number within the affected frame range\n" " - keyframes_abs must be in sequence (ascending or descending)\n" " - the first and last controlpoint are always implicite keyframes, and should be passed with keyframe_abs = 0\n" " - the number of controlpoints is limitied to a maximum of %d.\n" " the number of controlpoints must be passed in all argc_* parameters\n" "If the TraceLayer feature is turned on, an additional layer\n" " is inserted below the moving object. This Tracelayer shows all steps\n" " of the moving object since the 1st Frame.\n" "With TweenSteps you can calculate virtual Frames between 2 destination frames\n" " all these Steps are collected in another additional Layer.\n" " this Tweenlayer is added below the moving Obect in all handled destination Frames\n" "See also (plug_in_gap_move_path, plug_in_gap_move)", (int)GAP_MOV_MAX_POINT); gimp_install_procedure(PLUGIN_NAME_GAP_MOVE_PATH_EXT, "This plugin copies layer(s) from one sourceimage or source animation to multiple frames on disk,\n" "with varying position, size, perspective and opacity.\n" , l_help_str, "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, NULL, /* do not appear in menus */ "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_mov_path_ext, nreturn_std, args_mov_path_ext, return_std); g_free(l_help_str); gimp_install_procedure(PLUGIN_NAME_GAP_MOVE_PATH_EXT2, "This plugin copies layer(s) from one sourceimage or source animation to multiple frames on disk,\n" "with varying position, size, perspective and opacity.\n" , "This plugin is just another Interface for the MovePath (plug_in_gap_move_path_ext)\n" " using a File to specify Controlpoints (rather than Array parameters).\n" " Notes:\n" " - you can create a controlpoint file with in the MovePath Dialog (interactive call of plug_in_gap_move)\n" " - for more infos about controlpoints see help of (plug_in_gap_move_path)\n" , "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, NULL, /* do not appear in menus */ "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_mov_path_ext2, nreturn_std, args_mov_path_ext2, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_RANGE_TO_MULTILAYER, "This plugin creates a new image from the given range of frame-images. Each frame is converted to one layer in the new image, according to flatten_mode. (the frames on disk are not changed).", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Frames to Image..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_f2multi, nreturn_f2multi, args_f2multi, return_f2multi); gimp_install_procedure(PLUGIN_NAME_GAP_RANGE_FLATTEN, "This plugin flattens the given range of frame-images (on disk)", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Frames Flatten..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_rflatt, nreturn_std, args_rflatt, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_RANGE_LAYER_DEL, "This plugin deletes one layer in the given range of frame-images (on disk). exception: the last remaining layer of a frame is not deleted", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Frames Layer Delete..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_rlayerdel, nreturn_std, args_rlayerdel, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_RANGE_CONVERT, "This plugin converts the given range of frame-images to other fileformats (on disk) depending on extension", "WARNING this procedure is obsolete, please use plug_in_gap_range_convert2", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, NULL, /* do not appear in menus */ "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_rconv, nreturn_rconv, args_rconv, return_rconv); gimp_install_procedure(PLUGIN_NAME_GAP_RANGE_CONVERT2, "This plugin converts the given range of frame-images to other fileformats (on disk) depending on extension", "only one of the converted frames is returned (the one with lowest handled frame number)", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Frames Convert..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_rconv2, nreturn_rconv, args_rconv2, return_rconv); gimp_install_procedure(PLUGIN_NAME_GAP_ANIM_RESIZE, "This plugin resizes all video frames (images on disk) to the given new_width/new_height", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Frames Resize..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_resize, nreturn_std, args_resize, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_ANIM_CROP, "This plugin crops all video frames (images on disk) to the given new_width/new_height", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Frames Crop..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_resize, nreturn_std, args_resize, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_ANIM_SCALE, "This plugin scales all video frames (images on disk) to the given new_width/new_height", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Frames Scale..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_scale, nreturn_std, args_scale, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_SPLIT, "This plugin splits the current image to video frames (images on disk). Each layer is saved as one frame", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Split Image to Frames..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_split, nreturn_split, args_split, return_split); gimp_install_procedure(PLUGIN_NAME_GAP_SHIFT, "This plugin exchanges frame numbers in the given range. (discfile frame_0001.xcf is renamed to frame_0002.xcf, 2->3, 3->4 ... n->1)", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Frame Sequence Shift..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_shift, nreturn_std, args_shift, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_REVERSE, "This plugin reverse the order of frame numbers in the given range. ( 3-4-5-6-7 ==> 7-6-5-4-3)", "", "Saul Goode (saulgoode@brickfilms.com)", "Saul Goode", GAP_VERSION_WITH_DATE, N_("Frame Sequence Reverse..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_reverse, nreturn_std, args_reverse, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_RENUMBER, "This plugin renumbers all frames (discfiles) starting at start_frame_nr using n digits for the framenumber part)", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Frames Renumber..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_renumber, nreturn_std, args_renumber, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_MODIFY, "This plugin performs a modifying action on each selected layer in each selected framerange", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Frames Modify..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_modify, nreturn_std, args_modify, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_VIDEO_EDIT_COPY, "This plugin appends the selected framerange to the video paste buffer" "the video paste buffer is a directory configured by gimprc (video-paste-dir )" "and a framefile basename configured by gimprc (video-paste-basename)", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, NULL, /* do not appear in menus */ "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_video_copy, nreturn_nothing, args_video_copy, return_nothing); gimp_install_procedure(PLUGIN_NAME_GAP_VIDEO_EDIT_PASTE, "This plugin copies all frames from the video paste buffer" "to the current video. Depending on the paste_mode parameter" "the copied frames are replacing frames beginning at current frame" "or are inserted before or after the current frame" "the pasted frames are scaled to fit the current video size" "and converted in Imagetype (RGB,GRAY,INDEXED) if necessary" "the video paste buffer is a directory configured by gimprc (video-paste-dir )" "and a framefile basename configured by gimprc (video-paste-basename)", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, NULL, /* do not appear in menus */ "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_video_paste, nreturn_std, args_video_paste, return_std); gimp_install_procedure(PLUGIN_NAME_GAP_VIDEO_EDIT_CLEAR, "clear the video paste buffer by deleting all framefiles" "the video paste buffer is a directory configured by gimprc (video-paste-dir )" "and a framefile basename configured by gimprc (video-paste-basename)", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, NULL, /* do not appear in menus */ "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, G_N_ELEMENTS (args_video_clear), nreturn_nothing, args_video_clear, return_nothing); gimp_install_procedure(PLUGIN_NAME_GAP_GET_ANIMINFO, "This plugin gets animation infos about video frames." , "Informations about the video frames belonging to the\n" " passed image_id are returned. (therefore the directory\n" " is scanned and checked for video frame discfiles.\n" " If you call this plugin on images without a Name\n" " You will get just default values." , "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, NULL, /* no menu */ "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_std, nreturn_ainfo, args_std, return_ainfo); gimp_install_procedure(PLUGIN_NAME_GAP_SET_FRAMERATE, "This plugin sets the framerate for video frames", "The framerate is stored in a video info file" " named like the basename of the video frames" " without a framenumber. The extension" " of this video info file is .vin", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, NULL, /* no menu */ "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_setrate, nreturn_nothing, args_setrate, return_nothing); { /* Menu names */ const char *menupath_image_video = N_("/Video/"); const char *menupath_image_video_goto = N_("/Video/Go To/"); //gimp_plugin_menu_branch_register("", "Video"); //gimp_plugin_menu_branch_register("/Video", "Go To"); gimp_plugin_menu_register (PLUGIN_NAME_GAP_NEXT, menupath_image_video_goto); gimp_plugin_menu_register (PLUGIN_NAME_GAP_PREV, menupath_image_video_goto); gimp_plugin_menu_register (PLUGIN_NAME_GAP_FIRST, menupath_image_video_goto); gimp_plugin_menu_register (PLUGIN_NAME_GAP_LAST, menupath_image_video_goto); gimp_plugin_menu_register (PLUGIN_NAME_GAP_GOTO, menupath_image_video_goto); gimp_plugin_menu_register (PLUGIN_NAME_GAP_DEL, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_DUP, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_DENSITY, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_EXCHG, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_MOVE, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_RANGE_TO_MULTILAYER, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_RANGE_FLATTEN, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_RANGE_LAYER_DEL, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_RANGE_CONVERT2, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_ANIM_RESIZE, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_ANIM_CROP, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_ANIM_SCALE, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_SPLIT, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_SHIFT, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_REVERSE, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_RENUMBER, menupath_image_video); gimp_plugin_menu_register (PLUGIN_NAME_GAP_MODIFY, menupath_image_video); } } /* end query */ static void run (const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals) { const char *l_env; char l_extension[32]; char l_sel_str[MAX_LAYERNAME]; char l_layername[MAX_LAYERNAME]; char *l_basename_ptr; char *l_palette_ptr; static GimpParam values[20]; GimpRunMode run_mode; GimpRunMode lock_run_mode; GimpPDBStatusType status; gint32 image_id; gint32 lock_image_id; gint32 nr; long range_from, range_to; GimpImageBaseType dest_type; gint32 dest_colors; gint32 dest_dither; gint32 palette_type; gint32 alpha_dither; gint32 remove_unused; gint32 mode; long new_width; long new_height; long offs_x; long offs_y; gint32 inverse_order; gint32 no_alpha; long framerate; #define FRAME_BASENAME_LEN 256 char frame_basename[FRAME_BASENAME_LEN]; gint32 sel_mode, sel_case, sel_invert; gint32 selection_mode; gint32 l_rc_image; /* init std return values status and image (as used in most of the gap plug-ins) */ *nreturn_vals = 2; *return_vals = values; status = GIMP_PDB_SUCCESS; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; values[1].type = GIMP_PDB_IMAGE; values[1].data.d_int32 = -1; nr = 0; l_rc_image = -1; l_env = g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } run_mode = param[0].data.d_int32; lock_run_mode = run_mode; if((strcmp (name, PLUGIN_NAME_GAP_PREV) == 0) || (strcmp (name, PLUGIN_NAME_GAP_NEXT) == 0)) { /* stepping from frame to frame is often done * in quick sequence via Shortcut Key, and should * not open dialog windows if the previous GAP lock is still active. * therefore i set NONINTERACTIVE run_mode to prevent * gap_lock_check_for_lock from open a gimp_message window. */ lock_run_mode = GIMP_RUN_NONINTERACTIVE; } if(gap_debug) fprintf(stderr, "\n\ngap_main: debug name = %s\n", name); /* gimp_ui_init is sometimes needed even in NON-Interactive * runmodes. * because thumbnail handling uses the procedure gdk_pixbuf_new_from_file * that will crash if not initialized * so better init always, just to be on the save side. * (most diaolgs do init a 2.nd time but this worked well) */ gimp_ui_init ("gap_main", FALSE); image_id = param[1].data.d_image; if(!gap_image_is_alive(image_id)) { printf("GAP plug-in was called on INVALID IMAGE_ID:%d (terminating)\n", (int)image_id); status = GIMP_PDB_EXECUTION_ERROR; values[0].data.d_status = status; return ; } lock_image_id = image_id; /* --------------------------- * NON-LOCKING gap_plugins * --------------------------- */ if (strcmp (name, PLUGIN_NAME_GAP_GET_ANIMINFO) == 0) { GapAnimInfo *ainfo_ptr; GapVinVideoInfo *vin_ptr; ainfo_ptr = gap_lib_alloc_ainfo(image_id, GIMP_RUN_NONINTERACTIVE); if(ainfo_ptr == NULL) { status = GIMP_PDB_EXECUTION_ERROR; } else if (0 != gap_lib_dir_ainfo(ainfo_ptr)) { status = GIMP_PDB_EXECUTION_ERROR; } /* return the new generated image_id */ *nreturn_vals = nreturn_ainfo +1; values[0].data.d_status = status; values[1].type = GIMP_PDB_INT32; values[2].type = GIMP_PDB_INT32; values[3].type = GIMP_PDB_INT32; values[4].type = GIMP_PDB_INT32; values[5].type = GIMP_PDB_STRING; values[6].type = GIMP_PDB_STRING; values[7].type = GIMP_PDB_FLOAT; if(ainfo_ptr != NULL) { values[1].data.d_int32 = ainfo_ptr->first_frame_nr; values[2].data.d_int32 = ainfo_ptr->last_frame_nr; values[3].data.d_int32 = ainfo_ptr->curr_frame_nr; values[4].data.d_int32 = ainfo_ptr->frame_cnt; values[5].data.d_string = g_strdup(ainfo_ptr->basename); values[6].data.d_string = g_strdup(ainfo_ptr->extension); values[7].data.d_float = -1.0; vin_ptr = gap_vin_get_all(ainfo_ptr->basename); if(vin_ptr != NULL) { values[7].data.d_float = vin_ptr->framerate; } } return; } else if (strcmp (name, PLUGIN_NAME_GAP_SET_FRAMERATE) == 0) { GapAnimInfo *ainfo_ptr; GapVinVideoInfo *vin_ptr; *nreturn_vals = nreturn_nothing +1; if (n_params != nargs_setrate) { status = GIMP_PDB_CALLING_ERROR; } else { ainfo_ptr = gap_lib_alloc_ainfo(image_id, GIMP_RUN_NONINTERACTIVE); if(ainfo_ptr == NULL) { status = GIMP_PDB_EXECUTION_ERROR; } else if (0 != gap_lib_dir_ainfo(ainfo_ptr)) { status = GIMP_PDB_EXECUTION_ERROR;; } else { vin_ptr = gap_vin_get_all(ainfo_ptr->basename); if(vin_ptr == NULL) { status = GIMP_PDB_EXECUTION_ERROR;; } else { vin_ptr->framerate = param[3].data.d_float; gap_vin_set_common(vin_ptr, ainfo_ptr->basename); } } } values[0].data.d_status = status; return; } /* --------------------------- * check for LOCKS * --------------------------- */ if(gap_lock_check_for_lock(lock_image_id, lock_run_mode)) { status = GIMP_PDB_EXECUTION_ERROR; values[0].data.d_status = status; return ; } /* set LOCK on current image (for all gap_plugins) */ gap_lock_set_lock(lock_image_id); INIT_I18N(); /* --------------------------- * LOCKING gap_plugins * --------------------------- */ if (strcmp (name, PLUGIN_NAME_GAP_NEXT) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_std) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { l_rc_image = gap_base_next(run_mode, image_id); } } else if (strcmp (name, PLUGIN_NAME_GAP_PREV) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_std) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { l_rc_image = gap_base_prev(run_mode, image_id); } } else if (strcmp (name, PLUGIN_NAME_GAP_FIRST) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_std) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { l_rc_image = gap_base_first(run_mode, image_id); } } else if (strcmp (name, PLUGIN_NAME_GAP_LAST) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_std) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { l_rc_image = gap_base_last(run_mode, image_id); } } else if (strcmp (name, PLUGIN_NAME_GAP_GOTO) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_goto) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { nr = param[3].data.d_int32; /* destination frame nr */ l_rc_image = gap_base_goto(run_mode, image_id, nr); } } else if (strcmp (name, PLUGIN_NAME_GAP_DEL) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_del) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { nr = param[3].data.d_int32; /* number of frames to delete */ l_rc_image = gap_base_del(run_mode, image_id, nr); } } else if (strcmp (name, PLUGIN_NAME_GAP_DUP) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { /* accept the old interface with 4 parameters */ if ((n_params != 4) && (n_params != nargs_dup)) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { nr = param[3].data.d_int32; /* how often to copy current frame */ if (n_params > 5) { range_from = param[4].data.d_int32; /* frame nr to start */ range_to = param[5].data.d_int32; /* frame nr to stop */ } else { range_from = -1; range_to = -1; } l_rc_image = gap_base_dup(run_mode, image_id, nr, range_from, range_to ); } } else if (strcmp (name, PLUGIN_NAME_GAP_DENSITY) == 0) { gdouble density_factor; gboolean density_grow; if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_density) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { range_from = param[3].data.d_int32; /* frame nr to start */ range_to = param[4].data.d_int32; /* frame nr to stop */ density_factor = param[5].data.d_float; density_grow = param[6].data.d_int32; l_rc_image = gap_base_density(run_mode, image_id, range_from, range_to, density_factor, density_grow); } } else if (strcmp (name, PLUGIN_NAME_GAP_EXCHG) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_exchg) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { nr = param[3].data.d_int32; /* nr of frame to exchange with current frame */ l_rc_image = gap_base_exchg(run_mode, image_id, nr); } } else if (strcmp (name, PLUGIN_NAME_GAP_MOVE) == 0) { GapMovValues *pvals; pvals = g_new (GapMovValues, 1); if (run_mode == GIMP_RUN_NONINTERACTIVE) { status = GIMP_PDB_CALLING_ERROR; } if (status == GIMP_PDB_SUCCESS) { l_rc_image = gap_mov_exec_move_path(run_mode, image_id, pvals, NULL, 0, 0); } g_free(pvals); } else if ((strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT) == 0) || (strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT2) == 0)) { GapMovValues *pvals; gchar *pointfile; gint l_idx; gint l_numpoints; gint l_rotation_follow; gint32 l_startangle; pointfile = NULL; pvals = g_new (GapMovValues, 1); l_rotation_follow = 0; l_startangle = 0; pvals->dst_image_id = image_id; pvals->tmp_image_id = -1; pvals->tmpsel_image_id = -1; pvals->tmpsel_channel_id = -1; pvals->apv_mode = 0; pvals->apv_src_frame = -1; pvals->apv_mlayer_image = -1; pvals->apv_gap_paste_buff = NULL; pvals->apv_framerate = 24; pvals->apv_scalex = 100.0; pvals->apv_scaley = 100.0; pvals->cache_src_image_id = -1; pvals->cache_tmp_image_id = -1; pvals->cache_tmp_layer_id = -1; pvals->cache_frame_number = -1; pvals->cache_ainfo_ptr = NULL; pvals->point_idx = 0; pvals->point_idx_max = 0; pvals->src_apply_bluebox = 0; pvals->bbp = NULL; pvals->step_speed_factor = 1.0; pvals->tracelayer_enable = FALSE; pvals->trace_opacity_initial = 100.0; pvals->trace_opacity_desc = 80.0; pvals->tween_steps = 0; pvals->tween_opacity_initial = 80.0; pvals->tween_opacity_desc = 80.0; if (run_mode == GIMP_RUN_NONINTERACTIVE) { if ( ((n_params != nargs_mov_path_ext) && (strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT) == 0)) || ((n_params != nargs_mov_path_ext2) && (strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT2) == 0))) { status = GIMP_PDB_CALLING_ERROR; } else { pvals->dst_range_start = param[3].data.d_int32; pvals->dst_range_end = param[4].data.d_int32; pvals->dst_layerstack = param[5].data.d_int32; pvals->src_layer_id = param[6].data.d_layer; pvals->src_stepmode = param[7].data.d_int32; pvals->src_handle = param[8].data.d_int32; pvals->src_paintmode = param[9].data.d_int32; pvals->src_force_visible = param[10].data.d_int32; pvals->clip_to_img = param[11].data.d_int32; l_rotation_follow = param[12].data.d_int32; l_startangle = param[13].data.d_float; pvals->step_speed_factor = param[14].data.d_float; pvals->tween_steps = param[15].data.d_int32; pvals->tween_opacity_initial = param[16].data.d_float; pvals->tween_opacity_desc = param[17].data.d_float; pvals->tracelayer_enable = param[18].data.d_int32; pvals->trace_opacity_initial = param[19].data.d_float; pvals->trace_opacity_desc = param[20].data.d_float; pvals->src_apply_bluebox = param[21].data.d_int32; pvals->src_selmode = param[22].data.d_int32; if (strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT) == 0) { /* PLUGIN_NAME_GAP_MOVE_PATH_EXT passes controlpoints as array parameters */ l_numpoints = param[23].data.d_int32; if ((l_numpoints != param[25].data.d_int32) || (l_numpoints != param[27].data.d_int32) || (l_numpoints != param[29].data.d_int32) || (l_numpoints != param[31].data.d_int32) || (l_numpoints != param[33].data.d_int32) || (l_numpoints != param[35].data.d_int32) || (l_numpoints != param[37].data.d_int32) || (l_numpoints != param[39].data.d_int32) || (l_numpoints != param[41].data.d_int32) || (l_numpoints != param[43].data.d_int32) || (l_numpoints != param[45].data.d_int32) || (l_numpoints != param[47].data.d_int32) || (l_numpoints != param[49].data.d_int32) || (l_numpoints != param[51].data.d_int32) || (l_numpoints != param[53].data.d_int32)) { printf("plug_in_gap_move_path_ext: CallingError: different numbers in the controlpoint array argc parameters\n"); status = GIMP_PDB_CALLING_ERROR; } else { pvals->point_idx_max = l_numpoints -1; for(l_idx = 0; l_idx < l_numpoints; l_idx++) { pvals->point[l_idx].p_x = param[24].data.d_int32array[l_idx]; pvals->point[l_idx].p_y = param[26].data.d_int32array[l_idx]; pvals->point[l_idx].opacity = param[28].data.d_floatarray[l_idx]; pvals->point[l_idx].w_resize = param[30].data.d_floatarray[l_idx]; pvals->point[l_idx].h_resize = param[32].data.d_floatarray[l_idx]; pvals->point[l_idx].rotation = param[34].data.d_floatarray[l_idx]; pvals->point[l_idx].keyframe_abs = param[36].data.d_int32array[l_idx]; /* pvals->point[l_idx].keyframe = ; */ /* relative keyframes are calculated later */ pvals->point[l_idx].ttlx = param[38].data.d_floatarray[l_idx]; pvals->point[l_idx].ttly = param[40].data.d_floatarray[l_idx]; pvals->point[l_idx].ttrx = param[42].data.d_floatarray[l_idx]; pvals->point[l_idx].ttry = param[44].data.d_floatarray[l_idx]; pvals->point[l_idx].tblx = param[46].data.d_floatarray[l_idx]; pvals->point[l_idx].tbly = param[48].data.d_floatarray[l_idx]; pvals->point[l_idx].tbrx = param[50].data.d_floatarray[l_idx]; pvals->point[l_idx].tbry = param[52].data.d_floatarray[l_idx]; pvals->point[l_idx].sel_feather_radius = param[54].data.d_floatarray[l_idx]; } } } else { /* PLUGIN_NAME_GAP_MOVE_PATH_EXT2 operates with controlpoint file */ if(param[23].data.d_string != NULL) { pointfile = g_strdup(param[23].data.d_string); } } } } if (status == GIMP_PDB_SUCCESS) { l_rc_image = gap_mov_exec_move_path(run_mode, image_id, pvals, pointfile, l_rotation_follow, (gdouble)l_startangle); } g_free(pvals); if(pointfile != NULL) g_free(pointfile); } else if (strcmp (name, PLUGIN_NAME_GAP_RANGE_TO_MULTILAYER) == 0) { *nreturn_vals = nreturn_f2multi + 1; l_rc_image = -1; selection_mode = GAP_RANGE_OPS_SEL_IGNORE; if (run_mode == GIMP_RUN_NONINTERACTIVE) { if ((n_params != 7) && (n_params != 9) && (n_params != nargs_f2multi)) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { range_from = param[3].data.d_int32; /* frame nr to start */ range_to = param[4].data.d_int32; /* frame nr to stop */ mode = param[5].data.d_int32; /* { expand-as-necessary(0), CLIP-TO_IMG(1), CLIP-TO-BG-LAYER(2), FLATTEN(3)} */ nr = param[6].data.d_int32; /* { BG_NOT_VISIBLE (0), BG_VISIBLE(1)} */ /* old interface: use default values for framerate and frame_basename */ framerate = 50; strcpy(frame_basename, "frame"); sel_mode = GAP_MTCH_ALL_VISIBLE; sel_invert = FALSE; sel_case = TRUE; if ( n_params >= 9 ) { framerate = param[7].data.d_int32; if(param[8].data.d_string != NULL) { strncpy(frame_basename, param[8].data.d_string, FRAME_BASENAME_LEN -1); frame_basename[FRAME_BASENAME_LEN -1] = '\0'; } } if ( n_params >= 13 ) { sel_mode = param[9].data.d_int32; sel_case = param[10].data.d_int32; sel_invert = param[11].data.d_int32; if(param[12].data.d_string != NULL) { strncpy(l_sel_str, param[12].data.d_string, sizeof(l_sel_str) -1); l_sel_str[sizeof(l_sel_str) -1] = '\0'; } selection_mode = param[13].data.d_int32; } l_rc_image = gap_range_to_multilayer(run_mode, image_id, range_from, range_to, mode, nr, framerate, frame_basename, FRAME_BASENAME_LEN, sel_mode, sel_case, sel_invert, l_sel_str, selection_mode); } values[1].type = GIMP_PDB_IMAGE; values[1].data.d_int32 = l_rc_image; /* return the new generated image_id */ } else if (strcmp (name, PLUGIN_NAME_GAP_RANGE_FLATTEN) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_rflatt) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { range_from = param[3].data.d_int32; /* frame nr to start */ range_to = param[4].data.d_int32; /* frame nr to stop */ l_rc_image = gap_range_flatten(run_mode, image_id, range_from, range_to); } } else if (strcmp (name, PLUGIN_NAME_GAP_RANGE_LAYER_DEL) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_rlayerdel) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { range_from = param[3].data.d_int32; /* frame nr to start */ range_to = param[4].data.d_int32; /* frame nr to stop */ nr = param[5].data.d_int32; /* layerstack position (0 == on top) */ l_rc_image = gap_range_layer_del(run_mode, image_id, range_from, range_to, nr); } } else if ((strcmp (name, PLUGIN_NAME_GAP_RANGE_CONVERT) == 0) || (strcmp (name, PLUGIN_NAME_GAP_RANGE_CONVERT2) == 0)) { *nreturn_vals = nreturn_rconv +1; l_basename_ptr = NULL; l_palette_ptr = NULL; palette_type = GIMP_MAKE_PALETTE; alpha_dither = 0; remove_unused = 1; if (run_mode == GIMP_RUN_NONINTERACTIVE) { if ((n_params != 10) && (n_params != nargs_rconv) && (n_params != nargs_rconv2)) { status = GIMP_PDB_CALLING_ERROR; } else { strncpy(l_extension, param[9].data.d_string, sizeof(l_extension) -1); l_extension[sizeof(l_extension) -1] = '\0'; if (n_params >= 11) { l_basename_ptr = param[10].data.d_string; } if (n_params >= 15) { l_palette_ptr = param[14].data.d_string; palette_type = param[11].data.d_int32; alpha_dither = param[12].data.d_int32; remove_unused = param[13].data.d_int32; } } } if (status == GIMP_PDB_SUCCESS) { image_id = param[1].data.d_image; range_from = param[3].data.d_int32; /* frame nr to start */ range_to = param[4].data.d_int32; /* frame nr to stop */ nr = param[5].data.d_int32; /* flatten (0 == no , 1 == flatten) */ dest_type = param[6].data.d_int32; dest_colors = param[7].data.d_int32; dest_dither = param[8].data.d_int32; l_rc_image = gap_range_conv(run_mode, image_id, range_from, range_to, nr, dest_type, dest_colors, dest_dither, l_basename_ptr, l_extension, palette_type, alpha_dither, remove_unused, l_palette_ptr); } } else if (strcmp (name, PLUGIN_NAME_GAP_ANIM_RESIZE) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_resize) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { new_width = param[3].data.d_int32; new_height = param[4].data.d_int32; offs_x = param[5].data.d_int32; offs_y = param[6].data.d_int32; l_rc_image = gap_range_anim_sizechange(run_mode, GAP_ASIZ_RESIZE, image_id, new_width, new_height, offs_x, offs_y); } } else if (strcmp (name, PLUGIN_NAME_GAP_ANIM_CROP) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != 7) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { new_width = param[3].data.d_int32; new_height = param[4].data.d_int32; offs_x = param[5].data.d_int32; offs_y = param[6].data.d_int32; l_rc_image = gap_range_anim_sizechange(run_mode, GAP_ASIZ_CROP, image_id, new_width, new_height, offs_x, offs_y); } } else if (strcmp (name, PLUGIN_NAME_GAP_ANIM_SCALE) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_scale) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { new_width = param[3].data.d_int32; new_height = param[4].data.d_int32; l_rc_image = gap_range_anim_sizechange(run_mode, GAP_ASIZ_SCALE, image_id, new_width, new_height, 0, 0); } } else if (strcmp (name, PLUGIN_NAME_GAP_SPLIT) == 0) { gint32 l_digits; gint32 l_only_visible; gint32 l_copy_properties; *nreturn_vals = nreturn_split +1; l_rc_image = -1; if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_split) { status = GIMP_PDB_CALLING_ERROR; } else { strncpy(l_extension, param[5].data.d_string, sizeof(l_extension) -1); l_extension[sizeof(l_extension) -1] = '\0'; } } if (status == GIMP_PDB_SUCCESS) { inverse_order = param[3].data.d_int32; no_alpha = param[4].data.d_int32; l_only_visible= param[6].data.d_int32; l_digits = param[7].data.d_int32; l_copy_properties = param[8].data.d_int32; l_rc_image = gap_split_image(run_mode, image_id, inverse_order, no_alpha, l_extension, l_only_visible, l_copy_properties, l_digits); } /* IMAGE ID is filled at end (same as in standard return handling) */ values[1].type = GIMP_PDB_IMAGE; values[1].data.d_int32 = l_rc_image; /* return the new generated image_id */ } else if (strcmp (name, PLUGIN_NAME_GAP_SHIFT) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_shift) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { nr = param[3].data.d_int32; /* how many framenumbers to shift the framesequence */ range_from = param[4].data.d_int32; /* frame nr to start */ range_to = param[5].data.d_int32; /* frame nr to stop */ l_rc_image = gap_base_shift(run_mode, image_id, nr, range_from, range_to ); } } else if (strcmp (name, PLUGIN_NAME_GAP_REVERSE) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_shift) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { range_from = param[3].data.d_int32; /* frame nr to start */ range_to = param[4].data.d_int32; /* frame nr to stop */ l_rc_image = gap_base_reverse(run_mode, image_id, range_from, range_to ); } } else if (strcmp (name, PLUGIN_NAME_GAP_RENUMBER) == 0) { gint32 digits; digits = GAP_LIB_DEFAULT_DIGITS; if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_renumber) { status = GIMP_PDB_CALLING_ERROR; } } if (status == GIMP_PDB_SUCCESS) { nr = param[3].data.d_int32; /* new start framenumber of the 1.st frame in the framesequence */ digits = param[4].data.d_int32; /* digits to use for framenumber part in the filename(s) */ l_rc_image = gap_base_renumber(run_mode, image_id, nr, digits); } } else if (strcmp (name, PLUGIN_NAME_GAP_VIDEO_EDIT_COPY) == 0) { *nreturn_vals = nreturn_nothing +1; if (n_params != nargs_video_copy) { status = GIMP_PDB_CALLING_ERROR; } if (status == GIMP_PDB_SUCCESS) { range_from = param[3].data.d_int32; /* frame nr to start */ range_to = param[4].data.d_int32; /* frame nr to stop */ l_rc_image = gap_vid_edit_copy(run_mode, image_id, range_from, range_to ); } } else if (strcmp (name, PLUGIN_NAME_GAP_VIDEO_EDIT_PASTE) == 0) { if (n_params != nargs_video_paste) { status = GIMP_PDB_CALLING_ERROR; } if (status == GIMP_PDB_SUCCESS) { nr = param[3].data.d_int32; /* paste_mode (0,1 or 2) */ l_rc_image = gap_vid_edit_paste(run_mode, image_id, nr ); } } else if (strcmp (name, PLUGIN_NAME_GAP_VIDEO_EDIT_CLEAR) == 0) { *nreturn_vals = nreturn_nothing +1; if (status == GIMP_PDB_SUCCESS) { if(gap_vid_edit_clear() < 0) { l_rc_image = -1; } else { l_rc_image = 0; } } } else if (strcmp (name, PLUGIN_NAME_GAP_MODIFY) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_modify) { status = GIMP_PDB_CALLING_ERROR; } else { if(param[9].data.d_string != NULL) { strncpy(l_sel_str, param[9].data.d_string, sizeof(l_sel_str) -1); l_sel_str[sizeof(l_sel_str) -1] = '\0'; } if(param[10].data.d_string != NULL) { strncpy(l_layername, param[10].data.d_string, sizeof(l_layername) -1); l_layername[sizeof(l_layername) -1] = '\0'; } } } if (status == GIMP_PDB_SUCCESS) { range_from = param[3].data.d_int32; /* frame nr to start */ range_to = param[4].data.d_int32; /* frame nr to stop */ nr = param[5].data.d_int32; /* action_nr */ sel_mode = param[6].data.d_int32; sel_case = param[7].data.d_int32; sel_invert = param[8].data.d_int32; l_rc_image = gap_mod_layer(run_mode, image_id, range_from, range_to, nr, sel_mode, sel_case, sel_invert, l_sel_str, l_layername); } } /* ---------- return handling --------- */ if(l_rc_image < 0) { if(gap_debug) printf("gap_main: return GIMP_PDB_EXECUTION_ERROR\n"); status = GIMP_PDB_EXECUTION_ERROR; } else { if(gap_debug) printf("gap_main: return OK\n"); /* most gap_plug-ins return an image_id in values[1] */ if (values[1].type == GIMP_PDB_IMAGE) { if(gap_debug) printf("gap_main: return image_id:%d\n", (int)l_rc_image); values[1].data.d_int32 = l_rc_image; /* return image id of the resulting (current frame) image */ } } if (run_mode != GIMP_RUN_NONINTERACTIVE) { if(gap_debug) printf("gap_main BEFORE gimp_displays_flush\n"); gimp_displays_flush(); if(gap_debug) printf("gap_main AFTER gimp_displays_flush\n"); } values[0].data.d_status = status; /* remove LOCK on this image for all gap_plugins */ gap_lock_remove_lock(lock_image_id); } gimp-gap-2.6.0+dfsg.orig/gap/gap_bluebox_main.c0000644000175000017500000002667011212030253021166 0ustar thibautthibaut/* gap_bluebox_main.c * by hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains the GAP BlueBox Filter PDB Registration and MAIN * the Bluebox filter makes the specified color transparent. * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 1.3.23b; 2003/12/06 hof: added mode GAP_BLUBOX_THRES_ALL * gimp 1.3.20d; 2003/10/14 hof: creation */ static char *gap_bluebox_version = "1.3.23b; 2003/12/06"; /* SYTEM (UNIX) includes */ #include #include #include /* GIMP includes */ #include #include #include /* GAP includes */ #include "config.h" #include "gap-intl.h" #include "gap_lastvaldesc.h" #include "gap_bluebox.h" /* ------------------------ * gap DEBUG switch * ------------------------ */ /* int gap_debug = 1; */ /* print debug infos */ /* int gap_debug = 0; */ /* 0: dont print debug infos */ int gap_debug = 0; static GimpParamDef args_bluebox[] = { {GIMP_PDB_INT32, "run_mode", "Interactive"}, {GIMP_PDB_IMAGE, "image", "the image"}, {GIMP_PDB_DRAWABLE, "drawable", "the drawable"}, {GIMP_PDB_COLOR, "keycolor", "Select Pixels to be treansparent by this KeyColor" }, {GIMP_PDB_INT32, "thres_mode", "0 .. use the 3 threshold values for RGB\n" "1 .. use the 3 threshold values for HSV\n" "2 .. use only one simple Threshold\n" "3 .. use all 6 threshold values for HSV and RGB"}, {GIMP_PDB_FLOAT, "thres_r", "threshold value 0.0 upto 1.0 for RED value (ignored in thers_modes 1 and 2)"}, {GIMP_PDB_FLOAT, "thres_g", "threshold value 0.0 upto 1.0 for GREEN value (ignored in thers_modes 1 and 2)"}, {GIMP_PDB_FLOAT, "thres_b", "threshold value 0.0 upto 1.0 for BLUE value (ignored in thers_modes 1 and 2)"}, {GIMP_PDB_FLOAT, "thres_h", "threshold value 0.0 upto 1.0 for HUE value (ignored in thers_modes 0 and 2)"}, {GIMP_PDB_FLOAT, "thres_s", "threshold value 0.0 upto 1.0 for SATURATION value (ignored in thers_modes 0 and 2)"}, {GIMP_PDB_FLOAT, "thres_v", "threshold value 0.0 upto 1.0 for BRIGHTNESS value (ignored in thers_modes 0 and 2)"}, {GIMP_PDB_FLOAT, "thres", "threshold value 0.0 upto 1.0 (ignored in thers_modes 0, 1 and 3)"}, {GIMP_PDB_FLOAT, "tolerance", "alpha tolerance value 0.0 upto 1.0\n" "0.0 makes hard pixel selection by color threshold(s)\n" "greater values allow more or less variable Alpha Values\n" "for the selected Pixels within the threshold(s)\n" "depending on their difference to the keycolor"}, {GIMP_PDB_INT32, "grow", "Grow the Selection in Pixels (negative values for shrinking the selection)"}, {GIMP_PDB_INT32, "feather_edges", "TRUE: feather edges using feather_radius, FALSE: sharp edges (do not blur the selection)"}, {GIMP_PDB_FLOAT, "feather_radius", "Feather Radius (makes the selection smooth)"}, {GIMP_PDB_FLOAT, "source_alpha", "Select only pixelswith alpha >= source_alpha\n" " where (0.0 is full transparent, 1.0 is full opaque)"}, {GIMP_PDB_FLOAT, "target_alpha", "Control the Alpha Value for the Selected Pixels\n" "(0.0 is full transparent, 1.0 is full opaque)"}, }; /* ----------------------- * procedure declarations * ----------------------- */ static void query(void); static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; /* ------------------------ * MAIN, query & run * ------------------------ */ MAIN () /* --------------------------------- * query * --------------------------------- */ static void query () { static GapBlueboxVals bbox_vals; /* this structure is only used as structure model * for common iterator procedure registration */ static GimpLastvalDef lastvals[] = { GIMP_LASTVALDEF_GIMPRGB (GIMP_ITER_TRUE, bbox_vals.keycolor, "keycolor"), GIMP_LASTVALDEF_ENUM (GIMP_ITER_FALSE, bbox_vals.thres_mode, "thres_mode"), GIMP_LASTVALDEF_GDOUBLE (GIMP_ITER_TRUE, bbox_vals.thres_r, "thres_r"), GIMP_LASTVALDEF_GDOUBLE (GIMP_ITER_TRUE, bbox_vals.thres_g, "thres_g"), GIMP_LASTVALDEF_GDOUBLE (GIMP_ITER_TRUE, bbox_vals.thres_b, "thres_b"), GIMP_LASTVALDEF_GDOUBLE (GIMP_ITER_TRUE, bbox_vals.thres_h, "thres_h"), GIMP_LASTVALDEF_GDOUBLE (GIMP_ITER_TRUE, bbox_vals.thres_s, "thres_s"), GIMP_LASTVALDEF_GDOUBLE (GIMP_ITER_TRUE, bbox_vals.thres_v, "thres_v"), GIMP_LASTVALDEF_GDOUBLE (GIMP_ITER_TRUE, bbox_vals.thres, "thres"), GIMP_LASTVALDEF_GDOUBLE (GIMP_ITER_TRUE, bbox_vals.tolerance, "tolerance"), GIMP_LASTVALDEF_GDOUBLE (GIMP_ITER_TRUE, bbox_vals.grow, "grow"), GIMP_LASTVALDEF_GINT (GIMP_ITER_TRUE, bbox_vals.feather_edges, "feather_edges"), GIMP_LASTVALDEF_GDOUBLE (GIMP_ITER_TRUE, bbox_vals.feather_radius, "feather_radius"), GIMP_LASTVALDEF_GDOUBLE (GIMP_ITER_TRUE, bbox_vals.source_alpha, "source_alpha"), GIMP_LASTVALDEF_GDOUBLE (GIMP_ITER_TRUE, bbox_vals.target_alpha, "target_alpha"), }; static GimpParamDef *return_vals = NULL; static int nreturn_vals = 0; gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); /* registration for last values buffer structure (useful for animated filter apply) */ gimp_lastval_desc_register(GAP_BLUEBOX_PLUGIN_NAME, &bbox_vals, sizeof(bbox_vals), G_N_ELEMENTS (lastvals), lastvals); gimp_install_procedure(GAP_BLUEBOX_PLUGIN_NAME, "The bluebox effectfilter makes the specified color transparent", "This plug-in selects pixels in the specified drawable by keycolor " "and makes the Selected Pixels transparent. " "If there is a selection at calling time, then operate only " "on Pixels that are already selected (where selection value is > 0) " "The Slection by color follows threshold values " "The thresholds operate on RGB or HSV colormodel, " "depending on the thres_mode parameter. " "The selection by keycolor can be smoothed (by feather_radius) " "and/or extended by a grow value.", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", gap_bluebox_version, N_("Bluebox ..."), "RGB*", GIMP_PLUGIN, G_N_ELEMENTS (args_bluebox), nreturn_vals, args_bluebox, return_vals); //gimp_plugin_menu_branch_register("", "Video"); gimp_plugin_menu_register (GAP_BLUEBOX_PLUGIN_NAME, N_("/Video/")); } /* end query */ /* --------------------------------- * run * --------------------------------- */ static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals) { const gchar *l_env; static GimpParam values[2]; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; GapBlueboxGlobalParams *bbp; gint32 l_rc; *nreturn_vals = 1; *return_vals = values; l_rc = 0; INIT_I18N(); l_env = g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } bbp = gap_bluebox_bbp_new(param[2].data.d_drawable); run_mode = param[0].data.d_int32; bbp->run_mode = param[0].data.d_int32; bbp->image_id = param[1].data.d_image; gimp_image_undo_group_start (bbp->image_id); gap_bluebox_init_default_vals(bbp); if(gap_debug) printf("\n\ngap_bluebox main: debug name = %s\n", name); if (strcmp (name, GAP_BLUEBOX_PLUGIN_NAME) == 0) { switch (run_mode) { case GIMP_RUN_INTERACTIVE: { /* Possibly retrieve data */ gimp_get_data (GAP_BLUEBOX_DATA_KEY_VALS, &bbp->vals); l_rc = gap_bluebox_dialog(bbp); if(l_rc < 0) { status = GIMP_PDB_CANCEL; } } break; case GIMP_RUN_NONINTERACTIVE: { if (n_params != G_N_ELEMENTS (args_bluebox)) { status = GIMP_PDB_CALLING_ERROR; } else { bbp->vals.keycolor = param[3].data.d_color; bbp->vals.thres_mode = param[4].data.d_int32; bbp->vals.thres_r = param[5].data.d_float; bbp->vals.thres_g = param[6].data.d_float; bbp->vals.thres_b = param[7].data.d_float; bbp->vals.thres_h = param[8].data.d_float; bbp->vals.thres_s = param[9].data.d_float; bbp->vals.thres_v = param[10].data.d_float; bbp->vals.thres = param[11].data.d_float; bbp->vals.tolerance = param[12].data.d_float; bbp->vals.grow = (gdouble)param[13].data.d_int32; bbp->vals.feather_edges = param[14].data.d_int32; bbp->vals.feather_radius = param[15].data.d_float; bbp->vals.source_alpha = param[16].data.d_float; bbp->vals.target_alpha = param[17].data.d_float; bbp->run_flag = TRUE; } } break; case GIMP_RUN_WITH_LAST_VALS: { /* Possibly retrieve data */ gimp_get_data (GAP_BLUEBOX_DATA_KEY_VALS, &bbp->vals); bbp->run_flag = TRUE; } break; default: break; } } if(status == GIMP_PDB_SUCCESS) { bbp->layer_id = bbp->drawable_id; l_rc = gap_bluebox_apply(bbp); if(l_rc < 0) { status = GIMP_PDB_EXECUTION_ERROR; } else { gimp_set_data (GAP_BLUEBOX_DATA_KEY_VALS, &bbp->vals, sizeof (bbp->vals)); } } gimp_image_undo_group_end (bbp->image_id); /* ---------- return handling --------- */ values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; } /* end run */ gimp-gap-2.6.0+dfsg.orig/gap/gap_story_vthumb.c0000644000175000017500000010134011212030253021253 0ustar thibautthibaut/* gap_story_vthumb.h * * This module handles GAP storyboard dialog video thumbnail (vthumb) * processing. This includes videofile access via API and/or * via storyboard render processor. * video thumbnails are thumbnails of relevant frames (typically * the first referenced framenumber in a video, section or anim image) * * procedures for handling the list of video resources and video thumbnails * are implemented in this module. */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.26a; 2007/10/06 hof: created */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "gap_libgapbase.h" #include "gap_story_main.h" #include "gap_story_dialog.h" #include "gap_story_file.h" #include "gap_arr_dialog.h" #include "gap_story_render_processor.h" #include "gap_story_vthumb.h" #include "gap-intl.h" extern int gap_debug; /* 1 == print debug infos , 0 dont print debug infos */ /* global_stb_video_id is used to generate non-persistent unique video_id's per session */ static gint32 global_stb_video_id = 0; static void p_debug_print_vthumbs_refering_video_id( GapVThumbElem *vthumb_list , gint32 video_id ); static gboolean p_vid_progress_callback(gdouble progress ,gpointer user_data ); static GapStoryVTResurceElem * p_new_velem(GapStoryVthumbEnum vt_type); static GapVThumbElem * p_new_vthumb(gint32 video_id ,gint32 framenr ,guchar *th_data ,gint32 th_width ,gint32 th_height ,gint32 th_bpp ); /* --------------------------------------- * p_debug_print_vthumbs_refering_video_id * --------------------------------------- * print the list of video elements * to stdout (typical used for logging and debug purpose) */ static void p_debug_print_vthumbs_refering_video_id(GapVThumbElem *vthumb_list, gint32 video_id) { GapVThumbElem *vthumb_elem; printf(" vthumbs: ["); for(vthumb_elem = vthumb_list; vthumb_elem != NULL; vthumb_elem = vthumb_elem->next) { if(vthumb_elem->video_id == video_id) { printf(" %06d", (int)vthumb_elem->framenr); } } printf("]\n"); } /* end p_debug_print_vthumbs_refering_video_id */ /* -------------------------------------- * gap_story_vthumb_debug_print_videolist * -------------------------------------- * print the list of video elements * to stdout (typical used for logging and debug purpose) */ void gap_story_vthumb_debug_print_videolist(GapStoryVTResurceElem *video_list, GapVThumbElem *vthumb_list) { GapStoryVTResurceElem *velem; gint ii; printf("gap_story_vthumb_debug_print_videolist: START\n"); ii = 0; for(velem=video_list; velem != NULL; velem = velem->next) { const char *filename; printf(" [%03d] ", (int)ii); switch(velem->vt_type) { case GAP_STB_VLIST_MOVIE: printf("GAP_STB_VLIST_MOVIE:"); break; case GAP_STB_VLIST_SECTION: printf("GAP_STB_VLIST_SECTION: section_id:%d" , (int)velem->section_id ); break; case GAP_STB_VLIST_ANIM_IMAGE: printf("GAP_STB_VLIST_ANIM_IMAGE:"); break; default: printf("** Type Unknown **:"); break; } if (velem->video_filename != NULL) { filename = velem->video_filename; } else { filename = "(null)"; } printf(" total_frames:%d version:%d video_id:%d name:%s\n" , (int)velem->total_frames , (int)velem->version , (int)velem->video_id , filename ); if (vthumb_list != NULL) { p_debug_print_vthumbs_refering_video_id(vthumb_list, velem->video_id); } ii++; } printf("gap_story_vthumb_debug_print_videolist: END\n"); } /* end gap_story_vthumb_debug_print_videolist */ /* -------------------------------- * p_vid_progress_callback * -------------------------------- * return: TRUE: cancel videoapi immediate * FALSE: continue */ static gboolean p_vid_progress_callback(gdouble progress ,gpointer user_data ) { GapStbMainGlobalParams *sgpp; sgpp = (GapStbMainGlobalParams *)user_data; if(sgpp == NULL) { return (TRUE); } if(sgpp->progress_bar_sub == NULL) { return (TRUE); } gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(sgpp->progress_bar_sub), progress); gap_story_vthumb_g_main_context_iteration(sgpp); return(sgpp->cancel_video_api); /* return (TRUE); */ /* cancel video api if playback was stopped */ } /* end p_vid_progress_callback */ /* --------------------------------------- * gap_story_vthumb_g_main_context_iteration * --------------------------------------- * refresh widget processing * and lock video api during the refresh. * (to ensure the current video access is not interrupted * by any other video access attempts) */ void gap_story_vthumb_g_main_context_iteration(GapStbMainGlobalParams *sgpp) { gboolean old_gva_lock; old_gva_lock = sgpp->gva_lock; sgpp->gva_lock = TRUE; /* g_main_context_iteration makes sure that * gtk does refresh widgets, and react on events while the videoapi * is busy with searching for the next frame. * But hold gva_lock while processing. */ while(g_main_context_iteration(NULL, FALSE)); sgpp->gva_lock = old_gva_lock; } /* end gap_story_vthumb_g_main_context_iteration */ /* -------------------------------- * gap_story_vthumb_close_videofile * -------------------------------- */ void gap_story_vthumb_close_videofile(GapStbMainGlobalParams *sgpp) { #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if(sgpp->gvahand) { if(sgpp->gva_videofile) g_free(sgpp->gva_videofile); GVA_close(sgpp->gvahand); sgpp->gvahand = NULL; sgpp->gva_videofile = NULL; } #endif } /* end gap_story_vthumb_close_videofile */ /* -------------------------------- * gap_story_vthumb_open_videofile * -------------------------------- */ void gap_story_vthumb_open_videofile(GapStbMainGlobalParams *sgpp , const char *filename , gint32 seltrack , const char *preferred_decoder ) { #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT gboolean vindex_permission; gboolean l_have_valid_vindex; char *vindex_file; char *create_vindex_msg; if(gap_debug) { printf("gap_story_vthumb_open_videofile %s\n", filename); } gap_story_vthumb_close_videofile(sgpp); vindex_file = NULL; create_vindex_msg = NULL; sgpp->gvahand = GVA_open_read_pref(filename , seltrack , 1 /* aud_track */ , preferred_decoder , FALSE /* use MMX if available (disable_mmx == FALSE) */ ); if(sgpp->gvahand) { sgpp->gva_videofile = g_strdup(filename); /* sgpp->gvahand->emulate_seek = TRUE; */ sgpp->gvahand->do_gimp_progress = FALSE; sgpp->gvahand->progress_cb_user_data = sgpp; sgpp->gvahand->fptr_progress_callback = p_vid_progress_callback; /* set decoder name as progress idle text */ { t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)sgpp->gvahand->dec_elem; if(dec_elem->decoder_name) { create_vindex_msg = g_strdup_printf(_("Creating Index (decoder: %s)"), dec_elem->decoder_name); vindex_file = GVA_build_videoindex_filename(sgpp->gva_videofile ,1 /* track */ ,dec_elem->decoder_name ); } else { create_vindex_msg = g_strdup_printf(_("Creating Index")); } } sgpp->cancel_video_api = FALSE; l_have_valid_vindex = FALSE; vindex_permission = FALSE; if(sgpp->gvahand->vindex) { if(sgpp->gvahand->vindex->total_frames > 0) { l_have_valid_vindex = TRUE; } } if(l_have_valid_vindex == FALSE) { t_GVA_SeekSupport seekSupp; seekSupp = GVA_check_seek_support(sgpp->gvahand); /* check for permission to create a videoindex file */ vindex_permission = gap_arr_create_vindex_permission(sgpp->gva_videofile , vindex_file , (gint32)seekSupp ); } if((l_have_valid_vindex == FALSE) && (vindex_permission)) { if(gap_debug) { printf("STORY: DEBUG: create vidindex start\n"); } if(sgpp->progress_bar_sub) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sgpp->progress_bar_sub), create_vindex_msg); } sgpp->gvahand->create_vindex = TRUE; GVA_count_frames(sgpp->gvahand); if(gap_debug) { printf("STORY: DEBUG: create vidindex done\n"); } } if(sgpp->progress_bar_sub) { gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(sgpp->progress_bar_sub), 0.0); if(sgpp->cancel_video_api) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sgpp->progress_bar_sub) ,_("Canceled")); } else { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sgpp->progress_bar_sub), " "); } } if(vindex_file) { g_free(vindex_file); } if(create_vindex_msg) { g_free(create_vindex_msg); } } #endif } /* end gap_story_vthumb_open_videofile */ /* -------------------------------- * p_new_velem * -------------------------------- */ static GapStoryVTResurceElem * p_new_velem(GapStoryVthumbEnum vt_type) { GapStoryVTResurceElem *velem; velem = g_new(GapStoryVTResurceElem, 1); if(velem == NULL) { return (NULL); } velem->vt_type = vt_type; velem->version = 0; velem->section_id = -1; velem->video_id = global_stb_video_id++; velem->seltrack = 1; velem->video_filename = NULL; velem->total_frames = 0; velem->next = NULL; return (velem); } /* end p_new_velem */ /* -------------------------------- * p_new_vthumb * -------------------------------- */ GapVThumbElem * p_new_vthumb(gint32 video_id ,gint32 framenr ,guchar *th_data ,gint32 th_width ,gint32 th_height ,gint32 th_bpp ) { GapVThumbElem *vthumb; vthumb = g_new(GapVThumbElem ,1); if(vthumb) { vthumb->video_id = video_id; vthumb->th_data = th_data; vthumb->th_width = th_width; vthumb->th_height = th_height; vthumb->th_bpp = th_bpp; vthumb->framenr = framenr; vthumb->next = NULL; } return(vthumb); } /* end p_new_vthumb */ /* -------------------------------- * gap_story_vthumb_add_vthumb * -------------------------------- * create a new vthumb element with the specified * values and link it at begin of the sgpp->vthumb_list. * returns the newly created element. */ GapVThumbElem * gap_story_vthumb_add_vthumb(GapStbMainGlobalParams *sgpp ,gint32 framenr ,guchar *th_data ,gint32 th_width ,gint32 th_height ,gint32 th_bpp ,gint32 video_id ) { GapVThumbElem *vthumb; vthumb = p_new_vthumb(video_id , framenr , th_data , th_width , th_height , th_bpp ); if(vthumb) { /* link the new element as 1st into the list */ vthumb->next = sgpp->vthumb_list; sgpp->vthumb_list = vthumb; } return(vthumb); } /* end gap_story_vthumb_add_vthumb */ /* -------------------------------- * gap_story_vthumb_get_velem_movie * -------------------------------- * search the Videofile List * for a matching Videofile element * IF FOUND: return pointer to that element * ELSE: try to create a Videofile Element and return * pointer to the newly created Element * or NULL if no Element could be created. * * DO NOT g_free the returned Element ! * it is just a reference to the original List * and should be kept until the program (The Storyboard Plugin) exits. */ GapStoryVTResurceElem * gap_story_vthumb_get_velem_movie(GapStbMainGlobalParams *sgpp ,const char *video_filename ,gint32 seltrack ,const char *preferred_decoder ) { GapStoryVTResurceElem *velem; if(sgpp == NULL) { return (NULL); } /* check for known video_filenames */ for(velem = sgpp->video_list; velem != NULL; velem = (GapStoryVTResurceElem *)velem->next) { if((strcmp(velem->video_filename, video_filename) == 0) && (seltrack == velem->seltrack) && (velem->vt_type == GAP_STB_VLIST_MOVIE)) { return(velem); } } #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if(!sgpp->auto_vthumb) { return(NULL); } if(sgpp->auto_vthumb_refresh_canceled) { return(NULL); } gap_story_vthumb_open_videofile(sgpp, video_filename, seltrack, preferred_decoder); if(sgpp->gvahand) { /* video_filename is new, add a new element */ velem = p_new_velem(GAP_STB_VLIST_MOVIE); if(velem == NULL) { return (NULL); } velem->seltrack = seltrack; velem->video_filename = g_strdup(video_filename); velem->total_frames = sgpp->gvahand->total_frames; if(!sgpp->gvahand->all_frames_counted) { /* frames are not counted yet, * and the total_frames information is just a guess * in this case we assume 10 times more frames */ velem->total_frames *= 10; } velem->next = sgpp->video_list; sgpp->video_list = velem; } #endif return(velem); } /* end gap_story_vthumb_get_velem_movie */ /* ----------------------------------- * gap_story_vthumb_get_velem_no_movie * ----------------------------------- * search the Videofile List * for a matching Videofile element of types * GAP_STB_VLIST_SECTION and * GAP_STB_VLIST_ANIM_IMAGE * * Note that velem elements must match in name and version. * * IF FOUND: return pointer to that element * ELSE: try to create a Videofile Element and return * pointer to the newly created Element * or NULL if no Element could be created. * * DO NOT g_free the returned Element ! * it is just a reference to the original List * and should be kept until the program (The Storyboard Plugin) exits. */ GapStoryVTResurceElem * gap_story_vthumb_get_velem_no_movie(GapStbMainGlobalParams *sgpp ,GapStoryBoard *stb ,GapStoryElem *stb_elem ) { GapStoryVTResurceElem *velem; GapStorySection *referenced_section; GapStoryVthumbEnum vt_type; gint32 section_id; gint32 version; const char *name; if((sgpp == NULL) || (stb_elem == NULL)) { return (NULL); } referenced_section = NULL; section_id = -1; switch(stb_elem->record_type) { case GAP_STBREC_VID_SECTION: vt_type = GAP_STB_VLIST_SECTION; name = stb_elem->orig_filename; /* the referenced section_name */ if (name == NULL) { /* no sub section_name reference available * no processing possible */ return(NULL); } referenced_section = gap_story_find_section_by_name(stb, name); if (referenced_section == NULL) { /* sub section_name reference refers to invalid section * no processing possible */ return(NULL); } version = referenced_section->version; section_id = referenced_section->section_id; /* check for known section respecting section_id and version */ for(velem = sgpp->video_list; velem != NULL; velem = (GapStoryVTResurceElem *)velem->next) { if((section_id == velem->section_id) && (version == velem->version) && (velem->vt_type == GAP_STB_VLIST_SECTION)) { return(velem); } } break; case GAP_STBREC_VID_ANIMIMAGE: vt_type = GAP_STB_VLIST_ANIM_IMAGE; name = stb_elem->orig_filename; /* name of anim_image file */; version = gap_file_get_mtime(name); /* check for known anim images respecting filename and mtime version */ for(velem = sgpp->video_list; velem != NULL; velem = (GapStoryVTResurceElem *)velem->next) { if((strcmp(velem->video_filename, name) == 0) && (version == velem->version) && (velem->vt_type == GAP_STB_VLIST_ANIM_IMAGE)) { return(velem); } } break; default: return (NULL); break; } if(!sgpp->auto_vthumb) { return(NULL); } /* vt_type/name/version combination is new, add a new element */ velem = p_new_velem(vt_type); if(velem == NULL) { return (NULL); } velem->version = version; velem->video_filename = g_strdup(name); velem->section_id = section_id; if(stb_elem->record_type == GAP_STBREC_VID_SECTION) { velem->total_frames = stb_elem->nframes; velem->total_frames = gap_story_count_total_frames_in_section(referenced_section); } velem->next = sgpp->video_list; sgpp->video_list = velem; return(velem); } /* end gap_story_vthumb_get_velem_no_movie */ /* ------------------------------------- * gap_story_vthumb_create_generic_vthumb * ------------------------------------- * Create a thumbnail for the framenumber in the specified clip (via stb_elem) * * * return thdata pointer or NULL * create vthumb via storyboard render processor. * typical this is used only for storyboard element types: * (stb_elem->record_type == GAP_STBREC_VID_ANIMIMAGE) * (stb_elem->record_type == GAP_STBREC_VID_SECTION) * * Note that movie clips are handled separately * for performance reasons. * Single Images and frame images * use persistent thumbnails (open thumbnail standard), * and therefore are not present as vthumb at all. */ guchar * gap_story_vthumb_create_generic_vthumb(GapStbMainGlobalParams *sgpp , GapStoryBoard *stb , GapStorySection *section , GapStoryElem *stb_elem , gint32 framenumber , gint32 *th_bpp , gint32 *th_width , gint32 *th_height , gboolean do_scale ) { guchar *th_data; GapStoryBoard *stb_dup; GapStoryRenderVidHandle *stb_comp_vidhand; gint32 target_framenumber; gint32 l_total_framecount; th_data = NULL; #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if(gap_story_elem_is_video(stb_elem) != TRUE) { return (NULL); } target_framenumber = 1 + (framenumber - stb_elem->from_frame); /* create a duplicate of the storyboard that has * just one element (with the specified story_id) * in its main section. */ // TODO set vtrack number in the duplicated element to 1 ? // maybe not important because rendering of one element with another track number // shall give the same result. if(stb_elem->track == GAP_STB_MASK_TRACK_NUMBER) { /* we are rendering a mask_definition clip */ stb_dup = gap_story_duplicate_one_elem(stb, stb->mask_section, stb_elem->story_id); } else { /* we are rendering a non-mask clip, therefore include * all potential mask referneces */ stb_dup = gap_story_duplicate_one_elem_and_masks(stb, section, stb_elem->story_id); } if (stb_elem->record_type == GAP_STBREC_VID_SECTION) { /* to render a section clip we must include the refered subsection * (this implementation includes all subsections) */ gap_story_copy_sub_sections(stb, stb_dup); } if(gap_debug) { printf("VTHUMB by RENDER_PROCESSOR START gap_story_vthumb_create_generic_vthumb\n"); printf(" framenumber: %d target_framenumber: %d\n" ,(int)framenumber ,(int)target_framenumber ); printf("The CLIP to be rendered as vthumb:\n"); gap_story_debug_print_elem(stb_elem); printf("\nThe final duplicated storyboard: stb_dup\n"); gap_story_debug_print_list(stb_dup); printf("VTHUMB by RENDER_PROCESSOR END\n"); } stb_comp_vidhand = gap_story_render_open_vid_handle_from_stb (stb_dup ,&l_total_framecount ); if (stb_comp_vidhand != NULL) { gint32 vthumb_size; vthumb_size = 256; if(stb->master_width > stb->master_height) { *th_width = vthumb_size; *th_height = (stb->master_height * vthumb_size) / stb->master_width; } else { *th_height = vthumb_size; *th_width = (stb->master_width * vthumb_size) / stb->master_height; } stb_comp_vidhand->master_width = *th_width; stb_comp_vidhand->master_height = *th_height; *th_bpp = 3; th_data = gap_story_render_fetch_composite_vthumb(stb_comp_vidhand , target_framenumber , *th_width , *th_height ); gap_story_render_close_vid_handle(stb_comp_vidhand); } #endif return (th_data); } /* end gap_story_vthumb_create_generic_vthumb */ /* --------------------------------- * p_story_vthumb_elem_fetch * --------------------------------- * search the Video Thumbnail List * for a matching Thumbnail element. * supports videofile, anim-image and sub-section resources. * * IF FOUND: return pointer to that element * ELSE: try to create a Thumbnail Element and return * pointer to the newly created Element * or NULL if no Element could be created. * * DO NOT g_free the returned Element ! * it is just a reference to the original List * and should be kept until the program (The Storyboard Plugin) exits. */ static GapVThumbElem * p_story_vthumb_elem_fetch(GapStbMainGlobalParams *sgpp ,GapStoryBoard *stb ,GapStoryElem *stb_elem ,gint32 framenr ,gint32 seltrack ,const char *preferred_decoder ,gboolean trigger_prefetch_restart_flag ) { GapStoryVTResurceElem *velem; GapVThumbElem *vthumb; guchar *th_data; gint32 th_width; gint32 th_height; gint32 th_bpp; const char *video_filename; if(sgpp == NULL) { return (NULL); } if(trigger_prefetch_restart_flag == TRUE) { if(sgpp->vthumb_prefetch_in_progress != GAP_VTHUMB_PREFETCH_NOT_ACTIVE) { /* at this point an implicite cancel of video thumbnail prefetch * is detected. */ if(gap_debug) { printf("p_story_vthumb_elem_fetch TRIGGER condition for vthumb prefetch restart occured\n"); } sgpp->vthumb_prefetch_in_progress = GAP_VTHUMB_PREFETCH_RESTART_REQUEST; return (NULL); } } th_data = NULL; velem = NULL; video_filename = NULL; switch(stb_elem->record_type) { case GAP_STBREC_VID_MOVIE: video_filename = stb_elem->orig_filename; velem = gap_story_vthumb_get_velem_movie(sgpp ,video_filename ,seltrack ,preferred_decoder ); break; case GAP_STBREC_VID_SECTION: case GAP_STBREC_VID_ANIMIMAGE: velem = gap_story_vthumb_get_velem_no_movie(sgpp ,stb ,stb_elem ); break; default: return (NULL); break; } if(velem == NULL) { return (NULL); } /* check for known viedo_thumbnails */ for(vthumb = sgpp->vthumb_list; vthumb != NULL; vthumb = (GapVThumbElem *)vthumb->next) { if((velem->video_id == vthumb->video_id) && (framenr == vthumb->framenr)) { /* we found the wanted video thumbnail */ return(vthumb); } } if(!sgpp->auto_vthumb) { return(NULL); } if(sgpp->auto_vthumb_refresh_canceled) { return(NULL); } /* Videothumbnail not known yet, * we try to create it now */ switch(velem->vt_type) { case GAP_STB_VLIST_MOVIE: /* Fetch the wanted Frame from the Videofile */ th_data = gap_story_dlg_fetch_videoframe(sgpp , video_filename , framenr , seltrack , preferred_decoder , 1.5 /* delace */ , &th_bpp , &th_width , &th_height , TRUE /* do scale */ ); break; default: /* Fetch the wanted Frame by calling the storyboard render processor */ if(framenr <= velem->total_frames) { th_data = gap_story_vthumb_create_generic_vthumb(sgpp ,stb ,stb->active_section ,stb_elem ,framenr ,&th_bpp ,&th_width ,&th_height , TRUE /* do scale */ ); } break; } if(th_data == NULL ) { return (NULL); } /* add new vthumb elem to the global list of vthumb elements */ vthumb = gap_story_vthumb_add_vthumb(sgpp ,framenr ,th_data ,th_width ,th_height ,th_bpp ,velem->video_id ); return(vthumb); } /* end p_story_vthumb_elem_fetch */ /* --------------------------------- * gap_story_vthumb_elem_fetch * --------------------------------- * search the Video Thumbnail List * for a matching Thumbnail element. * supports videofile, anim-image and sub-section resources. * * IF FOUND: return pointer to that element * ELSE: try to create a Thumbnail Element and return * pointer to the newly created Element * or NULL if no Element could be created. * * DO NOT g_free the returned Element ! * it is just a reference to the original List * and should be kept until the program (The Storyboard Plugin) exits. * * IMPORTANT: Note that this procedure is intended to use for vthumb prefetch purpose, * and shall not be used for fetching vthumbs in other situations, * because it does NOT retrigger prefetch restart, and may laed to wrong results and/or crash * when called while vthumb prefetch is in progress. */ GapVThumbElem * gap_story_vthumb_elem_fetch(GapStbMainGlobalParams *sgpp ,GapStoryBoard *stb ,GapStoryElem *stb_elem ,gint32 framenr ,gint32 seltrack ,const char *preferred_decoder ) { return(p_story_vthumb_elem_fetch(sgpp ,stb ,stb_elem ,framenr ,seltrack ,preferred_decoder ,FALSE /* trigger_prefetch_restart_flag */ )); } /* end gap_story_vthumb_elem_fetch */ /* ------------------------------ * gap_story_vthumb_fetch_thdata * ------------------------------ * RETURN a copy of the videothumbnail data * or NULL if fetch was not successful * the caller is responsible to g_free the returned data * after usage. */ guchar * gap_story_vthumb_fetch_thdata(GapStbMainGlobalParams *sgpp ,GapStoryBoard *stb ,GapStoryElem *stb_elem ,gint32 framenr ,gint32 seltrack ,const char *preferred_decoder , gint32 *th_bpp , gint32 *th_width , gint32 *th_height ) { GapVThumbElem *vthumb; guchar *th_data; th_data = NULL; vthumb = p_story_vthumb_elem_fetch(sgpp ,stb ,stb_elem ,framenr ,seltrack ,preferred_decoder ,TRUE /* trigger_prefetch_restart_flag */ ); if(vthumb) { gint32 th_size; th_size = vthumb->th_width * vthumb->th_height * vthumb->th_bpp; th_data = g_malloc(th_size); if(th_data) { memcpy(th_data, vthumb->th_data, th_size); *th_width = vthumb->th_width; *th_height = vthumb->th_height; *th_bpp = vthumb->th_bpp; } } return(th_data); } /* end gap_story_vthumb_fetch_thdata */ /* -------------------------------------- * gap_story_vthumb_fetch_thdata_no_store * -------------------------------------- * RETURN a pointer of the videothumbnail data * or thumbnail data read from file (indicated by file_read_flag = TRUE) * the caller must g_free the returned data if file_read_flag = TRUE * but MUST NOT g_free the returned data if file_read_flag = FALSE * * the video_id (identifier of the videofile in the video files list) * is passed in the output parameter video_id * * NOTE: this variant of vthumb fetching does NOT store * newly created vthumbs in the vthumb list. * it is intended for use in properties dialog at split scene * feature, where all frames of a (long) viedo clip are shown * in sequence and storing all of them would fill up the memory * with a lot of frames that are not wanted in the vthumb list. * (The vthumb lists main purpose is quick access to start frames * of all clips in the storyboard for quick rendering of thumbnails) */ guchar * gap_story_vthumb_fetch_thdata_no_store(GapStbMainGlobalParams *sgpp ,GapStoryBoard *stb ,GapStoryElem *stb_elem ,gint32 framenr ,gint32 seltrack ,const char *preferred_decoder , gint32 *th_bpp , gint32 *th_width , gint32 *th_height , gboolean *file_read_flag , gint32 *video_id ) { GapStoryVTResurceElem *velem; GapVThumbElem *vthumb; guchar *th_data; const char *video_filename; if(sgpp == NULL) { return (NULL); } video_filename = stb_elem->orig_filename; *video_id = -1; *file_read_flag = FALSE; velem = gap_story_vthumb_get_velem_movie(sgpp ,video_filename ,seltrack ,preferred_decoder ); if(velem == NULL) { return (NULL); } *video_id = velem->video_id; /* check for known viedo_thumbnails */ for(vthumb = sgpp->vthumb_list; vthumb != NULL; vthumb = (GapVThumbElem *)vthumb->next) { if((velem->video_id == vthumb->video_id) && (framenr == vthumb->framenr)) { /* we found the wanted video thumbnail */ *th_width = vthumb->th_width; *th_height = vthumb->th_height; *th_bpp = vthumb->th_bpp; return(vthumb->th_data); } } if(!sgpp->auto_vthumb) { return(NULL); } if(sgpp->vthumb_prefetch_in_progress != GAP_VTHUMB_PREFETCH_NOT_ACTIVE) { /* at this point an implicite cancel of video thumbnail prefetch * is detected. * - one option is to render default icon, and restert the prefetch * via GAP_VTHUMB_PREFETCH_RESTART_REQUEST * (because the storyboard may have changed since prefetch was started * note that prefetch will be very quick for all clips where vthumb is already present * from the cancelled previous prefetch cycle) * - an other (not implemented) option is to cancel prefetch and implicite turn off auto_vthumb mode */ sgpp->vthumb_prefetch_in_progress = GAP_VTHUMB_PREFETCH_RESTART_REQUEST; return (NULL); } /* Videothumbnail not known yet, * we try to create it now * (but dont add it tho global vthumb list) */ /* Fetch the wanted Frame from the Videofile */ th_data = gap_story_dlg_fetch_videoframe(sgpp , video_filename , framenr , seltrack , preferred_decoder , 1.5 /* delace */ , th_bpp , th_width , th_height , TRUE /* do_scale */ ); *file_read_flag = TRUE; return(th_data); } /* end gap_story_vthumb_fetch_thdata_no_store */ gimp-gap-2.6.0+dfsg.orig/gap/gap_story_render_audio.h0000644000175000017500000000616111212030253022420 0ustar thibautthibaut/* gap_story_render_audio.h * * GAP storyboard rendering processor. * */ /* * 2006.06.25 hof - created (moved stuff from the former gap_gve_story modules to this new module) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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_STORY_RENDER_AUDIO_H #define GAP_STORY_RENDER_AUDIO_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 #include "gap_story_file.h" #include "gap_lib_common_defs.h" #include "gap_story_render_processor.h" void gap_story_render_audio_calculate_playtime(GapStoryRenderVidHandle *vidhand, gdouble *aud_total_sec); gboolean gap_story_render_audio_create_composite_audiofile(GapStoryRenderVidHandle *vidhand , char *comp_audiofile ); GapStoryRenderAudioRangeElem * gap_story_render_audio_new_audiorange_element(GapStoryRenderAudioType aud_type ,gint32 track ,const char *audiofile ,gint32 master_samplerate ,gdouble play_from_sec ,gdouble play_to_sec ,gdouble volume_start ,gdouble volume ,gdouble volume_end ,gdouble fade_in_sec ,gdouble fade_out_sec ,char *util_sox ,char *util_sox_options ,const char *storyboard_file /* IN: NULL if no storyboard file is used */ ,const char *preferred_decoder ,GapStoryRenderAudioRangeElem *known_aud_list /* NULL or list of already known ranges */ ,GapStoryRenderErrors *sterr /* element to store Error/Warning report */ ,gint32 seltrack /* IN: select audiotrack number 1 upto 99 for GAP_AUT_MOVIE */ ,gboolean create_audio_tmp_files ,gdouble min_play_sec ,gdouble max_play_sec ,GapStoryRenderVidHandle *vidhand /* for progress */ ); void gap_story_render_audio_add_aud_list(GapStoryRenderVidHandle *vidhand, GapStoryRenderAudioRangeElem *aud_elem); #endif /* GAP_STORY_RENDER_AUDIO_H */ gimp-gap-2.6.0+dfsg.orig/gap/gap_frame_fetcher.c0000644000175000017500000006714411212030253021315 0ustar thibautthibaut/* 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. * (those cached images are marked with an image parasite) * * 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 multithread save ! * (the procedures may drop cached images that are still in use by a concurrent thread * further the cache lists can be messed 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. Therefore unregister of the last user does NOT drop all resources * * (If there are still registrated users at exit time, the cached images are still * loaded in the gimp session) * * TODO: user registration shall be serialized and stored via gimp_set_data * to keep track over the entire gimp session. * * * * Copyright (C) 2008 Wolfgang Hofer * * * 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 /* SYTEM (UNIX) includes */ #include //#include //#include //#include //#include //#include #include /* GIMP includes */ #include "gtk/gtk.h" #include "gap-intl.h" #include "libgimp/gimp.h" #include "gap_libgapbase.h" #include "gap_libgimpgap.h" #include "gap_lib_common_defs.h" #include "gap_layer_copy.h" //#include "gap_fmac_name.h" #include "gap_frame_fetcher.h" #define GAP_FFETCH_MAX_IMG_CACHE_ELEMENTS 18 #define GAP_FFETCH_MAX_GVC_CACHE_ELEMENTS 6 #define GAP_FFETCH_GVA_FRAMES_TO_KEEP_CACHED 36 /* the lists of cached images and duplicates are implemented via GIMP image parasites, * where images are simply loaded by GIMP without adding a display and marked with a non persistent parasite. * the GAP_IMAGE_CACHE_PARASITE holds the modification timestamp (mtime) and full filename (inclusive terminating 0) * the GAP_IMAGE_DUP_CACHE_PARASITE holds the gint32 ffetch_user_id */ #define GAP_IMAGE_CACHE_PARASITE "GAP-IMAGE-CACHE-PARASITE" #define GAP_IMAGE_DUP_CACHE_PARASITE "GAP-IMAGE-DUP-CACHE-PARASITE" typedef struct GapFFetchResourceUserElem { gint32 ffetch_user_id; void *next; } GapFFetchResourceUserElem; /* -------- 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 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(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_load_cache_image * ---------------------------------------------------- */ static gint32 p_load_cache_image(const char* filename, gboolean addToCache) { gint32 l_image_id; char *l_filename; gint32 *images; gint nimages; gint l_idi; gint l_number_of_cached_images; gint32 l_first_chached_image_id; GimpParasite *l_parasite; if(filename == NULL) { printf("p_load_cache_image: ** ERROR cant load filename == NULL! pid:%d\n", (int)gap_base_getpid()); return -1; } l_image_id = -1; l_first_chached_image_id = -1; l_number_of_cached_images = 0; images = gimp_image_list(&nimages); for(l_idi=0; l_idi < nimages; l_idi++) { l_parasite = gimp_image_parasite_find(images[l_idi], GAP_IMAGE_CACHE_PARASITE); if(l_parasite) { gint32 *mtime_ptr; gchar *filename_ptr; mtime_ptr = (gint32 *) l_parasite->data; filename_ptr = (gchar *)&l_parasite->data[sizeof(gint32)]; l_number_of_cached_images++; if (l_first_chached_image_id < 0) { l_first_chached_image_id = images[l_idi]; } if(strcmp(filename, filename_ptr) == 0) { gint32 mtimefile; mtimefile = gap_file_get_mtime(filename); if(mtimefile == *mtime_ptr) { /* image found in cache */ l_image_id = images[l_idi]; } else { /* image found in cache, but has changed modification timestamp * (delete from cache and reload) */ if(gap_debug) { printf("FrameFetcher: DELETE because mtime changed : (image_id:%d) name:%s mtimefile:%d mtimecache:%d pid:%d\n" , (int)images[l_idi] , gimp_image_get_filename(images[l_idi]) , (int)mtimefile , (int)*mtime_ptr , (int)gap_base_getpid() ); } gap_image_delete_immediate(images[l_idi]); } l_idi = nimages -1; /* force break at next loop iteration */ } gimp_parasite_free(l_parasite); } } if(images) { g_free(images); } if (l_image_id >= 0) { if(gap_debug) { printf("FrameFetcher: p_load_cache_image CACHE-HIT :%s (image_id:%d) pid:%d\n" , filename, (int)l_image_id, (int)gap_base_getpid()); } return(l_image_id); } l_filename = g_strdup(filename); l_image_id = gap_lib_load_image(l_filename); if(gap_debug) { printf("FrameFetcher: loaded image from disk:%s (image_id:%d) pid:%d\n" , l_filename, (int)l_image_id, (int)gap_base_getpid()); } if((l_image_id >= 0) && (addToCache == TRUE)) { guchar *parasite_data; gint32 parasite_size; gint32 *parasite_mtime_ptr; gchar *parasite_filename_ptr; gint32 len_filename0; /* filename length including the terminating 0 */ if (l_number_of_cached_images > GAP_FFETCH_MAX_IMG_CACHE_ELEMENTS) { /* the image cache already has more elements than desired, * drop the 1st cached image */ if(gap_debug) { printf("FrameFetcher: DELETE because cache is full: (image_id:%d) name:%s number_of_cached_images:%d pid:%d\n" , (int)l_first_chached_image_id , gimp_image_get_filename(images[l_idi]) , (int)l_number_of_cached_images , (int)gap_base_getpid() ); } gap_image_delete_immediate(l_first_chached_image_id); } /* build parasite data including mtime and full filename with terminating 0 byte */ len_filename0 = strlen(filename) + 1; parasite_size = sizeof(gint32) + len_filename0; parasite_data = g_malloc0(parasite_size); parasite_mtime_ptr = (gint32 *)parasite_data; parasite_filename_ptr = (gchar *)¶site_data[sizeof(gint32)]; *parasite_mtime_ptr = gap_file_get_mtime(filename); memcpy(parasite_filename_ptr, filename, len_filename0); /* attach a parasite to mark the image as part of the gap image cache */ l_parasite = gimp_parasite_new(GAP_IMAGE_CACHE_PARASITE ,0 /* GIMP_PARASITE_PERSISTENT 0 for non persistent */ ,parasite_size ,parasite_data ); if(l_parasite) { gimp_image_parasite_attach(l_image_id, l_parasite); gimp_parasite_free(l_parasite); } g_free(parasite_data); } g_free(l_filename); return(l_image_id); } /* end p_load_cache_image */ /* ---------------------------------------------------- * p_drop_image_cache * ---------------------------------------------------- * drop the image cache. */ static void p_drop_image_cache(void) { gint32 *images; gint nimages; gint l_idi; if(gap_debug) { printf("p_drop_image_cache START pid:%d\n", (int) gap_base_getpid()); } images = gimp_image_list(&nimages); for(l_idi=0; l_idi < nimages; l_idi++) { GimpParasite *l_parasite; l_parasite = gimp_image_parasite_find(images[l_idi], GAP_IMAGE_CACHE_PARASITE); if(gap_debug) { printf("FrameFetcher: CHECK (image_id:%d) name:%s pid:%d\n" , (int)images[l_idi] , gimp_image_get_filename(images[l_idi]) , (int)gap_base_getpid() ); } if(l_parasite) { if(gap_debug) { printf("FrameFetcher: DELETE (image_id:%d) name:%s pid:%d\n" , (int)images[l_idi] , gimp_image_get_filename(images[l_idi]) , (int)gap_base_getpid() ); } /* delete image from the duplicates cache */ gap_image_delete_immediate(images[l_idi]); gimp_parasite_free(l_parasite); } } if(images) { g_free(images); } if(gap_debug) { printf("p_drop_image_cache END pid:%d\n", (int)gap_base_getpid()); } } /* 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 */ #endif #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* ---------------------------------------------------- * 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 */ #endif #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* ---------------------------------------------------- * 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 = gap_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) { GimpParasite *l_parasite; /* attach a parasite to mark the image as part of the gap image duplicates cache */ l_parasite = gimp_parasite_new(GAP_IMAGE_DUP_CACHE_PARASITE ,0 /* GIMP_PARASITE_PERSISTENT 0 for non persistent */ , sizeof(gint32) /* size of parasite data */ ,&ffetch_user_id /* parasite data */ ); if(l_parasite) { gimp_image_parasite_attach(image_id, l_parasite); gimp_parasite_free(l_parasite); } } /* 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) { gint32 *images; gint nimages; gint l_idi; images = gimp_image_list(&nimages); for(l_idi=0; l_idi < nimages; l_idi++) { GimpParasite *l_parasite; l_parasite = gimp_image_parasite_find(images[l_idi], GAP_IMAGE_DUP_CACHE_PARASITE); if(gap_debug) { printf("FrameFetcher: check (image_id:%d) name:%s pid:%d\n" , (int)images[l_idi] , gimp_image_get_filename(images[l_idi]) , (int)gap_base_getpid() ); } if(l_parasite) { gint32 *ffetch_user_id_ptr; ffetch_user_id_ptr = (gint32 *) l_parasite->data; if((*ffetch_user_id_ptr == ffetch_user_id) || (ffetch_user_id < 0)) { if(gap_debug) { printf("FrameFetcher: DELETE duplicate %s (image_id:%d) user_id:%d (%d) name:%s pid:%d\n" , gimp_image_get_filename(images[l_idi]) , (int)images[l_idi] , (int)ffetch_user_id , (int)*ffetch_user_id_ptr , gimp_image_get_filename(images[l_idi]) , (int)gap_base_getpid() ); } /* delete image from the duplicates cache */ gap_image_delete_immediate(images[l_idi]); } gimp_parasite_free(l_parasite); } } if(images) { g_free(images); } } /* 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; dup_image_id = -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; gdouble l_xresoulution, l_yresoulution; gint32 l_unit; 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) ); gimp_image_get_resolution(image_id, &l_xresoulution, &l_yresoulution); gimp_image_set_resolution(dup_image_id, l_xresoulution, l_yresoulution); l_unit = gimp_image_get_unit(image_id); gimp_image_set_unit(dup_image_id, l_unit); 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) { GimpParasite *l_parasite; l_parasite = gimp_image_parasite_find(image_id, GAP_IMAGE_CACHE_PARASITE); if(l_parasite) { gimp_parasite_free(l_parasite); } else { /* 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(); #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT p_drop_vidhandle_cache(); #endif } /* 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 pid:%d\n" , new_usr_ptr->ffetch_user_id , caller_name , (int)&new_usr_ptr , (int) gap_base_getpid() ); } 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 videohandle resources and temporary image duplicates are dropped) * Current restriction: * the current implementation keeps user registration in global data * but filtermacros and storyboard processor typically are running in separate * processes an therefore each process has its own global data. * an empty list of users does not really indicate * that there are no more users (another process may still have users * of cached images) * therefore cached images are NOT 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 pid:%d\n" , ffetch_user_id , (int) gap_base_getpid() ); } 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 duplicates and video handles\n"); } gap_frame_fetch_delete_list_of_duplicated_images(-1); #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT p_drop_vidhandle_cache(); #endif } } /* end gap_frame_fetch_unregister_user */ gimp-gap-2.6.0+dfsg.orig/gap/gap_fmac_base.h0000644000175000017500000000313211212030253020413 0ustar thibautthibaut/* gap_fmac_base.h * 2006.12.11 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * - filtermacro execution backend procedures. * * WARNING: * filtermacros are a temporary solution, useful for animations * but do not expect support for filtermacros in future releases of GIMP-GAP * because GIMP may have real makro features in the future ... * * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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_BASE_H #define GAP_FMAC_BASE_H #include "libgimp/gimp.h" gint gap_fmac_execute(GimpRunMode run_mode, gint32 image_id, gint32 drawable_id , const char *filtermacro_file1 , const char *filtermacro_file2 , gdouble current_step , gint32 total_steps ); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_story_undo.c0000644000175000017500000004256311212030253020726 0ustar thibautthibaut/* gap_story_undo.c * This module handles GAP storyboard undo and redo features. */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.25a; 2007/10/18 hof: created */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "gap_story_main.h" #include "gap_story_undo_types.h" #include "gap_story_undo.h" #include "gap_story_dialog.h" #include "gap_story_file.h" extern int gap_debug; /* 1 == print debug infos , 0 dont print debug infos */ static void p_free_undo_elem(GapStoryUndoElem *undo_elem); static void p_delete_redo_stack_area(GapStbTabWidgets *tabw); /* ---------------------------------------------------- * gap_stb_undo_debug_print_stack * ---------------------------------------------------- */ void gap_stb_undo_debug_print_stack(GapStbTabWidgets *tabw) { GapStoryUndoElem *undo_elem; if(tabw == NULL) { printf("\nStack NOT present (NULL POINTER)\n"); fflush(stdout); return; } printf("\n-------------------------------- Top of STACK ---\n\n"); printf("gap_stb_undo_debug_print_stack: tabw:%d stack_list:%d stack_ptr:%d group_counter:%.2f\n" , (int)tabw , (int)tabw->undo_stack_list , (int)tabw->undo_stack_ptr , (float)tabw->undo_stack_group_counter ); fflush(stdout); for(undo_elem = tabw->undo_stack_list; undo_elem != NULL; undo_elem = undo_elem->next) { printf(" %d %s" , (int)undo_elem , gap_stb_undo_feature_to_string(undo_elem->feature_id) ); if(undo_elem == tabw->undo_stack_ptr) { printf(" <-- stack_ptr"); } printf("\n"); fflush(stdout); } printf("\n-------------------------------- End of STACK ---\n\n"); fflush(stdout); } /* end gap_stb_undo_debug_print_stack */ /* ---------------------------------------------------- * gap_stb_undo_feature_to_string * ---------------------------------------------------- */ const char * gap_stb_undo_feature_to_string(GapStoryFeatureEnum feature_id) { switch(feature_id) { case GAP_STB_FEATURE_LATEST: return("latest"); break; case GAP_STB_FEATURE_EDIT_CUT: return("edit cut"); break; case GAP_STB_FEATURE_EDIT_PASTE: return("edit paste"); break; case GAP_STB_FEATURE_DND_CUT: return("dnd cut"); break; case GAP_STB_FEATURE_DND_PASTE: return("dnd paste"); break; case GAP_STB_FEATURE_CREATE_CLIP: return("create clip"); break; case GAP_STB_FEATURE_CREATE_TRANSITION: return("create transition"); break; case GAP_STB_FEATURE_CREATE_SECTION_CLIP: return("create section clip"); break; case GAP_STB_FEATURE_CREATE_SECTION: return("create section"); break; case GAP_STB_FEATURE_DELETE_SECTION: return("delete section"); break; case GAP_STB_FEATURE_PROPERTIES_CLIP: return("properties clip"); break; case GAP_STB_FEATURE_PROPERTIES_TRANSITION: return("properties transition"); break; case GAP_STB_FEATURE_PROPERTIES_SECTION: return("properties section"); break; case GAP_STB_FEATURE_PROPERTIES_MASTER: return("properties master"); break; case GAP_STB_FEATURE_SCENE_SPLITTING: return("scene split"); break; case GAP_STB_FEATURE_GENERATE_OTONE: return("generate otone"); break; } return("unknown"); } /* end gap_stb_undo_feature_to_string */ /* --------------------------------------- * gap_stb_undo_pop * --------------------------------------- * this procedure is typically called for UNDO storyboard changes * made by the storyboard features. * * undo the feature that is refered by the undo stackpointer * move the stackpointer to next element. (keep the element * on the stack for redo purpose) * returns a duplicate of the storyboard backup that is attached to the * undo stackpointer (position as it was before this call) * this refers to the backup version at the time BEFORE the * feature (that now shall be undone) was applied. * * example1: * latest * stack_list --> BBBB <-- stack_ptr before pop BBBB * AAAA AAAA <--- stack_ptr after pop returns (BBBB) * -------------------------------------------------------------------------------- * * if the stack_ptr is on top (e.g. == stack_list root) * a duplicate of the current storyboard is pushed as feature_id "latest" onto the stack. * this backup reprents the version AFTER feature BBBB of example1 to be re-done * * * example2: * * stack_list -->latest latest * DDDD DDDD * CCCC <-- stack_ptr before pop CCCC * BBBB BBBB <--- stack_ptr after pop returns (CCCC) * AAAA AAAA * -------------------------------------------------------------------------------- */ GapStoryBoard * gap_stb_undo_pop(GapStbTabWidgets *tabw) { GapStoryBoard *stb; stb = NULL; if(tabw == NULL) { return (NULL); } if (tabw->undo_stack_ptr == NULL) { return (NULL); } if (tabw->undo_stack_ptr == tabw->undo_stack_list) { /* at undo push the lastest available */ gap_stb_undo_push_clip(tabw, GAP_STB_FEATURE_LATEST, -1); /* advance stack_ptr * (to compensate the extra push above) */ tabw->undo_stack_ptr = tabw->undo_stack_ptr->next; } stb = gap_story_duplicate_full(tabw->undo_stack_ptr->stb); if(gap_debug) { printf("gap_stb_undo_pop returning feature_id:%d %s grp_count:%.2f next:%d\n" ,(int)tabw->undo_stack_ptr->feature_id ,gap_stb_undo_feature_to_string(tabw->undo_stack_ptr->feature_id) ,(float)tabw->undo_stack_group_counter ,(int)tabw->undo_stack_ptr->next ); fflush(stdout); } tabw->undo_stack_ptr = tabw->undo_stack_ptr->next; gap_story_dlg_tabw_undo_redo_sensitivity(tabw); return (stb); } /* end gap_stb_undo_pop */ /* --------------------------------------- * gap_stb_undo_redo * --------------------------------------- * redo the feature that is above (e.g before) the undo stackpointer * returns a duplicate of the storyboard backup that is attached to the * element 2 above the undo stackpointer. * this refers to the backup version at the time BEFORE the * feature (that now shall be undone) was applied. * * * stack_list -->latest latest * EEEE EEEE * DDDD DDDD <--- stack_ptr after redo * CCCC <-- stack_ptr before redo CCCC returns (EEEE) * BBBB BBBB * AAAA AAAA * -------------------------------------------------------------------------------- */ GapStoryBoard * gap_stb_undo_redo(GapStbTabWidgets *tabw) { GapStoryBoard *stb; GapStoryUndoElem *undo_elem; GapStoryUndoElem *prev_elem; GapStoryUndoElem *redo_elem; stb = NULL; if(tabw == NULL) { return (NULL); } prev_elem = NULL; redo_elem = NULL; for(undo_elem = tabw->undo_stack_list; undo_elem != NULL; undo_elem = undo_elem->next) { if(undo_elem->next == tabw->undo_stack_ptr) { redo_elem = prev_elem; tabw->undo_stack_ptr = undo_elem; break; } prev_elem = undo_elem; } if (redo_elem != NULL) { stb = gap_story_duplicate_full(redo_elem->stb); gap_story_dlg_tabw_undo_redo_sensitivity(tabw); if(gap_debug) { printf("gap_stb_undo_redo returning feature_id:%d %s grp_count:%.2f resulting stack_ptr:%d\n" ,(int)redo_elem->feature_id ,gap_stb_undo_feature_to_string(redo_elem->feature_id) ,(float)tabw->undo_stack_group_counter ,(int)tabw->undo_stack_ptr ); fflush(stdout); } } return (stb); } /* end gap_stb_undo_redo */ /* --------------------------------------- * p_free_undo_elem * --------------------------------------- */ static void p_free_undo_elem(GapStoryUndoElem *undo_elem) { if(undo_elem == NULL) { return; } if(gap_debug) { printf("p_free_undo_elem: %d %s\n" , (int)undo_elem , gap_stb_undo_feature_to_string(undo_elem->feature_id) ); fflush(stdout); } if(undo_elem->stb) { gap_story_free_storyboard(&undo_elem->stb); } g_free(undo_elem); } /* end p_free_undo_elem */ /* --------------------------------------- * p_delete_redo_stack_area * --------------------------------------- * delete all undo elements beginning from stack_list root * up to exclusive stackpointer. * if the stackpointer points to an element with feature_id * GAP_STB_FEATURE_LATEST * then delete inclusive this element. * * after this procedure the stack_list root and stack_ptr * point to the same element (or both are NULL) */ static void p_delete_redo_stack_area(GapStbTabWidgets *tabw) { GapStoryUndoElem *undo_elem; GapStoryUndoElem *next_elem; GapStoryUndoElem *new_root_elem; if(tabw == NULL) { return; } if(gap_debug) { printf("p_delete_redo_stack_area\n"); } /* make sure that the stack_ptr does not point to an element * with feature_id GAP_STB_FEATURE_LATEST * (advance if necessary) */ for(undo_elem = tabw->undo_stack_ptr; undo_elem != NULL; undo_elem = undo_elem->next) { if(undo_elem->feature_id != GAP_STB_FEATURE_LATEST) { break; } tabw->undo_stack_ptr = undo_elem->next; } new_root_elem = NULL; next_elem = NULL; for(undo_elem = tabw->undo_stack_list; undo_elem != NULL; undo_elem = next_elem) { if(undo_elem == tabw->undo_stack_ptr) { new_root_elem = undo_elem; break; } next_elem = undo_elem->next; p_free_undo_elem(undo_elem); } tabw->undo_stack_list = new_root_elem; return; } /* end p_delete_redo_stack_area */ /* --------------------------------------- * gap_stb_undo_destroy_undo_stack * --------------------------------------- * delete all undo elements beginning from stack_list root * up to exclusive stackpointer. * after this procedure the stack_list root and stack_ptr * point to the same element (or both are NULL) */ void gap_stb_undo_destroy_undo_stack(GapStbTabWidgets *tabw) { if(tabw == NULL) { return; } if(gap_debug) { printf("gap_stb_undo_destroy_undo_stack\n"); fflush(stdout); } tabw->undo_stack_ptr = NULL; p_delete_redo_stack_area(tabw); gap_story_dlg_tabw_undo_redo_sensitivity(tabw); } /* end gap_stb_undo_destroy_undo_stack */ /* --------------------------------------- * gap_stb_undo_push_clip * --------------------------------------- * create a new undo element (according to specified parameters) * and place it at top (first) of the und stack. * if the stackpointer is NOT equal to the stack_list root, * the delete all undo elements from stack_list up to stackpointer. * * move the stackpointer to next element. (keep the element * on the stack for redo purpose) * * stack_list -->DDDD * CCCC EEEE <--- stack_ptr after push (EEEE) * BBBB <-- stack_ptr before push(EEEE) BBBB (deletes CCCC, DDDD) * AAAA AAAA * -------------------------------------------------------------------------------- */ void gap_stb_undo_push_clip(GapStbTabWidgets *tabw, GapStoryFeatureEnum feature_id, gint32 story_id) { GapStoryBoard *stb; GapStoryUndoElem *new_undo_elem; if(tabw == NULL) { return; } if(gap_debug) { printf("gap_stb_undo_push_clip feature_id:%d %s grp_count:%.2f\n" ,(int)feature_id ,gap_stb_undo_feature_to_string(feature_id) ,(float)tabw->undo_stack_group_counter ); fflush(stdout); } if(tabw->undo_stack_group_counter > 1) { return; } if(tabw->undo_stack_group_counter == 1) { tabw->undo_stack_group_counter = 1.5; } p_delete_redo_stack_area(tabw); stb = gap_story_dlg_tabw_get_stb_ptr(tabw); if(story_id >= 0) { switch (feature_id) { case GAP_STB_FEATURE_PROPERTIES_CLIP: case GAP_STB_FEATURE_PROPERTIES_TRANSITION: if(tabw->undo_stack_ptr != NULL) { if((tabw->undo_stack_ptr->feature_id == feature_id) && (tabw->undo_stack_ptr->clip_story_id == story_id)) { /* multiple push of the same feature on the same clip object * are supressed. this collects multiple property changes * in sequence into one single undo step. */ return; } } break; default: break; } } new_undo_elem = g_new(GapStoryUndoElem, 1); new_undo_elem->clip_story_id = story_id; new_undo_elem->feature_id = feature_id; new_undo_elem->next = tabw->undo_stack_list; tabw->undo_stack_list = new_undo_elem; tabw->undo_stack_ptr = new_undo_elem; gap_story_dlg_update_edit_settings(stb, tabw); new_undo_elem->stb = gap_story_duplicate_full(stb); gap_story_dlg_tabw_undo_redo_sensitivity(tabw); } /* end gap_stb_undo_push_clip */ /* --------------------------------------- * gap_stb_undo_push * --------------------------------------- */ void gap_stb_undo_push(GapStbTabWidgets *tabw, GapStoryFeatureEnum feature_id) { gap_stb_undo_push_clip(tabw, feature_id, -1 /* story_id */); } /* end gap_stb_undo_push */ /* --------------------------------------- * gap_stb_undo_group_begin * --------------------------------------- * */ void gap_stb_undo_group_begin(GapStbTabWidgets *tabw) { if(tabw == NULL) { return; } tabw->undo_stack_group_counter += 1.0; } /* end gap_stb_undo_group_begin */ /* --------------------------------------- * gap_stb_undo_group_end * --------------------------------------- */ void gap_stb_undo_group_end(GapStbTabWidgets *tabw) { if(tabw == NULL) { return; } tabw->undo_stack_group_counter -= 1.0; if (tabw->undo_stack_group_counter < 1.0) { tabw->undo_stack_group_counter = 0.0; } } /* end gap_stb_undo_group_end */ /* --------------------------------------- * gap_stb_undo_get_undo_feature * --------------------------------------- * return NULL if undo not available * or feature name that is ready to be un-done * (dont g_free the returned string) */ const char * gap_stb_undo_get_undo_feature(GapStbTabWidgets *tabw) { const char *feature_name; if (tabw == NULL) { return (NULL); } if (tabw->undo_stack_ptr == NULL) { return (NULL); } feature_name = gap_stb_undo_feature_to_string(tabw->undo_stack_ptr->feature_id); return (feature_name); } /* end gap_stb_undo_get_undo_feature */ /* --------------------------------------- * gap_stb_undo_get_redo_feature * --------------------------------------- * return NULL if redo not available * or feature name that is ready to be re-done * (dont g_free the returned string) */ const char * gap_stb_undo_get_redo_feature(GapStbTabWidgets *tabw) { const char *feature_name; GapStoryUndoElem *undo_elem; GapStoryUndoElem *redo_elem; if (tabw == NULL) { return (NULL); } redo_elem = NULL; for(undo_elem = tabw->undo_stack_list; undo_elem != NULL; undo_elem = undo_elem->next) { if(undo_elem->next == tabw->undo_stack_ptr) { if(undo_elem->feature_id == GAP_STB_FEATURE_LATEST) { return (NULL); } redo_elem = undo_elem; break; } } if (redo_elem != NULL) { feature_name = gap_stb_undo_feature_to_string(redo_elem->feature_id); return (feature_name); } return (NULL); } /* end gap_stb_undo_get_redo_feature */ /* --------------------------------------- * gap_stb_undo_stack_set_unsaved_changes * --------------------------------------- * set the unsaved_changes flag = TRUE in * all storyboard backups in the undo stack. * this is typicall called on save. * (because the unsaved_changes in the back ups * refers to the state at capture time and gets invalid * when the storyboard is saved to file). */ void gap_stb_undo_stack_set_unsaved_changes(GapStbTabWidgets *tabw) { GapStoryUndoElem *undo_elem; for(undo_elem = tabw->undo_stack_list; undo_elem != NULL; undo_elem = undo_elem->next) { if(undo_elem->stb != NULL) { undo_elem->stb->unsaved_changes = TRUE; } } } /* end gap_stb_undo_stack_set_unsaved_changes */ gimp-gap-2.6.0+dfsg.orig/gap/gap_story_undo_types.h0000644000175000017500000000427411212030253022154 0ustar thibautthibaut/* gap_story_undo_types.h * * This module defines types for GAP storyboard undo and redo features. */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.25a; 2007/10/18 hof: created */ #ifndef _GAP_STORY_UNDO_TYPES_H #define _GAP_STORY_UNDO_TYPES_H #include "libgimp/gimp.h" #include "gap_story_file.h" #include #include #include typedef enum { GAP_STB_FEATURE_LATEST ,GAP_STB_FEATURE_EDIT_CUT ,GAP_STB_FEATURE_EDIT_PASTE ,GAP_STB_FEATURE_DND_CUT ,GAP_STB_FEATURE_DND_PASTE ,GAP_STB_FEATURE_CREATE_CLIP ,GAP_STB_FEATURE_CREATE_TRANSITION ,GAP_STB_FEATURE_CREATE_SECTION_CLIP ,GAP_STB_FEATURE_CREATE_SECTION ,GAP_STB_FEATURE_DELETE_SECTION ,GAP_STB_FEATURE_PROPERTIES_CLIP ,GAP_STB_FEATURE_PROPERTIES_TRANSITION ,GAP_STB_FEATURE_PROPERTIES_SECTION ,GAP_STB_FEATURE_PROPERTIES_MASTER ,GAP_STB_FEATURE_SCENE_SPLITTING ,GAP_STB_FEATURE_GENERATE_OTONE } GapStoryFeatureEnum; /* storyboard undo element */ typedef struct GapStoryUndoElem { GapStoryFeatureEnum feature_id; gint32 clip_story_id; /* -1 if feature modifies more than 1 clip */ GapStoryBoard *stb; /* storyboard backup before * feature with feature_id was applied */ struct GapStoryUndoElem *next; } GapStoryUndoElem; #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_story_render_processor.c0000644000175000017500000063712711212030253023345 0ustar thibautthibaut/* gap_story_render_processor.c * * * GAP storyboard rendering processor. * * GAP video encoder tool procedures for STORYBOARD file based video encoding * This module is the Storyboard processor that reads instructions from the storyboard * file, fetches input frames, and renders composite video frames * according to the instructions in the storyboard file. * * The storyboard processor is typically used to: * - check storyboard syntax and deliver information (number of total frames) * for the master encoder dialog. * - render the composite video frame at specified master frame number * (is called as frame fetching utility by all encoders) * * The storyboard processor provides fuctionality to mix audiodata, * this is usually done in the master encoder dialog (before starting the selected encoder) * * Copyright (C) 2006 Wolfgang Hofer * * * 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. */ /* * 2006.06.25 hof - created (moved stuff from the former gap_gve_story modules to this new module) * - new features: * use shadow tracks, (implicite) generated by the new overlap attribute * normal track numbers are 1, 3, 5, 7 * corresponding shadow tracks are 0, 2, 4, 6 (shadow = normal -1) * - support video frame flipping (hor/vertical) * */ #include /* SYTEM (UNIX) includes */ #include #include #include #include #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "gap-intl.h" #include "libgimp/gimp.h" #include "gap_libgapbase.h" #include "gap_libgimpgap.h" #include "gap_lib_common_defs.h" #include "gap_audio_util.h" #include "gap_audio_wav.h" #include "gap_story_file.h" #include "gap_layer_copy.h" #include "gap_story_render_audio.h" #include "gap_story_render_processor.h" #include "gap_fmac_name.h" #include "gap_frame_fetcher.h" /* data for the storyboard proceesor frame fetching */ typedef struct GapStbFetchData { /* nick: gfd */ gint32 comp_image_id; gint32 tmp_image_id; gint32 layer_id; gchar *framename; gdouble opacity; gdouble scale_x; gdouble scale_y; gdouble move_x; gdouble move_y; GapStoryRenderFrameRangeElem *frn_elem; gint32 localframe_index; gint32 local_stepcount; gdouble localframe_tween_rest; gboolean keep_proportions; gboolean fit_width; gboolean fit_height; GapStoryRenderFrameType frn_type; char *trak_filtermacro_file; } GapStbFetchData; /************************************************************* * STORYBOARD FUNCTIONS * ************************************************************* */ #define MAX_IMG_CACHE_ELEMENTS 6 extern int gap_debug; /* 1 == print debug infos , 0 dont print debug infos */ static gint32 global_monitor_image_id = -1; static gint32 global_monitor_display_id = -1; static void p_debug_print_render_section_names(GapStoryRenderVidHandle *vidhand); static void p_frame_backup_save( char *key , gint32 image_id , gint32 layer_id , gint32 master_frame_nr , gboolean multilayer ); static void p_debug_dup_image(gint32 image_id); static void p_encoding_monitor( char *key , gint32 image_id , gint32 layer_id , gint32 master_frame_nr ); static GapStoryRenderErrors * p_new_stb_error(void); 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_find_min_max_vid_tracknumbers(GapStoryRenderFrameRangeElem *frn_list , gint32 *lowest_tracknr , gint32 *highest_tracknr ); static void p_step_attribute(gint32 frames_handled ,gdouble *from_val ,gdouble *to_val ,gint32 *dur ); static gdouble p_step_attribute_read(gint32 frame_step ,gdouble from_val ,gdouble to_val ,gint32 dur ); static gdouble p_step_attribute_read(gint32 frame_step ,gdouble from_val ,gdouble to_val ,gint32 dur ); static void p_select_section_by_name(GapStoryRenderVidHandle *vidhand , const char *section_name); static char * p_fetch_framename (GapStoryRenderFrameRangeElem *frn_list , gint32 master_frame_nr /* starts at 1 */ , gint32 track , GapStoryRenderFrameType *frn_type , char **filtermacro_file , gint32 *localframe_index /* used only for ANIMIMAGE and videoclip, -1 for all other types */ , gint32 *local_stepcount /* nth frame within this clip, starts with 0 */ , gdouble *localframe_tween_rest /* non-integer part of the position. value < 1.0 for tween fetching */ , gboolean *keep_proportions , gboolean *fit_width , gboolean *fit_height , gdouble *red_f , gdouble *green_f , gdouble *blue_f , gdouble *alpha_f , gdouble *opacity /* output opacity 0.0 upto 1.0 */ , gdouble *scale_x /* output 0.0 upto 10.0 where 1.0 is 1:1 */ , gdouble *scale_y /* output 0.0 upto 10.0 where 1.0 is 1:1 */ , gdouble *move_x /* output -1.0 upto 1.0 where 0.0 is centered */ , gdouble *move_y /* output -1.0 upto 1.0 where 0.0 is centered */ , GapStoryRenderFrameRangeElem **frn_elem_ptr /* OUT pointer to the relevant framerange element */ ); static void p_calculate_frames_to_handle(GapStoryRenderFrameRangeElem *frn_elem); static GapStoryRenderFrameRangeElem * p_new_framerange_element( GapStoryRenderFrameType frn_type ,gint32 track ,const char *basename /* basename or full imagename for frn_type GAP_FRN_IMAGE */ ,const char *ext /* NULL for frn_type GAP_FRN_IMAGE */ ,gint32 frame_from /* IN: range start */ ,gint32 frame_to /* IN: range end */ ,const char *storyboard_file /* IN: NULL if no storyboard file is used */ ,const char *preferred_decoder /* IN: NULL if no preferred_decoder is specified */ ,const char *filtermacro_file /* IN: NULL, or name of the macro file */ ,GapStoryRenderFrameRangeElem *frn_list /* NULL or list of already known ranges */ ,GapStoryRenderErrors *sterr /* element to store Error/Warning report */ ,gint32 seltrack /* IN: select videotrack number 1 upto 99 for GAP_FRN_MOVIE */ ,gint32 exact_seek /* IN: 0 fast seek, 1 exact seek (only for GVA Videoreads) */ ,gdouble delace /* IN: 0.0 no deinterlace, 1.0-1.99 odd 2.0-2.99 even rows (only for GVA Videoreads) */ ,gdouble step_density /* IN: 1==normal stepsize 1:1 0.5 == each frame twice, 2.0 only every 2nd frame */ ,gint32 flip_request /* 0 NONE, 1 flip horizontal, 2 flip vertical, 3 rotate 180degree */ ,const char *mask_name /* reference to layer mask definition */ ,gdouble mask_stepsize /* stepsize for the layer mask */ ,GapStoryMaskAnchormode mask_anchor /* how to apply the layer mask */ ,gboolean mask_disable ,gint32 fmac_total_steps ); static void p_add_frn_list(GapStoryRenderVidHandle *vidhand, GapStoryRenderFrameRangeElem *frn_elem); static void p_step_all_vtrack_attributes(gint32 track, gint32 frames_to_handle ,GapStoryRenderVTrackArray *vtarr ); static void p_set_vtrack_attributes(GapStoryRenderFrameRangeElem *frn_elem ,GapStoryRenderVTrackArray *vtarr ); static void p_vidclip_add_as_is(GapStoryRenderFrameRangeElem *frn_elem ,GapStoryRenderVidHandle *vidhand ,GapStoryRenderVTrackArray *vtarr ); static void p_vidclip_shadow_add_silence(gint32 shadow_track ,gint32 fill_shadow_frames ,GapStoryRenderVidHandle *vidhand ,GapStoryRenderVTrackArray *vtarr ,const char *storyboard_file ); static void p_recalculate_range_part(GapStoryRenderFrameRangeElem *frn_elem , gint32 lost_frames , gint32 rest_frames ); static void p_copy_vattr_values(gint32 src_track , gint32 dst_track , GapStoryRenderVTrackArray *vtarr ); static void p_vidclip_split_and_add_frn_list(GapStoryRenderFrameRangeElem *frn_elem, GapStoryRenderVidHandle *vidhand, GapStoryRenderVTrackArray *vtarr, const char *storyboard_file ); static void p_vidclip_add(GapStoryRenderFrameRangeElem *frn_elem ,GapStoryRenderVidHandle *vidhand ,GapStoryRenderVTrackArray *vtarr ,const char *storyboard_file ,gboolean first_of_group ); static void p_clear_vattr_array(GapStoryRenderVTrackArray *vtarr); static gboolean p_fmt_string_has_framenumber_format(const char *fmt_string); static gboolean p_fmt_string_has_videobasename_format(const char *fmt_string); static void p_storyboard_analyze(GapStoryBoard *stb , gint32 *mainsection_frame_count , GapStoryRenderVidHandle *vidhand ); static GapStoryRenderFrameRangeElem * p_framerange_list_from_storyboard( const char *storyboard_file ,gint32 *frame_count ,GapStoryRenderVidHandle *vidhand ,GapStoryBoard *stb_mem_ptr ); static void p_free_framerange_list(GapStoryRenderFrameRangeElem * frn_list); static GapStoryRenderSection * p_new_render_section(const char *section_name); static void p_append_render_section_to_vidhand(GapStoryRenderVidHandle *vidhand , GapStoryRenderSection *new_render_section); static void p_open_mask_vidhand(GapStoryElem *stb_elem , GapStoryRenderMaskDefElem *maskdef_elem); static void p_copy_mask_definitions_to_vidhand(GapStoryBoard *stb_ptr , GapStoryRenderVidHandle *vidhand); static void p_free_mask_definitions(GapStoryRenderVidHandle *vidhand); static GapStoryRenderMaskDefElem * p_find_maskdef_by_name(GapStoryRenderVidHandle *vidhand, const char *mask_name); static gint32 p_mask_fetcher(GapStoryRenderVidHandle *vidhand , const char *mask_name , gint32 master_frame_nr , gint32 mask_width , gint32 mask_height , gint32 *layer_id /* OUT: Id of the only layer in the composite image */ , gboolean *was_last_maskframe /* OUT: true if this was the last maskframe */ ); static void p_fetch_and_add_layermask(GapStoryRenderVidHandle *vidhand , GapStoryRenderFrameRangeElem *frn_elem , gint32 local_stepcount , gint32 image_id , gint32 layer_id ); static GapStoryRenderVidHandle * p_open_video_handle_private( gboolean ignore_audio , gboolean ignore_video , gboolean create_audio_tmp_files , gdouble *progress_ptr , char *status_msg , gint32 status_msg_len , const char *storyboard_file , const char *basename , const char *ext , gint32 frame_from , gint32 frame_to , gint32 *frame_count /* output total frame_count , or 0 on failure */ , gboolean do_gimp_progress , GapLibTypeInputRange input_mode , const char *imagename , const char *preferred_decoder , gint32 seltrack , gint32 exact_seek , gdouble delace , gboolean compensate_framerange , GapStoryBoard *stb_mem_ptr ); static gint32 p_exec_filtermacro(gint32 image_id , gint32 layer_id , const char *filtermacro_file , const char *filtermacro_file_to , gdouble current_step , gint32 total_steps ); static gint32 p_transform_and_add_layer( gint32 comp_image_id , gint32 tmp_image_id , gint32 layer_id , gboolean keep_proportions , gboolean fit_width , gboolean fit_height , gdouble opacity /* 0.0 upto 1.0 */ , gdouble scale_x /* 0.0 upto 10.0 where 1.0 = 1:1 */ , gdouble scale_y /* 0.0 upto 10.0 where 1.0 = 1:1 */ , gdouble move_x /* -1.0 upto +1.0 where 0 = no move, -1 is left outside */ , gdouble move_y /* -1.0 upto +1.0 where 0 = no move, -1 is top outside */ , char *filtermacro_file , gint32 flip_request , GapStoryRenderFrameRangeElem *frn_elem , GapStoryRenderVidHandle *vidhand , gint32 local_stepcount ); static gint32 p_create_unicolor_image(gint32 *layer_id, gint32 width , gint32 height , gdouble r_f, gdouble g_f, gdouble b_f, gdouble a_f); static gint32 p_prepare_RGB_image(gint32 image_id); static void p_limit_open_videohandles(GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr , gint32 currently_open_videohandles ); static t_GVA_Handle * p_try_to_steal_gvahand(GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr , char *basename /* the videofile name */ , gint32 exact_seek ); static void p_split_delace_value(gdouble delace , gdouble localframe_tween_rest , gint32 *deinterlace_ptr , gdouble *threshold_ptr); static void p_conditional_delace_drawable(GapStbFetchData *gfd, gint32 drawable_id); static void p_stb_render_image_or_animimage(GapStbFetchData *gfd , GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr); static void p_stb_render_movie(GapStbFetchData *gfd , GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr , gint32 vid_width, gint32 vid_height); static void p_stb_render_section(GapStbFetchData *gfd , GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr , gint32 vid_width, gint32 vid_height , const char *section_name); static void p_stb_render_frame_images(GapStbFetchData *gfd, gint32 master_frame_nr); static void p_stb_render_composite_image_postprocessing(GapStbFetchData *gfd , GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr , gint32 vid_width, gint32 vid_height , char *filtermacro_file , const char *section_name ); static void p_stb_render_result_monitoring(GapStbFetchData *gfd, gint32 master_frame_nr); static void p_paste_logo_pattern(gint32 drawable_id , gint32 logo_pattern_id , gint32 offsetX , gint32 offsetY ); static void p_do_insert_area_processing(GapStbFetchData *gfd , GapStoryRenderVidHandle *vidhand); static gint32 p_story_render_fetch_composite_image_private(GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr /* starts at 1 */ , gint32 vid_width /* desired Video Width in pixels */ , gint32 vid_height /* desired Video Height in pixels */ , char *filtermacro_file /* NULL if no filtermacro is used */ , gint32 *layer_id /* output: Id of the only layer in the composite image */ , const char *section_name /* NULL for main section */ ); /* ---------------------------------------------------- * gap_story_render_debug_print_maskdef_elem * ---------------------------------------------------- * print all List elements for the given track * (negative track number will print all elements) */ void gap_story_render_debug_print_maskdef_elem(GapStoryRenderMaskDefElem *maskdef_elem, gint l_idx) { if(maskdef_elem) { printf("\n ===== maskdef_elem start ============ \n" ); printf(" [%d] record_type : %d\n", (int)l_idx, (int)maskdef_elem->record_type ); printf(" [%d] mask_name : ", (int)l_idx); if(maskdef_elem->mask_name) { printf("%s\n", maskdef_elem->mask_name );} else { printf ("(null)\n"); } printf(" [%d] mask_vidhand : %d\n", (int)l_idx, (int)maskdef_elem->mask_vidhand ); printf(" [%d] frame_count : %d\n", (int)l_idx, (int)maskdef_elem->frame_count ); printf(" [%d] flip_request : %d\n", (int)l_idx, (int)maskdef_elem->flip_request ); if(maskdef_elem->mask_vidhand) { printf("Storyboard list for this maskdef_elem:\n" ); gap_story_render_debug_print_framerange_list(maskdef_elem->mask_vidhand->frn_list, -1); } printf("\n ===== maskdef_elem end ============ \n" ); } } /* end gap_story_render_debug_print_maskdef_elem */ /* ---------------------------------------------------- * p_frn_record_type_to_string * ---------------------------------------------------- */ static const char * p_frn_record_type_to_string(GapStoryRenderFrameType frn_type) { switch(frn_type) { case GAP_FRN_SILENCE: return("GAP_FRN_SILENCE"); break; case GAP_FRN_COLOR: return("GAP_FRN_COLOR"); break; case GAP_FRN_IMAGE: return("GAP_FRN_IMAGE"); break; case GAP_FRN_ANIMIMAGE: return("GAP_FRN_ANIMIMAGE"); break; case GAP_FRN_FRAMES: return("GAP_FRN_FRAMES"); break; case GAP_FRN_MOVIE: return("GAP_FRN_MOVIE"); break; case GAP_FRN_SECTION: return("GAP_FRN_SECTION"); break; } return("** UNDEFINED RECORD TYPE **"); } /* end p_frn_record_type_to_string */ /* ---------------------------------------------------- * gap_story_render_debug_print_frame_elem * ---------------------------------------------------- * print all List elements for the given track * (negative track number will print all elements) */ void gap_story_render_debug_print_frame_elem(GapStoryRenderFrameRangeElem *frn_elem, gint l_idx) { static const char *normal_track = " (normal)"; static const char *shadow_track = " (shadow)"; if(frn_elem) { const char *track_type; track_type = normal_track; if((frn_elem->track & 1) == 0) { track_type = shadow_track; } printf("\n [%d] frn_type : %d %s\n", (int)l_idx, (int)frn_elem->frn_type ,p_frn_record_type_to_string(frn_elem->frn_type)); printf(" [%d] itrack (internal) : %d %s\n", (int)l_idx, (int)frn_elem->track, track_type ); printf(" [%d] track (file) : %d\n", (int)l_idx, (int)(1+(frn_elem->track / 2)) ); printf(" [%d] basename : ", (int)l_idx); if(frn_elem->basename) { printf("%s\n", frn_elem->basename );} else { printf ("(null)\n"); } printf(" [%d] ext : ", (int)l_idx); if(frn_elem->ext) { printf("%s\n", frn_elem->ext );} else { printf ("(null)\n"); } printf(" [%d] gvahand : %d\n", (int)l_idx, (int)frn_elem->gvahand ); printf(" [%d] seltrack : %d\n", (int)l_idx, (int)frn_elem->seltrack ); printf(" [%d] exact_seek : %d\n", (int)l_idx, (int)frn_elem->exact_seek ); printf(" [%d] delace : %.2f\n", (int)l_idx, (float)frn_elem->delace ); printf(" [%d] filtermacro_file : ", (int)l_idx); if(frn_elem->filtermacro_file) { printf("%s\n", frn_elem->filtermacro_file );} else { printf ("(null)\n"); } printf(" [%d] f.macro_file_to : ", (int)l_idx); if(frn_elem->filtermacro_file_to) { printf("%s\n", frn_elem->filtermacro_file_to );} else { printf ("(null)\n"); } printf(" [%d] fmac_total_steps : %d\n", (int)l_idx, (int)frn_elem->fmac_total_steps ); printf(" [%d] frame_from : %.4f\n", (int)l_idx, (float)frn_elem->frame_from ); printf(" [%d] frame_to : %.4f\n", (int)l_idx, (float)frn_elem->frame_to ); printf(" [%d] frames_to_handle : %d\n", (int)l_idx, (int)frn_elem->frames_to_handle); printf(" [%d] delta : %d\n", (int)l_idx, (int)frn_elem->delta ); printf(" [%d] step_density : %.4f\n", (int)l_idx, (float)frn_elem->step_density ); if(frn_elem->keep_proportions) {printf(" [%d] keep_proportions : TRUE\n", (int)l_idx );} else {printf(" [%d] keep_proportions : FALSE\n", (int)l_idx );} if(frn_elem->fit_width) {printf(" [%d] fit_width : TRUE\n", (int)l_idx );} else {printf(" [%d] fit_width : FALSE\n", (int)l_idx );} if(frn_elem->fit_height) {printf(" [%d] fit_height : TRUE\n", (int)l_idx );} else {printf(" [%d] fit_height : FALSE\n", (int)l_idx );} printf(" [%d] flip_request : %d\n", (int)l_idx, (int)frn_elem->flip_request ); if(frn_elem->mask_name) { printf(" [%d] mask_name : %s\n", (int)l_idx, frn_elem->mask_name); printf(" [%d] mask_anchor : %d\n", (int)l_idx, (int)frn_elem->mask_anchor ); printf(" [%d] mask_stepsize : %.4f\n", (int)l_idx, (float)frn_elem->mask_stepsize ); printf(" [%d] mask_framecount : %.4f\n", (int)l_idx, (float)frn_elem->mask_framecount ); } else { printf(" [%d] mask_name : (null)\n", (int)l_idx ); } printf(" [%d] wait_untiltime_sec : %f\n", (int)l_idx, (float)frn_elem->wait_untiltime_sec ); printf(" [%d] wait_untilframes : %d\n", (int)l_idx, (int)frn_elem->wait_untilframes ); printf(" [%d] opacity_from : %f\n", (int)l_idx, (float)frn_elem->opacity_from ); printf(" [%d] opacity_to : %f\n", (int)l_idx, (float)frn_elem->opacity_to ); printf(" [%d] opacity_dur : %d\n", (int)l_idx, (int)frn_elem->opacity_dur ); printf(" [%d] scale_x_from : %f\n", (int)l_idx, (float)frn_elem->scale_x_from ); printf(" [%d] scale_x_to : %f\n", (int)l_idx, (float)frn_elem->scale_x_to ); printf(" [%d] scale_x_dur : %d\n", (int)l_idx, frn_elem->scale_x_dur ); printf(" [%d] scale_y_from : %f\n", (int)l_idx, (float)frn_elem->scale_y_from ); printf(" [%d] scale_y_to : %f\n", (int)l_idx, (float)frn_elem->scale_y_to ); printf(" [%d] scale_y_dur : %d\n", (int)l_idx, (int)frn_elem->scale_y_dur ); printf(" [%d] move_x_from : %f\n", (int)l_idx, (float)frn_elem->move_x_from ); printf(" [%d] move_x_to : %f\n", (int)l_idx, (float)frn_elem->move_x_to ); printf(" [%d] move_x_dur : %d\n", (int)l_idx, (int)frn_elem->move_x_dur ); printf(" [%d] move_y_from : %f\n", (int)l_idx, (float)frn_elem->move_y_from ); printf(" [%d] move_y_to : %f\n", (int)l_idx, (float)frn_elem->move_y_to ); printf(" [%d] move_y_dur : %d\n", (int)l_idx, (int)frn_elem->move_y_dur ); } } /* end gap_story_render_debug_print_frame_elem */ /* ---------------------------------------------------- * p_debug_print_render_section_names * ---------------------------------------------------- * print section_name and pointers as debug information to stdout, */ static void p_debug_print_render_section_names(GapStoryRenderVidHandle *vidhand) { GapStoryRenderSection *section; printf("\nDEBUG p_debug_print_render_section_names START\n"); for(section = vidhand->section_list; section != NULL; section = section->next) { printf("DEBUG render_section: adr vidhand:%d section:%d section->frn_list:%d)" , (int)vidhand , (int)section , (int)section->frn_list ); if (section->section_name == NULL) { printf("section_name: (null) e.g. MAIN\n"); } else { printf("section->section_name: %s\n", section->section_name); } } printf("DEBUG p_debug_print_render_section_names END\n"); fflush(stdout); } /* end p_debug_print_render_section_names */ /* ---------------------------------------------------- * gap_story_render_debug_print_framerange_list * ---------------------------------------------------- * print all List elements for the given track * (negative track number will print all elements) */ void gap_story_render_debug_print_framerange_list(GapStoryRenderFrameRangeElem *frn_list , gint32 track /* -1 show all tracks */ ) { GapStoryRenderFrameRangeElem *frn_elem; gint l_idx; printf("\ngap_story_render_debug_print_framerange_list: START\n"); l_idx = 0; for(frn_elem = frn_list; frn_elem != NULL; frn_elem = (GapStoryRenderFrameRangeElem *)frn_elem->next) { if((frn_elem->track == track) || (track < 0)) { gap_story_render_debug_print_frame_elem(frn_elem, l_idx); } l_idx++; } printf("gap_story_render_debug_print_framerange_list: END\n"); fflush(stdout); } /* end gap_story_render_debug_print_framerange_list */ /* ---------------------------------------------------- * gap_story_render_debug_print_audiorange_list * ---------------------------------------------------- * print all List elements for the given track * (negative track number will print all elements) */ void gap_story_render_debug_print_audiorange_list(GapStoryRenderAudioRangeElem *aud_list , gint32 track /* -1 show all tracks */ ) { GapStoryRenderAudioRangeElem *aud_elem; gint l_idx; printf("\ngap_story_render_debug_print_audiorange_list: START\n"); l_idx = 0; for(aud_elem = aud_list; aud_elem != NULL; aud_elem = (GapStoryRenderAudioRangeElem *)aud_elem->next) { if((aud_elem->track == track) || (track < 0)) { printf("\n [%d] aud_type : %d\n", (int)l_idx, (int)aud_elem->aud_type ); printf(" [%d] track : %d\n", (int)l_idx, (int)aud_elem->track ); printf(" [%d] audiofile : ", (int)l_idx); if(aud_elem->audiofile) { printf("%s\n", aud_elem->audiofile );} else { printf ("(null)\n"); } printf(" [%d] tmp_audiofile : ", (int)l_idx); if(aud_elem->tmp_audiofile) { printf("%s\n", aud_elem->tmp_audiofile );} else { printf ("(null)\n"); } printf(" [%d] gvahand : %d\n", (int)l_idx, (int)aud_elem->gvahand ); printf(" [%d] seltrack : %d\n", (int)l_idx, (int)aud_elem->seltrack ); printf(" [%d] samplerate : %d\n", (int)l_idx, (int)aud_elem->samplerate ); printf(" [%d] channels : %d\n", (int)l_idx, (int)aud_elem->channels ); printf(" [%d] bytes_per_sample : %d\n", (int)l_idx, (int)aud_elem->bytes_per_sample ); printf(" [%d] samples : %d\n", (int)l_idx, (int)aud_elem->samples ); printf(" [%d] audio_id : %d\n", (int)l_idx, (int)aud_elem->audio_id); printf(" [%d] aud_data : %d\n", (int)l_idx, (int)aud_elem->aud_data); printf(" [%d] aud_bytelength : %d\n", (int)l_idx, (int)aud_elem->aud_bytelength); printf(" [%d] range_samples : %d\n", (int)l_idx, (int)aud_elem->range_samples ); printf(" [%d] fade_in_samples : %d\n", (int)l_idx, (int)aud_elem->fade_in_samples ); printf(" [%d] fade_out_samples : %d\n", (int)l_idx, (int)aud_elem->fade_out_samples ); printf(" [%d] offset_rangestart : %d\n", (int)l_idx, (int)aud_elem->byteoffset_rangestart ); printf(" [%d] byteoffset_data : %d\n", (int)l_idx, (int)aud_elem->byteoffset_data ); printf(" [%d] wait_untiltime_sec: %f\n", (int)l_idx, (float)aud_elem->wait_untiltime_sec ); printf(" [%d] wait_until_samples: %d\n", (int)l_idx, (int)aud_elem->wait_until_samples ); printf(" [%d] max_playtime_sec : %f\n", (int)l_idx, (float)aud_elem->max_playtime_sec ); printf(" [%d] range_playtime_sec: %f\n", (int)l_idx, (float)aud_elem->range_playtime_sec ); printf(" [%d] play_from_sec : %f\n", (int)l_idx, (float)aud_elem->play_from_sec ); printf(" [%d] play_to_sec : %f\n", (int)l_idx, (float)aud_elem->play_to_sec ); printf(" [%d] volume_start : %f\n", (int)l_idx, (float)aud_elem->volume_start ); printf(" [%d] volume : %f\n", (int)l_idx, (float)aud_elem->volume ); printf(" [%d] volume_end : %f\n", (int)l_idx, (float)aud_elem->volume_end ); printf(" [%d] fade_in_sec : %f\n", (int)l_idx, (float)aud_elem->fade_in_sec ); printf(" [%d] fade_out_sec : %f\n", (int)l_idx, (float)aud_elem->fade_out_sec ); } l_idx++; } printf("gap_story_render_debug_print_audiorange_list: END\n"); fflush(stdout); } /* end gap_story_render_debug_print_audiorange_list */ /* ---------------------------------------------------- * p_frame_backup_save * ---------------------------------------------------- */ static void p_frame_backup_save( char *key , gint32 image_id , gint32 layer_id , gint32 master_frame_nr , gboolean multilayer ) { gint32 l_len; char *l_framename; char *l_basename; l_len = gimp_get_data_size(key); if(l_len <= 0) { return; } l_basename = g_malloc0(l_len); gimp_get_data(key, l_basename); if(*l_basename != '\0') { if(multilayer) { l_framename = gap_lib_alloc_fname(l_basename, master_frame_nr, ".xcf"); } else { l_framename = gap_lib_alloc_fname(l_basename, master_frame_nr, ".png"); } if(gap_debug) printf("Debug: Saving frame to file: %s\n", l_framename); gimp_file_save(GIMP_RUN_WITH_LAST_VALS, image_id, layer_id, l_framename, l_framename); g_free(l_framename); } g_free(l_basename); } /* end p_frame_backup_save */ /* ---------------------------------------------------- * p_debug_dup_image * ---------------------------------------------------- * Duplicate image, and open a display for the duplicate * (Procedure is used for debug only */ static void p_debug_dup_image(gint32 image_id) { gint32 l_dup_image_id; l_dup_image_id = gimp_image_duplicate(image_id); gimp_display_new(l_dup_image_id); } /* end p_debug_dup_image */ /* ---------------------------------------------------- * p_encoding_monitor * ---------------------------------------------------- * monitor the image before passed to the encoder. * - at 1.st call open global_monitor_image_id * and add a display. * - on all further calls copy the composite layer * to the global_monitor_image_id */ static void p_encoding_monitor( char *key , gint32 image_id , gint32 layer_id , gint32 master_frame_nr ) { gint32 l_len; char *l_true_or_false; l_len = gimp_get_data_size(key); if(l_len <= 0) { return; } l_true_or_false = g_malloc0(l_len); gimp_get_data(key, l_true_or_false); if(*l_true_or_false == 'T') { char *l_imagename; printf("Monitoring image_id: %d, layer_id:%d master_frame:%d\n", (int)image_id, (int)layer_id ,(int)master_frame_nr ); l_imagename = g_strdup_printf(_("encoding_video_frame_%06d"), (int)master_frame_nr); if(global_monitor_image_id < 0) { global_monitor_image_id = gimp_image_duplicate(image_id); global_monitor_display_id = gimp_display_new(global_monitor_image_id); gimp_image_set_filename(global_monitor_image_id, l_imagename); } else { gint l_nlayers; gint32 *l_layers_list; gint32 l_fsel_layer_id; l_layers_list = gimp_image_get_layers(global_monitor_image_id, &l_nlayers); if(l_layers_list != NULL) { gimp_selection_none(image_id); /* if there is no selection, copy the complete layer */ gimp_selection_none(global_monitor_image_id); /* if there is no selection, copy the complete layer */ gimp_edit_copy(layer_id); l_fsel_layer_id = gimp_edit_paste(l_layers_list[0], FALSE); /* FALSE paste clear selection */ gimp_floating_sel_anchor(l_fsel_layer_id); g_free (l_layers_list); gimp_image_set_filename(global_monitor_image_id, l_imagename); gimp_displays_flush(); } else { printf("no more MONITORING, (user has closed monitor image)\n"); } } g_free(l_imagename); } g_free(l_true_or_false); } /* end p_encoding_monitor */ /* -------------------------------- * p_init_stb_error * -------------------------------- */ static void p_init_stb_error(GapStoryRenderErrors *sterr) { if(sterr->errtext) { g_free(sterr->errtext); } if(sterr->errline) { g_free(sterr->errline); } if(sterr->warntext) { g_free(sterr->warntext); } if(sterr->warnline) { g_free(sterr->warnline); } sterr->errtext = NULL; sterr->errline = NULL; sterr->warntext = NULL; sterr->warnline = NULL; sterr->currline = NULL; sterr->errline_nr = 0; sterr->warnline_nr = 0; sterr->curr_nr = 0; } /* end p_init_stb_error */ /* -------------------------------- * p_new_stb_error * -------------------------------- */ static GapStoryRenderErrors * p_new_stb_error(void) { GapStoryRenderErrors *sterr; sterr = g_malloc0(sizeof(GapStoryRenderErrors)); p_init_stb_error(sterr); return(sterr); } /* end p_new_stb_error */ /* -------------------------------- * p_free_stb_error * -------------------------------- */ static void p_free_stb_error(GapStoryRenderErrors *sterr) { p_init_stb_error(sterr); g_free(sterr); } /* end p_free_stb_error */ /* -------------------------------- * p_set_stb_error * -------------------------------- */ static void p_set_stb_error(GapStoryRenderErrors *sterr, char *errtext) { printf("** error: %s\n [at line:%d] %s\n" , errtext , (int)sterr->curr_nr , sterr->currline ); if(sterr->errtext == NULL) { sterr->errtext = g_strdup(errtext); sterr->errline_nr = sterr->curr_nr; sterr->errline = g_strdup(sterr->currline); } } /* end p_set_stb_error */ /* -------------------------------- * gap_story_render_set_stb_error * -------------------------------- */ void gap_story_render_set_stb_error(GapStoryRenderErrors *sterr, char *errtext) { p_set_stb_error(sterr, errtext); } /* end gap_story_render_set_stb_error */ /* -------------------------------- * gap_story_render_set_stb_warning * -------------------------------- */ void gap_story_render_set_stb_warning(GapStoryRenderErrors *sterr, char *warntext) { printf("** warning: %s\n [at line:%d] %s\n" , warntext , (int)sterr->curr_nr , sterr->currline ); if(sterr->warntext == NULL) { sterr->warntext = g_strdup(warntext); sterr->warnline_nr = sterr->curr_nr; sterr->warnline = g_strdup(sterr->currline); } } /* end gap_story_render_set_stb_warning */ /* ---------------------------------------------------- * p_find_min_max_vid_tracknumbers * ---------------------------------------------------- * findout the lowest and highest track number used * in the framerange list */ static void p_find_min_max_vid_tracknumbers(GapStoryRenderFrameRangeElem *frn_list , gint32 *lowest_tracknr , gint32 *highest_tracknr ) { GapStoryRenderFrameRangeElem *frn_elem; *lowest_tracknr = GAP_STB_MAX_VID_INTERNAL_TRACKS; *highest_tracknr = -1; for(frn_elem = frn_list; frn_elem != NULL; frn_elem = (GapStoryRenderFrameRangeElem *)frn_elem->next) { if (frn_elem->track > *highest_tracknr) { *highest_tracknr = frn_elem->track; } if (frn_elem->track < *lowest_tracknr) { *lowest_tracknr = frn_elem->track; } } if(gap_debug) printf("p_find_min_max_vid_tracknumbers: min:%d max:%d\n", (int)*lowest_tracknr, (int)*highest_tracknr); } /* end p_find_min_max_vid_tracknumbers */ /* --------------------------------------- * p_step_attribute * --------------------------------------- * calculate remaining attribute value after N frames_handled * and change *from_val and *dur accordingly */ static void p_step_attribute(gint32 frames_handled ,gdouble *from_val ,gdouble *to_val ,gint32 *dur ) { gint32 l_rest_steps; gdouble step_delta_val; l_rest_steps = *dur - frames_handled; if((l_rest_steps <= 0) || (*dur <= 0)) { *from_val = *to_val; *dur = 0; } else { step_delta_val = (*to_val - *from_val) / (gdouble)(*dur); *from_val = *to_val - (step_delta_val * l_rest_steps) ; *dur = l_rest_steps; } } /* end p_step_attribute */ /* -------------------------------- * p_step_attribute_read * -------------------------------- * return attribute value after N frame steps */ static gdouble p_step_attribute_read(gint32 frame_step ,gdouble from_val ,gdouble to_val ,gint32 dur ) { gdouble l_from_val; gdouble l_to_val; gint32 l_dur; l_from_val = from_val; l_to_val = to_val; l_dur = dur; p_step_attribute( frame_step , &l_from_val , &l_to_val , &l_dur ); return(l_from_val); } /* end p_step_attribute */ /* ---------------------------------------------------- * p_select_section_by_name * ---------------------------------------------------- * switch to specified section by * setting frn_list and aud_list pointers of the specified video handle vidhand * to the sub list of to the specified section_name. * section_name NULL refers to the main section. * at unknown section_name's set both pointers to NULL. */ static void p_select_section_by_name(GapStoryRenderVidHandle *vidhand, const char *section_name) { GapStoryRenderSection *section; for(section = vidhand->section_list; section != NULL; section = section->next) { if (section_name == NULL) { if (section->section_name == NULL) { if(gap_debug) { printf("p_select_section_by_name: null (switch to MAIN section)\n"); fflush(stdout); } break; } } else { if (section->section_name != NULL) { if (strcmp(section->section_name, section_name) == 0) { if(gap_debug) { printf("p_select_section_by_name: (switch to SUB-SECTION: %s)\n", section_name); fflush(stdout); } break; } } } } if (section != NULL) { vidhand->frn_list = section->frn_list; vidhand->aud_list = section->aud_list; } else { vidhand->frn_list = NULL; vidhand->aud_list = NULL; } if(gap_debug) { printf("p_select_section_by_name: addr of section: %d Resulting addr of frn_list: %d)\n" , (int)section , (int)vidhand->frn_list ); fflush(stdout); } } /* end p_select_section_by_name */ /* ---------------------------------------------------- * p_fetch_framename * ---------------------------------------------------- * fetch framename for a given master_frame_nr in the given video track * within a storyboard framerange list. * (simple animations without a storyboard file * are represented by a short storyboard framerange list that has * just one element entry at track 1). * * output gduoble attribute values (opacity, scale, move) for the frame * at track and master_frame_nr position. * * return the name of the frame (that is to be displayed at position master_frame_nr). * return NULL if there is no frame at desired track and master_frame_nr */ static char * p_fetch_framename(GapStoryRenderFrameRangeElem *frn_list , gint32 master_frame_nr /* starts at 1 */ , gint32 track , GapStoryRenderFrameType *frn_type , char **filtermacro_file , gint32 *localframe_index /* starts at 1, used for ANIMIMAGE and VIDEOFILES, -1 for all other types */ , gint32 *local_stepcount /* nth frame within this clip, starts with 0 */ , gdouble *localframe_tween_rest /* non-integer part of the position. value < 1.0 for tween fetching */ , gboolean *keep_proportions , gboolean *fit_width , gboolean *fit_height , gdouble *red_f , gdouble *green_f , gdouble *blue_f , gdouble *alpha_f , gdouble *opacity /* output opacity 0.0 upto 1.0 */ , gdouble *scale_x /* output 0.0 upto 10.0 where 1.0 is 1:1 */ , gdouble *scale_y /* output 0.0 upto 10.0 where 1.0 is 1:1 */ , gdouble *move_x /* output -1.0 upto 1.0 where 0.0 is centered */ , gdouble *move_y /* output -1.0 upto 1.0 where 0.0 is centered */ , GapStoryRenderFrameRangeElem **frn_elem_ptr /* OUT pointer to the relevant framerange element */ ) { GapStoryRenderFrameRangeElem *frn_elem; char *l_framename; gint32 l_frame_group_count; gint32 l_fnr; gint32 l_step; gint32 l_found_at_idx; gint32 l_frames_to_handle; l_frame_group_count = 0; l_framename = NULL; /* default attributes (used if storyboard does not define settings) */ *opacity = 1.0; *scale_x = 1.0; *scale_y = 1.0; *move_x = 0.0; *move_y = 0.0; *localframe_index = -1; *local_stepcount = 0; *localframe_tween_rest = 0.0; *frn_type = GAP_FRN_SILENCE; *keep_proportions = FALSE; *fit_width = TRUE; *fit_height = TRUE; *red_f = 0.0; *green_f = 0.0; *blue_f = 0.0; *alpha_f = 1.0; *filtermacro_file = NULL; *frn_elem_ptr = NULL; l_found_at_idx=0; for (frn_elem = frn_list; frn_elem != NULL; frn_elem = (GapStoryRenderFrameRangeElem *)frn_elem->next) { if(frn_elem->track == track) { l_frames_to_handle = frn_elem->frames_to_handle; if (frn_elem->wait_untiltime_sec > 0) { l_frames_to_handle += MAX(0, frn_elem->wait_untilframes - l_frame_group_count); } if (master_frame_nr <= l_frame_group_count + l_frames_to_handle) { gdouble fnr; /* calculate positive or negative offset from_frame to desired frame */ fnr = (gdouble)(frn_elem->delta * (master_frame_nr - (l_frame_group_count +1 ))) * frn_elem->step_density; /* calculate framenumber local to the clip */ l_fnr = (gint32)(frn_elem->frame_from + fnr); { gint32 fnrInt; fnrInt = fnr; /* truncate to integer */ *localframe_tween_rest = fnr - fnrInt; if(gap_debug) { printf("fnr:%.4f, fnrInt:%d localframe_tween_rest:%.4f\n" ,(float)fnr ,(int)fnrInt ,(float)*localframe_tween_rest ); } } *local_stepcount = master_frame_nr - l_frame_group_count; *local_stepcount -= 1; switch(frn_elem->frn_type) { case GAP_FRN_SILENCE: case GAP_FRN_COLOR: l_framename = NULL; /* there is no filename for video silence or unicolor */ break; case GAP_FRN_IMAGE: l_framename = g_strdup(frn_elem->basename); /* use 1:1 basename for single images */ break; case GAP_FRN_ANIMIMAGE: l_framename = g_strdup(frn_elem->basename); /* use 1:1 basename for ainimated single images */ *localframe_index = l_fnr; /* local frame number is index in the layerstack */ break; case GAP_FRN_MOVIE: /* video file frame numners start at 1 */ l_framename = g_strdup(frn_elem->basename); /* use 1:1 basename for videofiles */ *localframe_index = l_fnr; /* local frame number is the wanted video frame number */ break; case GAP_FRN_FRAMES: l_framename = gap_lib_alloc_fname(frn_elem->basename ,l_fnr ,frn_elem->ext ); break; case GAP_FRN_SECTION: /* frame numners in storyboard sections start at 1 */ l_framename = g_strdup(frn_elem->basename); /* section_name 1:1 for STB sections */ *localframe_index = l_fnr; /* local frame number is the wanted video frame number */ break; } /* return values for current fixed attribute settings */ *frn_type = frn_elem->frn_type; *keep_proportions = frn_elem->keep_proportions; *fit_width = frn_elem->fit_width; *fit_height = frn_elem->fit_height; *red_f = frn_elem->red_f; *green_f = frn_elem->green_f; *blue_f = frn_elem->blue_f; *alpha_f = frn_elem->alpha_f; *filtermacro_file = frn_elem->filtermacro_file; frn_elem->last_master_frame_access = master_frame_nr; *frn_elem_ptr = frn_elem; /* deliver pointer to the current frn_elem */ /* calculate effect attributes for the current step * where l_step = 0 at the 1.st frame of the local range */ l_step = (master_frame_nr - 1) - l_frame_group_count; *opacity = p_step_attribute_read(l_step , frn_elem->opacity_from , frn_elem->opacity_to , frn_elem->opacity_dur ); *scale_x = p_step_attribute_read(l_step , frn_elem->scale_x_from , frn_elem->scale_x_to , frn_elem->scale_x_dur ); *scale_y = p_step_attribute_read(l_step , frn_elem->scale_y_from , frn_elem->scale_y_to , frn_elem->scale_y_dur ); *move_x = p_step_attribute_read(l_step , frn_elem->move_x_from , frn_elem->move_x_to , frn_elem->move_x_dur ); *move_y = p_step_attribute_read(l_step , frn_elem->move_y_from , frn_elem->move_y_to , frn_elem->move_y_dur ); break; } l_frame_group_count += l_frames_to_handle; } l_found_at_idx++; } if(gap_debug) { printf("p_fetch_framename: track:%d master_frame_nr:%d framename:%s: found_at_idx:%d opa:%f scale:%f %f move:%f %f layerstack_idx:%d\n" ,(int)track ,(int)master_frame_nr , l_framename ,(int)l_found_at_idx , (float)*opacity , (float)*scale_x , (float)*scale_y , (float)*move_x , (float)*move_y , (int)*localframe_index ); } return l_framename; } /* end p_fetch_framename */ /* --------------------------------- * p_calculate_frames_to_handle * --------------------------------- */ static void p_calculate_frames_to_handle(GapStoryRenderFrameRangeElem *frn_elem) { gdouble fnr; if(frn_elem->step_density <= 0) { /* force legal value */ frn_elem->step_density = 1.0; } fnr = (gdouble)(ABS(frn_elem->frame_from - frn_elem->frame_to) +1); fnr = fnr / frn_elem->step_density; frn_elem->frames_to_handle = MAX((gint32)(fnr + 0.5), 1); } /* end p_calculate_frames_to_handle */ /* ---------------------------------------------------- * p_new_framerange_element * ---------------------------------------------------- * allocate a new GapStoryRenderFrameRangeElem for storyboard processing * - read directory to check for first and last available frame Number * for the given filename and extension. * - findout processing order (1 ascending, -1 descending) * - findout frames_to_handle in the given range. * * Single images are added with frn_type == GAP_FRN_IMAGE * and frame_from = 1 * and frame_to = N (10 if image is to display for duration of 10 frames) * * return GapStoryRenderFrameRangeElem with allocated copies of basename and ext strings. */ static GapStoryRenderFrameRangeElem * p_new_framerange_element(GapStoryRenderFrameType frn_type ,gint32 track ,const char *basename /* basename or full imagename for frn_type GAP_FRN_IMAGE */ ,const char *ext /* NULL for frn_type GAP_FRN_IMAGE and GAP_FRN_MOVIE */ ,gint32 frame_from /* IN: range start */ ,gint32 frame_to /* IN: range end */ ,const char *storyboard_file /* IN: NULL if no storyboard file is used */ ,const char *preferred_decoder /* IN: NULL if no preferred_decoder is specified */ ,const char *filtermacro_file /* IN: NULL, or name of the macro file */ ,GapStoryRenderFrameRangeElem *frn_list /* NULL or list of already known ranges */ ,GapStoryRenderErrors *sterr /* element to store Error/Warning report */ ,gint32 seltrack /* IN: select videotrack number 1 upto 99 for GAP_FRN_MOVIE */ ,gint32 exact_seek /* IN: 0 fast seek, 1 exact seek (only for GVA Videoreads) */ ,gdouble delace /* IN: 0.0 no deinterlace, 1.0-1.99 odd 2.0-2.99 even rows (only for GVA Videoreads) */ ,gdouble step_density /* IN: 1==normal stepsize 1:1 0.5 == each frame twice, 2.0 only every 2nd frame */ ,gint32 flip_request /* 0 NONE, 1 flip horizontal, 2 flip vertical, 3 rotate 180degree */ ,const char *mask_name /* reference to layer mask definition */ ,gdouble mask_stepsize /* stepsize for the layer mask */ ,GapStoryMaskAnchormode mask_anchor /* how to apply the layer mask */ ,gboolean mask_disable ,gint32 fmac_total_steps ) { GapStoryRenderFrameRangeElem *frn_elem; if(gap_debug) { printf("\np_new_framerange_element: START frn_type:%d\n", (int)frn_type); printf(" track:%d:\n", (int)track); printf(" frame_from:%d:\n", (int)frame_from); printf(" frame_to:%d:\n", (int)frame_to); printf(" step_density:%f:\n", (float)step_density); if(basename) printf(" basename:%s:\n", basename); if(ext) printf(" ext:%s:\n", ext); if(storyboard_file) printf(" storyboard_file:%s:\n", storyboard_file); if(preferred_decoder) printf(" preferred_decoder:%s:\n", preferred_decoder); } frn_elem = g_malloc0(sizeof(GapStoryRenderFrameRangeElem)); frn_elem->frn_type = frn_type; frn_elem->track = track; frn_elem->frame_from = frame_from; frn_elem->frame_to = frame_to; frn_elem->frames_to_handle = 0; frn_elem->delta = 1; frn_elem->step_density = step_density; frn_elem->last_master_frame_access = -1; /* -1 indicate that there was no access */ frn_elem->flip_request = flip_request; frn_elem->mask_framecount = 0; frn_elem->mask_stepsize = mask_stepsize; frn_elem->mask_anchor = mask_anchor; /* disabled masks are ignored for storyboard processing * by using a mask_name == NULL */ frn_elem->mask_name = NULL; if(!mask_disable) { if(mask_name) { frn_elem->mask_name = g_strdup(mask_name); } } /* default attributes (used if storyboard does not define settings) */ frn_elem->red_f = 0.0; frn_elem->green_f = 0.0; frn_elem->blue_f = 0.0; frn_elem->alpha_f = 1.0; frn_elem->keep_proportions = FALSE; frn_elem->fit_width = TRUE; frn_elem->fit_height = TRUE; frn_elem->wait_untiltime_sec = 0.0; frn_elem->wait_untilframes = 0; frn_elem->opacity_from = 1.0; frn_elem->opacity_to = 1.0; frn_elem->opacity_dur = 0; frn_elem->scale_x_from = 1.0; frn_elem->scale_x_to = 1.0; frn_elem->scale_x_dur = 0; frn_elem->scale_y_from = 1.0; frn_elem->scale_y_to = 1.0; frn_elem->scale_y_dur = 0; frn_elem->move_x_from = 0.0; frn_elem->move_x_to = 0.0; frn_elem->move_x_dur = 0; frn_elem->move_y_from = 0.0; frn_elem->move_y_to = 0.0; frn_elem->move_y_dur = 0; frn_elem->filtermacro_file = NULL; frn_elem->filtermacro_file_to = NULL; frn_elem->fmac_total_steps = 1; frn_elem->gvahand = NULL; frn_elem->seltrack = seltrack; frn_elem->exact_seek = exact_seek; frn_elem->delace = delace; frn_elem->next = NULL; if(ext) { if(*ext == '.') { frn_elem->ext = g_strdup(ext); } else { frn_elem->ext = g_strdup_printf(".%s", ext); } } /* check basename for absolute pathname. * Except for frn_type GAP_FRN_SECTION, where basename * refers to a section_name and not to a filename(part). */ if(basename) { if (frn_type == GAP_FRN_SECTION) { frn_elem->basename = g_strdup(basename); } else { frn_elem->basename = gap_file_make_abspath_filename(basename, storyboard_file); } } /* end check for absolute pathname */ /* check filtermacro_file for absolute pathname */ frn_elem->fmac_total_steps = fmac_total_steps; frn_elem->filtermacro_file = NULL; if(filtermacro_file) { if(*filtermacro_file != '\0') { frn_elem->filtermacro_file = gap_file_make_abspath_filename(filtermacro_file, storyboard_file); if(!g_file_test(frn_elem->filtermacro_file, G_FILE_TEST_EXISTS)) { char *l_errtxt; l_errtxt = g_strdup_printf("filtermacro_file not found: %s", frn_elem->filtermacro_file); p_set_stb_error(sterr, l_errtxt); g_free(l_errtxt); g_free(frn_elem->filtermacro_file); frn_elem->filtermacro_file = NULL; } else { frn_elem->filtermacro_file_to = gap_fmac_get_alternate_name(filtermacro_file); if(frn_elem->filtermacro_file_to) { if(!gap_fmac_chk_filtermacro_file(frn_elem->filtermacro_file_to)) { g_free(frn_elem->filtermacro_file_to); frn_elem->filtermacro_file_to = NULL; } } } } } /* check processing order delta */ if (frn_elem->frame_from > frn_elem->frame_to) { frn_elem->delta = -1; /* -1 is inverse (descending) order */ } else { frn_elem->delta = 1; /* +1 is normal (ascending) order */ } /* calculate frames_to_handle respecting step_density */ p_calculate_frames_to_handle(frn_elem); if(gap_debug) { if(frn_elem->basename) printf("\np_new_framerange_element: frn_elem->basename:%s:\n", frn_elem->basename); if(frn_elem->ext) printf("p_new_framerange_element: frn_elem->ext:%s:\n",frn_elem->ext); printf("p_new_framerange_element: frn_elem->frame_from:%d:\n", (int)frn_elem->frame_from); printf("p_new_framerange_element: frn_elem->frame_to:%d:\n", (int)frn_elem->frame_to); printf("p_new_framerange_element: frn_elem->frames_to_handle:%d:\n", (int)frn_elem->frames_to_handle); printf("\np_new_framerange_element: END\n"); } return(frn_elem); } /* end p_new_framerange_element */ /* -------------------------------- * p_add_frn_list * -------------------------------- */ static void p_add_frn_list(GapStoryRenderVidHandle *vidhand, GapStoryRenderFrameRangeElem *frn_elem) { GapStoryRenderFrameRangeElem *frn_listend; if((vidhand) && (frn_elem)) { if(vidhand->parsing_section == NULL) { printf("** INTERNAL ERROR parsing_section is NULL\n"); return; } frn_listend = vidhand->parsing_section->frn_list; if (vidhand->parsing_section->frn_list == NULL) { /* 1. element (or returned list) starts frn_list */ vidhand->parsing_section->frn_list = frn_elem; } else { /* link frn_elem (that can be a single ement or list) to the end of frn_list */ frn_listend = vidhand->parsing_section->frn_list; while(frn_listend->next != NULL) { frn_listend = (GapStoryRenderFrameRangeElem *)frn_listend->next; } frn_listend->next = (GapStoryRenderFrameRangeElem *)frn_elem; } } } /* end p_add_frn_list */ /* ---------------------------------------------------- * p_step_all_vtrack_attributes * ---------------------------------------------------- */ static void p_step_all_vtrack_attributes(gint32 track , gint32 frames_to_handle , GapStoryRenderVTrackArray *vtarr ) { p_step_attribute( frames_to_handle , &vtarr->attr[track].opacity_from , &vtarr->attr[track].opacity_to , &vtarr->attr[track].opacity_dur ); p_step_attribute( frames_to_handle , &vtarr->attr[track].scale_x_from , &vtarr->attr[track].scale_x_to , &vtarr->attr[track].scale_x_dur ); p_step_attribute( frames_to_handle , &vtarr->attr[track].scale_y_from , &vtarr->attr[track].scale_y_to , &vtarr->attr[track].scale_y_dur ); p_step_attribute( frames_to_handle , &vtarr->attr[track].move_x_from , &vtarr->attr[track].move_x_to , &vtarr->attr[track].move_x_dur ); p_step_attribute( frames_to_handle , &vtarr->attr[track].move_y_from , &vtarr->attr[track].move_y_to , &vtarr->attr[track].move_y_dur ); } /* end p_step_all_vtrack_attributes */ /* ---------------------------------------------------- * p_set_vtrack_attributes * ---------------------------------------------------- * set current video track attributes for the * Framerange_Element. from the current attribute array. * * attribute array is changed to the state after * the playback of the Framerange_element. * * Example for fade_in Attribute settings: * IN: opacity_from: 0.0 opacity_to: 1.0 opacity_dur: 50 frames * if the range has 50 or more frames * the fade_in can be handled fully within the range, * the result will be: * OUT: opacity_from: 1.0 opacity_to: 1.0 opacity_dur: 0 frames * * if the range is for example 25 frames (smaller than the duration 50) * the result will be: * OUT: opacity_from: 0.5 opacity_to: 1.0 opacity_dur: 25 frames * because there are 25 rest frames to complete the fade in action * in the next range (if there will be any) * */ static void p_set_vtrack_attributes(GapStoryRenderFrameRangeElem *frn_elem ,GapStoryRenderVTrackArray *vtarr ) { gint32 track; track = frn_elem->track; frn_elem->keep_proportions = vtarr->attr[track].keep_proportions; frn_elem->fit_width = vtarr->attr[track].fit_width; frn_elem->fit_height = vtarr->attr[track].fit_height; frn_elem->mask_framecount = vtarr->attr[track].mask_framecount; frn_elem->opacity_from = vtarr->attr[track].opacity_from; frn_elem->opacity_to = vtarr->attr[track].opacity_to; frn_elem->opacity_dur = vtarr->attr[track].opacity_dur; frn_elem->scale_x_from = vtarr->attr[track].scale_x_from; frn_elem->scale_x_to = vtarr->attr[track].scale_x_to; frn_elem->scale_x_dur = vtarr->attr[track].scale_x_dur; frn_elem->scale_y_from = vtarr->attr[track].scale_y_from; frn_elem->scale_y_to = vtarr->attr[track].scale_y_to; frn_elem->scale_y_dur = vtarr->attr[track].scale_y_dur; frn_elem->move_x_from = vtarr->attr[track].move_x_from; frn_elem->move_x_to = vtarr->attr[track].move_x_to; frn_elem->move_x_dur = vtarr->attr[track].move_x_dur; frn_elem->move_y_from = vtarr->attr[track].move_y_from; frn_elem->move_y_to = vtarr->attr[track].move_y_to; frn_elem->move_y_dur = vtarr->attr[track].move_y_dur; /* advance mask_framecount */ vtarr->attr[track].mask_framecount += frn_elem->frames_to_handle; p_step_all_vtrack_attributes(track, frn_elem->frames_to_handle, vtarr); } /* end p_set_vtrack_attributes */ /* --------------------------------- * p_vidclip_add_as_is * --------------------------------- * set vtrack attribtes and add the frn_elem to the * list of videoclips (frn_list). * NOTE: the mask_framecount is set from current vattr context. */ static void p_vidclip_add_as_is(GapStoryRenderFrameRangeElem *frn_elem ,GapStoryRenderVidHandle *vidhand ,GapStoryRenderVTrackArray *vtarr ) { if(frn_elem) { vtarr->attr[frn_elem->track].frame_count += frn_elem->frames_to_handle; p_set_vtrack_attributes(frn_elem, vtarr); p_add_frn_list(vidhand, frn_elem); if(gap_debug) { printf("#------------------ \n"); gap_story_render_debug_print_frame_elem(frn_elem, -4); printf("\n#------------------ \n"); } } } /* end p_vidclip_add_as_is */ /* --------------------------------- * p_vidclip_shadow_add_silence * --------------------------------- */ static void p_vidclip_shadow_add_silence(gint32 shadow_track ,gint32 fill_shadow_frames ,GapStoryRenderVidHandle *vidhand ,GapStoryRenderVTrackArray *vtarr ,const char *storyboard_file) { GapStoryRenderFrameRangeElem *frn_elem; frn_elem = p_new_framerange_element(GAP_FRN_SILENCE , shadow_track , NULL /* basename */ , NULL /* extension */ , 1 /* frame_from */ , fill_shadow_frames /* frame_to */ , storyboard_file , NULL /* preferred_decoder */ , NULL /* filtermacro_file */ , vidhand->frn_list , vidhand->sterr , 1 /* seltrack */ , 0 /* exact_seek*/ , 0.0 /* delace */ , 1.0 /* step_density */ , GAP_STB_FLIP_NONE /* flip_request */ , NULL /* mask_name */ , 1.0 /* mask_stepsize */ , GAP_MSK_ANCHOR_CLIP /* mask_anchor */ , TRUE /* mask_disable */ , 1 /* fmac_total_steps */ ); if(frn_elem) { vtarr->attr[frn_elem->track].frame_count += frn_elem->frames_to_handle; p_set_vtrack_attributes(frn_elem, vtarr); /* do NOT step vtrack attributes * because ths fill operation with empty frames in the shadow track * creates frames before the current position and needs no current vtrack attributes * and MUST NOT change the current vattr settings. */ p_add_frn_list(vidhand, frn_elem); } } /* end p_vidclip_shadow_add_silence */ /* --------------------------------- * p_recalculate_range_part * --------------------------------- * calculate a new from_frames and to_frames values * to reduce the clip length to the specified rest_frames. * lost_frames is an offest from the start. * * * ######################################################### * | | | | * |<-- lost_frames -->|<----- rest_frames --->| | * | | | * | | * |<--- frames_to_handle (before recalculate) ----------->| */ static void p_recalculate_range_part(GapStoryRenderFrameRangeElem *frn_elem , gint32 lost_frames , gint32 rest_frames) { gdouble l_offs_lost; gdouble l_offs_rest; gdouble l_orig_from; gdouble l_orig_to; gint32 l_orig_frames_to_handle; l_orig_from = frn_elem->frame_from; l_orig_to = frn_elem->frame_to; p_calculate_frames_to_handle(frn_elem); l_orig_frames_to_handle = frn_elem->frames_to_handle; if ((lost_frames + rest_frames) > l_orig_frames_to_handle) { printf("p_recalculate_range_part: ** ERROR cant split %d frames into parts of %d + %d\n" , (int)frn_elem->frames_to_handle , (int)lost_frames , (int)rest_frames ); if(lost_frames > frn_elem->frames_to_handle) { return; } rest_frames = frn_elem->frames_to_handle - lost_frames; } l_offs_lost = (gdouble)lost_frames * frn_elem->step_density; l_offs_rest = (gdouble)(MAX(0,rest_frames -1)) * frn_elem->step_density; if(frn_elem->frame_to >= frn_elem->frame_from) { frn_elem->frame_from += l_offs_lost; frn_elem->frame_to = frn_elem->frame_from + l_offs_rest; } else { frn_elem->frame_from -= l_offs_lost; frn_elem->frame_to = frn_elem->frame_from - l_offs_rest; frn_elem->frame_from += 0.5; frn_elem->frame_to += 0.5; } p_calculate_frames_to_handle(frn_elem); if(gap_debug) { printf("\nRANGE PART (in): orig from:%.3f to:%.3f to_handle:%d lost_frames:%d rest_frames:%d\n" , (float)l_orig_from , (float)l_orig_to , (int)l_orig_frames_to_handle , (int)lost_frames , (int)rest_frames ); printf("RANGE PART (out): from:%f to:%f offs_lost:%f offs_rest:%f frames_to_handle: %d\n\n" , (float)frn_elem->frame_from , (float)frn_elem->frame_to , (float)l_offs_lost , (float)l_offs_rest , (int)frn_elem->frames_to_handle ); } if(frn_elem->frames_to_handle != rest_frames) { if(gap_debug) { /* result may differ due to rounding * in case step_density != 1.0 is used */ printf("\n\nRANGE PART (dif) frames_to_handle != rest_frames due to rounding differences\n"); printf(" ==> FORCE frames_to_handle: from caluclated value: %d forced value: %d\n\n" ,(int)frn_elem->frames_to_handle ,(int)rest_frames ); } frn_elem->frames_to_handle = rest_frames; } } /* end p_recalculate_range_part */ /* --------------------------------- * p_copy_vattr_values * --------------------------------- * copy video attribute values from specified src track * to specified dest track. * NOTE: * the current frame_count and overlap_count are NOT copied! * (typical use of this procedure is to transfer the settings * from a normal track to a shadow track, where the counters * must not be affected by the copy) */ static void p_copy_vattr_values(gint32 src_track , gint32 dst_track , GapStoryRenderVTrackArray *vtarr ) { vtarr->attr[dst_track].keep_proportions = vtarr->attr[src_track].keep_proportions; vtarr->attr[dst_track].fit_width = vtarr->attr[src_track].fit_width; vtarr->attr[dst_track].fit_height = vtarr->attr[src_track].fit_height; vtarr->attr[dst_track].opacity_from = vtarr->attr[src_track].opacity_from; vtarr->attr[dst_track].opacity_to = vtarr->attr[src_track].opacity_to; vtarr->attr[dst_track].opacity_dur = vtarr->attr[src_track].opacity_dur; vtarr->attr[dst_track].scale_x_from = vtarr->attr[src_track].scale_x_from; vtarr->attr[dst_track].scale_x_to = vtarr->attr[src_track].scale_x_to; vtarr->attr[dst_track].scale_x_dur = vtarr->attr[src_track].scale_x_dur; vtarr->attr[dst_track].scale_y_from = vtarr->attr[src_track].scale_y_from; vtarr->attr[dst_track].scale_y_to = vtarr->attr[src_track].scale_y_to; vtarr->attr[dst_track].scale_y_dur = vtarr->attr[src_track].scale_y_dur; vtarr->attr[dst_track].move_x_from = vtarr->attr[src_track].move_x_from; vtarr->attr[dst_track].move_x_to = vtarr->attr[src_track].move_x_to; vtarr->attr[dst_track].move_x_dur = vtarr->attr[src_track].move_x_dur; vtarr->attr[dst_track].move_y_from = vtarr->attr[src_track].move_y_from; vtarr->attr[dst_track].move_y_to = vtarr->attr[src_track].move_y_to; vtarr->attr[dst_track].move_y_dur = vtarr->attr[src_track].move_y_dur; } /* end p_copy_vattr_values */ /* --------------------------------- * p_vidclip_split_and_add_frn_list * --------------------------------- * split the current clip into parts used for overlap in the shadow track * and remaining part in the normal track. * if the required amount of overlaping frames is not available in this * currently handled clip, the splitting will continue in the following * clips later on. In this case there will be no remaning part. * In some rare cases the current clip is completely thrown away * because the needed amount for overlapping will be fetched from * one of the following handled clips. */ static void p_vidclip_split_and_add_frn_list(GapStoryRenderFrameRangeElem *frn_elem ,GapStoryRenderVidHandle *vidhand ,GapStoryRenderVTrackArray *vtarr ,const char *storyboard_file) { gint32 l_track; gint32 l_shadow_track; gint32 l_shadow_frames_free; gint32 l_cut_frames; /* frames cut off from start of this video clip */ gint32 l_overlap_frames; /* overlapping frames handled by this video clip */ gint32 l_fill_shadow_frames; /* requred empty frames to fill up shadow track */ gint32 l_lost_frames; /* frames in this clip thrown away because no space in shadow track */ gint32 l_remain_frames; /* frames reamaining to be placed in normal track */ gint32 l_dead_frames; /* frames in this clip and further clips thrown away because no space in shadow track */ gint32 l_need_frames; /* required number of frames to overlap */ l_track = frn_elem->track; l_shadow_track = l_track - 1; l_shadow_frames_free = MAX(0, (vtarr->attr[l_track].frame_count - vtarr->attr[l_shadow_track].frame_count)); l_cut_frames = MIN(vtarr->attr[l_track].overlap_count, frn_elem->frames_to_handle); l_fill_shadow_frames = MAX(0, ((vtarr->attr[l_track].frame_count - vtarr->attr[l_track].overlap_count) - vtarr->attr[l_shadow_track].frame_count) ); l_need_frames = MAX(0, (l_shadow_frames_free - l_fill_shadow_frames)); l_dead_frames = vtarr->attr[l_track].overlap_count - l_need_frames; l_overlap_frames = MAX(0, (l_cut_frames - l_dead_frames)); l_lost_frames = l_cut_frames - l_overlap_frames; l_remain_frames = frn_elem->frames_to_handle - l_cut_frames; if(gap_debug) { printf("SPLIT: free_shadow:%d fill_shadow:%d need:%d dead:%d cut: %d, overlap:%d, lost:%d remain:%d\n" , (int)l_shadow_frames_free , (int)l_fill_shadow_frames , (int)l_need_frames , (int)l_dead_frames , (int)l_cut_frames , (int)l_overlap_frames , (int)l_lost_frames , (int)l_remain_frames ); } if(l_fill_shadow_frames > 0) { p_vidclip_shadow_add_silence(l_shadow_track , l_fill_shadow_frames , vidhand , vtarr , storyboard_file ); /* reset mask_framecount in shadow track to 0 */ vtarr->attr[l_shadow_track].mask_framecount = 0; } if(l_overlap_frames > 0) { GapStoryRenderFrameRangeElem *frn_elem_dup; /* shadow track shall continue with current vatt settings * of the corresponding normal track */ p_copy_vattr_values(l_track /* source */ ,l_shadow_track /* destination */ ,vtarr ); /* create a copy for the shadow track */ frn_elem_dup = p_new_framerange_element(frn_elem->frn_type ,l_shadow_track ,frn_elem->basename ,frn_elem->ext ,frn_elem->frame_from ,frn_elem->frame_to ,storyboard_file ,vidhand->preferred_decoder ,frn_elem->filtermacro_file ,vidhand->frn_list ,vidhand->sterr ,frn_elem->seltrack ,frn_elem->exact_seek ,frn_elem->delace ,frn_elem->step_density ,frn_elem->flip_request ,frn_elem->mask_name ,frn_elem->mask_stepsize ,frn_elem->mask_anchor ,FALSE /* keep mask enabled if the element has one */ ,frn_elem->fmac_total_steps ); p_recalculate_range_part(frn_elem_dup ,l_lost_frames ,l_overlap_frames ); p_vidclip_add_as_is(frn_elem_dup, vidhand, vtarr); /* copy vattr settings back from shadow track to normal track * (after the overlapping frames were processed in the * shadow track), the normal track will continue with settings * changed by shadow track processing */ p_copy_vattr_values(l_shadow_track /* source */ ,l_track /* destination */ ,vtarr ); /* continue mask_framecount in normal track (that has started in the shadow track) */ vtarr->attr[l_track].mask_framecount = vtarr->attr[l_shadow_track].mask_framecount; /* decrement overlap_count by */ vtarr->attr[l_track].overlap_count -= l_cut_frames; } if(l_remain_frames > 0) { p_recalculate_range_part(frn_elem ,l_cut_frames ,l_remain_frames ); p_vidclip_add_as_is(frn_elem, vidhand, vtarr); } } /* end p_vidclip_split_and_add_frn_list */ /* --------------------------------- * p_vidclip_add * --------------------------------- * set vtrack attribtes and add the frn_elem to the * list of videoclips (frn_list) * Overlapping is handled by splitting th video clip * into appropriate parts, where the overlapping frames * are placed into the shadow track. */ static void p_vidclip_add(GapStoryRenderFrameRangeElem *frn_elem ,GapStoryRenderVidHandle *vidhand ,GapStoryRenderVTrackArray *vtarr ,const char *storyboard_file ,gboolean first_of_group ) { if(frn_elem == NULL) { return; } if(vtarr->attr[frn_elem->track].overlap_count > 0) { if(first_of_group) { /* reset mask frame progress to 0 in the shadow track */ vtarr->attr[frn_elem->track -1].mask_framecount = 0; /* shadow track */ } /* an overlap transition is pending * have to split off the overlapping frame part * to the shadow track, the rest will be added to * the normal track */ p_vidclip_split_and_add_frn_list(frn_elem, vidhand, vtarr, storyboard_file); } else { if(first_of_group) { /* reset mask frame progress to 0 before processing each parsed clip. * the mask_framecount handles clip internal start value for fetching layer mask frames * in case were the scanned clip is splitted internally * (due to repetitions, pingpong mode, or overlapping) * the splitted parts 2 up to N will have mask_framecount > 0 */ vtarr->attr[frn_elem->track].mask_framecount = 0; } /* normal scenario without shadow track overlapping * simply add the video clip 1:1 to the list */ p_vidclip_add_as_is(frn_elem, vidhand, vtarr); } } /* end p_vidclip_add */ /* ---------------------------------------------------- * p_clear_vattr_array * ---------------------------------------------------- */ static void p_clear_vattr_array(GapStoryRenderVTrackArray *vtarr) { gint l_idx; vtarr->max_tracknum = GAP_STB_MAX_VID_INTERNAL_TRACKS -1; /* clear video track attribute settings for all tracks */ for(l_idx=0; l_idx <= vtarr->max_tracknum; l_idx++) { vtarr->attr[l_idx].frame_count = 0; vtarr->attr[l_idx].overlap_count = 0; vtarr->attr[l_idx].mask_framecount = 0; vtarr->attr[l_idx].keep_proportions = FALSE; vtarr->attr[l_idx].fit_width = TRUE; vtarr->attr[l_idx].fit_height = TRUE; vtarr->attr[l_idx].opacity_from = 1.0; vtarr->attr[l_idx].opacity_to = 1.0; vtarr->attr[l_idx].opacity_dur = 0; vtarr->attr[l_idx].scale_x_from = 1.0; vtarr->attr[l_idx].scale_x_to = 1.0; vtarr->attr[l_idx].scale_x_dur = 0; vtarr->attr[l_idx].scale_y_from = 1.0; vtarr->attr[l_idx].scale_y_to = 1.0; vtarr->attr[l_idx].scale_y_dur = 0; vtarr->attr[l_idx].move_x_from = 0.0; vtarr->attr[l_idx].move_x_to = 0.0; vtarr->attr[l_idx].move_x_dur = 0; vtarr->attr[l_idx].move_y_from = 0.0; vtarr->attr[l_idx].move_y_to = 0.0; vtarr->attr[l_idx].move_y_dur = 0; } } /* end p_clear_vattr_array */ /* ------------------------------------- * p_fmt_string_has_framenumber_format * ------------------------------------- * return true if the specified format string contains "%06d" (or "%02d" up to "%09d") * false if the format has no such numeric part for the framenumber. * */ static gboolean p_fmt_string_has_framenumber_format(const char *fmt_string) { const char *ptr; gboolean l_found; l_found = FALSE; ptr = fmt_string; while(ptr) { if(ptr[0] == '\0') { break; } if (ptr[0] == '%') { if(ptr[1] != '\0') { if(ptr[2] != '\0') { if(ptr[3] != '\0') { if((ptr[1] == '0') && (ptr[3] == 'd')) { if((ptr[2] >= '2') && (ptr[2] <= '9')) { l_found = TRUE; break; } } } } } } ptr++; } return (l_found); } /* end p_fmt_string_has_framenumber_format */ /* ------------------------------------- * p_fmt_string_has_videobasename_format * ------------------------------------- * return true if the specified format string contains "%s" * false if the format has no such videobasename placeholder part. * */ static gboolean p_fmt_string_has_videobasename_format(const char *fmt_string) { const char *ptr; gboolean l_found; l_found = FALSE; ptr = fmt_string; while(ptr) { if(ptr[0] == '\0') { break; } if ((ptr[0] == '%') && (ptr[1] == 's')) { l_found = TRUE; break; } ptr++; } return (l_found); } /* end p_fmt_string_has_videobasename_format */ /* ---------------------------------------------------- * p_storyboard_analyze * ---------------------------------------------------- * this procedure checks the specified storyboard (GapStoryBoard *stb) in memory * and converts all elements to the * corresponding rangelist structures (audio or frames or attr tables) * OUT: mainsection_frame_count is set to the number of frames in the main section * (if the main section has more than one track, the longest track * is used to set the mainsection_frame_count). */ static void p_storyboard_analyze(GapStoryBoard *stb , gint32 *mainsection_frame_count , GapStoryRenderVidHandle *vidhand ) { GapStoryRenderVTrackArray vtarray; GapStoryRenderVTrackArray *vtarr; GapStorySection *stb_section; GapStoryElem *stb_elem; char *storyboard_file; GapStoryRenderAudioRangeElem *aud_elem; GapStoryRenderFrameRangeElem *frn_elem; GapStoryRenderFrameRangeElem *frn_list; GapStoryRenderFrameRangeElem *frn_pinglist; GapStoryRenderErrors *sterr; GapStoryRenderFrameRangeElem *frn_known_list; gint32 l_track; gint l_idx; gint32 l_max_elems; gint32 l_cnt_elems; gint32 highest_vtrack; sterr=vidhand->sterr; frn_list = NULL; vtarr = &vtarray; storyboard_file = stb->storyboardfile; /* copy Master informations: */ if(stb->master_width > 0) { vidhand->master_width = stb->master_width; vidhand->master_height = stb->master_height; } if(stb->master_framerate > 0) { vidhand->master_framerate = stb->master_framerate; } vidhand->preferred_decoder = NULL; if(stb->preferred_decoder) { vidhand->preferred_decoder = g_strdup(stb->preferred_decoder); } vidhand->master_insert_area_format = NULL; if(stb->master_insert_area_format) { vidhand->master_insert_area_format = g_strdup(stb->master_insert_area_format); vidhand->master_insert_area_format_has_framenumber = p_fmt_string_has_framenumber_format(vidhand->master_insert_area_format); vidhand->master_insert_area_format_has_videobasename = p_fmt_string_has_videobasename_format(vidhand->master_insert_area_format); } if(stb->master_volume >= 0) { vidhand->master_volume = stb->master_volume; } if(stb->master_samplerate > 0) { vidhand->master_samplerate = stb->master_samplerate; } vidhand->section_list = NULL; for(stb_section = stb->stb_section; stb_section != NULL; stb_section = stb_section->next) { if (stb_section == stb->mask_section) { /* ignore mask definitions (e.g. all elements in mask_section) here, * because mask definitions are handled separately. * (for the rendering mask_definitions are not handled like sub sections, * mask_definitions have global scope in the whole storyboard * see procedure p_copy_mask_definitions_to_vidhand) */ continue; } vidhand->parsing_section = p_new_render_section(stb_section->section_name); p_append_render_section_to_vidhand(vidhand, vidhand->parsing_section); /* clear video track attribute settings for all tracks. * video attribute array holds current transition values (opacity, move and scale) * of all tracks and is updated at parsing of the the current clip. * each processed clip gets its start values from the array, and modifies the values * according to the amount of framesteps of a transition that can be handled * by processing the clip. * processing of a transition attribute element explicite sets the specified * number of framesteps, and from_ and to values for the next transition. * * The video attribute array must be cleared at start of each section. */ p_clear_vattr_array(vtarr); /* count Elements in the current STB section and check highest video track number */ highest_vtrack = 0; l_max_elems = 0; for(stb_elem = stb_section->stb_elem; stb_elem != NULL; stb_elem = stb_elem->next) { l_max_elems++; if(stb_elem->track > highest_vtrack) { highest_vtrack = stb_elem->track; } } /* Loop foreach Element in the current STB section */ l_cnt_elems = 0; for(stb_elem = stb_section->stb_elem; stb_elem != NULL; stb_elem = stb_elem->next) { if(stb_elem->track == GAP_STB_MASK_TRACK_NUMBER) { /* ignore mask definitions, in the reserved GAP_STB_MASK_TRACK_NUMBER track * in this loop, * mask definitions are handled separately. * (GAP_STB_MASK_TRACK_NUMBER shall not occure in main and sub sections * in new versions of storyboard processing) */ continue; } /* convert video tracknumbers from file to internal representation * note that internal tracknumbers 0, 2, 4 ... are reserved for shadow tracks * that are generated only for internal usage if a videotrack uses overlapping * frames. * the lowest internal tracknumber always appears in foreground * (e.g. is placed on top of layerstack at rendering of the composite frame) */ if (stb->master_vtrack1_is_toplayer) { /* default order track 1 is the top layer * 1 ==> 1 * 2 ==> 3 * 3 ==> 5 */ l_track = 1 + (2 * MAX((stb_elem->track -1), 0)); } else { /* inverse order track 1 is the background layer * 1 ==> 5 * 2 ==> 3 * 3 ==> 1 */ l_track = 1 + (2 * MAX((highest_vtrack - stb_elem->track), 0)); } frn_known_list = vidhand->frn_list; if (stb_section->section_name != NULL) { if (stb_elem->record_type == GAP_STBREC_VID_SECTION) { /* section playback is only supported in the main section * in other section use black frames when they contain * GAP_STBREC_VID_SECTION (this case should not happen regulary) */ stb_elem->record_type = GAP_STBREC_VID_BLACKSECTION; } } /* reset mask frame progress to 1 before processing each parsed clip. * the mask_framecount handles clip internal start value for fetching layer mask frames * in case were the scanned clip is splitted internally * (due to repetitions, pingpong mode, or overlapping) * the splitted parts 2 up to N will have mask_framecount > 0 */ vtarr->attr[l_track].mask_framecount = 0; switch(stb_elem->record_type) { case GAP_STBREC_ATT_TRANSITION: { gint ii; vtarr->attr[l_track].overlap_count += MAX(stb_elem->att_overlap, 0); vtarr->attr[l_track].fit_width = stb_elem->att_fit_width; vtarr->attr[l_track].fit_height = stb_elem->att_fit_height; vtarr->attr[l_track].keep_proportions = stb_elem->att_keep_proportions; for(ii=0; ii < GAP_STB_ATT_TYPES_ARRAY_MAX; ii++) { if(stb_elem->att_arr_enable[ii]) { switch(ii) { case GAP_STB_ATT_TYPE_OPACITY: vtarr->attr[l_track].opacity_from = stb_elem->att_arr_value_from[ii]; vtarr->attr[l_track].opacity_to = stb_elem->att_arr_value_to[ii]; vtarr->attr[l_track].opacity_dur = stb_elem->att_arr_value_dur[ii]; break; case GAP_STB_ATT_TYPE_MOVE_X: vtarr->attr[l_track].move_x_from = stb_elem->att_arr_value_from[ii]; vtarr->attr[l_track].move_x_to = stb_elem->att_arr_value_to[ii]; vtarr->attr[l_track].move_x_dur = stb_elem->att_arr_value_dur[ii]; break; case GAP_STB_ATT_TYPE_MOVE_Y: vtarr->attr[l_track].move_y_from = stb_elem->att_arr_value_from[ii]; vtarr->attr[l_track].move_y_to = stb_elem->att_arr_value_to[ii]; vtarr->attr[l_track].move_y_dur = stb_elem->att_arr_value_dur[ii]; break; case GAP_STB_ATT_TYPE_ZOOM_X: vtarr->attr[l_track].scale_x_from = stb_elem->att_arr_value_from[ii]; vtarr->attr[l_track].scale_x_to = stb_elem->att_arr_value_to[ii]; vtarr->attr[l_track].scale_x_dur = stb_elem->att_arr_value_dur[ii]; break; case GAP_STB_ATT_TYPE_ZOOM_Y: vtarr->attr[l_track].scale_y_from = stb_elem->att_arr_value_from[ii]; vtarr->attr[l_track].scale_y_to = stb_elem->att_arr_value_to[ii]; vtarr->attr[l_track].scale_y_dur = stb_elem->att_arr_value_dur[ii]; break; } } } } break; case GAP_STBREC_VID_SILENCE: if(!vidhand->ignore_video) { /* add framerange element for the current storyboard_file line */ frn_elem = p_new_framerange_element(GAP_FRN_SILENCE , l_track , NULL /* basename */ , NULL /* extension */ , 1 /* frame_from */ , stb_elem->nloop /* frame_to */ , storyboard_file , NULL /* preferred_decoder */ , NULL /* filtermacro_file */ , frn_known_list , sterr , 1 /* seltrack */ , 0 /* exact_seek*/ , 0.0 /* delace */ , 1.0 /* step_density */ , GAP_STB_FLIP_NONE /* flip_request */ , NULL /* mask_name */ , 1.0 /* mask_stepsize */ , GAP_MSK_ANCHOR_CLIP /* mask_anchor */ , TRUE /* mask_disable */ , 1 /* fmac_total_steps */ ); if(frn_elem) { frn_elem->wait_untiltime_sec = stb_elem->vid_wait_untiltime_sec; frn_elem->wait_untilframes = stb_elem->vid_wait_untiltime_sec * vidhand->master_framerate; p_vidclip_add(frn_elem, vidhand, vtarr, storyboard_file, TRUE); } } break; case GAP_STBREC_VID_BLACKSECTION: if(!vidhand->ignore_video) { /* add framerange element for the current storyboard_file line */ frn_elem = p_new_framerange_element(GAP_FRN_SILENCE , l_track , NULL /* basename */ , NULL /* extension */ , 1 /* frame_from */ , 1 + abs(stb_elem->to_frame - stb_elem->from_frame) , storyboard_file , NULL /* preferred_decoder */ , NULL /* filtermacro_file */ , frn_known_list , sterr , 1 /* seltrack */ , 0 /* exact_seek*/ , 0.0 /* delace */ , 1.0 /* step_density */ , GAP_STB_FLIP_NONE /* flip_request */ , NULL /* mask_name */ , 1.0 /* mask_stepsize */ , GAP_MSK_ANCHOR_CLIP /* mask_anchor */ , TRUE /* mask_disable */ , 1 /* fmac_total_steps */ ); if(frn_elem) { p_vidclip_add(frn_elem, vidhand, vtarr, storyboard_file, TRUE); } } break; case GAP_STBREC_VID_COLOR: if(!vidhand->ignore_video) { /* add framerange element for the current storyboard_file line */ frn_elem = p_new_framerange_element(GAP_FRN_COLOR , l_track , NULL , NULL /* extension */ , 1 /* frame_from */ , stb_elem->nloop /* frame_to */ , storyboard_file , NULL /* referred_decoder */ , NULL /* filtermacro_file */ , frn_known_list , sterr , 1 /* seltrack */ , 0 /* exact_seek*/ , 0.0 /* delace */ , 1.0 /* step_density */ , stb_elem->flip_request , stb_elem->mask_name , stb_elem->mask_stepsize , stb_elem->mask_anchor , stb_elem->mask_disable , stb_elem->fmac_total_steps ); if(frn_elem) { frn_elem->red_f = CLAMP(stb_elem->color_red, 0.0, 1.0); frn_elem->green_f = CLAMP(stb_elem->color_green, 0.0, 1.0); frn_elem->blue_f = CLAMP(stb_elem->color_blue, 0.0, 1.0); frn_elem->alpha_f = CLAMP(stb_elem->color_alpha, 0.0, 1.0); p_vidclip_add(frn_elem, vidhand, vtarr, storyboard_file, TRUE); } } break; case GAP_STBREC_VID_IMAGE: if(!vidhand->ignore_video) { /* add framerange element for the current storyboard_file line */ frn_elem = p_new_framerange_element(GAP_FRN_IMAGE , l_track , stb_elem->orig_filename , NULL /* extension */ , 1 /* frame_from */ , stb_elem->nloop /* frame_to */ , storyboard_file , vidhand->preferred_decoder , stb_elem->filtermacro_file , frn_known_list , sterr , 1 /* seltrack */ , 0 /* exact_seek*/ , 0.0 /* delace */ , 1.0 /* step_density */ , stb_elem->flip_request , stb_elem->mask_name , stb_elem->mask_stepsize , stb_elem->mask_anchor , stb_elem->mask_disable , stb_elem->fmac_total_steps ); if(frn_elem) { p_vidclip_add(frn_elem, vidhand, vtarr, storyboard_file, TRUE); } } break; case GAP_STBREC_VID_ANIMIMAGE: case GAP_STBREC_VID_FRAMES: case GAP_STBREC_VID_MOVIE: case GAP_STBREC_VID_SECTION: if(!vidhand->ignore_video) { GapStoryRenderFrameType l_frn_type; gint32 l_repcnt; gint32 l_sub_from; gint32 l_sub_to; gint l_pingpong; char *l_file_or_basename; char *l_ext_ptr; gboolean first_of_group; l_ext_ptr = NULL; l_file_or_basename = stb_elem->orig_filename; l_pingpong = 1; if(stb_elem->playmode == GAP_STB_PM_PINGPONG) { l_pingpong = 2; } l_frn_type = GAP_FRN_ANIMIMAGE; switch(stb_elem->record_type) { case GAP_STBREC_VID_ANIMIMAGE: l_frn_type = GAP_FRN_ANIMIMAGE; l_file_or_basename = stb_elem->orig_filename; break; case GAP_STBREC_VID_FRAMES: l_frn_type = GAP_FRN_FRAMES; l_ext_ptr = stb_elem->ext; l_file_or_basename = stb_elem->basename; break; case GAP_STBREC_VID_MOVIE: l_frn_type = GAP_FRN_MOVIE; l_file_or_basename = stb_elem->orig_filename; break; case GAP_STBREC_VID_SECTION: l_frn_type = GAP_FRN_SECTION; l_file_or_basename = stb_elem->orig_filename; break; default: break; /* should never be reached */ } frn_pinglist = frn_known_list; first_of_group = TRUE; /* expand element according to pingpong and nloop settings */ for(l_repcnt=0; l_repcnt < stb_elem->nloop; l_repcnt++) { l_sub_from = stb_elem->from_frame; l_sub_to = stb_elem->to_frame; for(l_idx=0; l_idx < l_pingpong; l_idx++) { /* add framerange element for the current storyboard_file line */ frn_elem = p_new_framerange_element( l_frn_type , l_track , l_file_or_basename , l_ext_ptr , l_sub_from , l_sub_to , storyboard_file , gap_story_get_preferred_decoder(stb, stb_elem) , stb_elem->filtermacro_file , frn_pinglist , sterr , stb_elem->seltrack , stb_elem->exact_seek , stb_elem->delace , stb_elem->step_density , stb_elem->flip_request , stb_elem->mask_name , stb_elem->mask_stepsize , stb_elem->mask_anchor , stb_elem->mask_disable , stb_elem->fmac_total_steps ); if(frn_elem) { /* prepare for pingpong mode with inverted range, * omitting the start/end frames */ l_sub_from = frn_elem->frame_to - frn_elem->delta; l_sub_to = frn_elem->frame_from + frn_elem->delta; p_vidclip_add(frn_elem, vidhand, vtarr, storyboard_file, first_of_group); first_of_group = FALSE; frn_pinglist = frn_list; } } } } break; case GAP_STBREC_AUD_SILENCE: if(!vidhand->ignore_audio) { /* add audiorange element for the current storyboard_file line */ aud_elem = gap_story_render_audio_new_audiorange_element(GAP_AUT_SILENCE , l_track , NULL , vidhand->master_samplerate , 0 /* from_sec */ , stb_elem->aud_play_to_sec /* to_sec */ , 0.0 /* vol_start */ , 0.0 /* volume */ , 0.0 /* vol_end */ , 0.0 /* fade_in_sec */ , 0.0 /* fade_out_sec */ , vidhand->util_sox , vidhand->util_sox_options , storyboard_file , vidhand->preferred_decoder , vidhand->aud_list /* known audio range elements */ , sterr , 1 /* seltrack */ , vidhand->create_audio_tmp_files , 0.0 /* min_play_sec */ , 0.0 /* max_play_sec */ , vidhand ); if(aud_elem) { aud_elem->wait_untiltime_sec = stb_elem->aud_wait_untiltime_sec; aud_elem->wait_until_samples = stb_elem->aud_wait_untiltime_sec * aud_elem->samplerate; gap_story_render_audio_add_aud_list(vidhand, aud_elem); } } break; case GAP_STBREC_AUD_SOUND: case GAP_STBREC_AUD_MOVIE: if(!vidhand->ignore_audio) { GapStoryRenderAudioType l_aud_type; gint l_rix; if(stb_elem->record_type == GAP_STBREC_AUD_SOUND) { l_aud_type = GAP_AUT_AUDIOFILE; } else { l_aud_type = GAP_AUT_MOVIE; } for(l_rix=0; l_rix < stb_elem->nloop; l_rix++) { /* add audiorange element for the current storyboard_file line */ aud_elem = gap_story_render_audio_new_audiorange_element(l_aud_type /* GAP_AUT_MOVIE or GAP_AUT_AUDIOFILE */ , l_track , stb_elem->aud_filename , vidhand->master_samplerate , stb_elem->aud_play_from_sec , stb_elem->aud_play_to_sec , stb_elem->aud_volume_start , stb_elem->aud_volume , stb_elem->aud_volume_end , stb_elem->aud_fade_in_sec , stb_elem->aud_fade_out_sec , vidhand->util_sox , vidhand->util_sox_options , storyboard_file , gap_story_get_preferred_decoder(stb, stb_elem) , vidhand->aud_list /* known audio range elements */ , sterr , stb_elem->aud_seltrack , vidhand->create_audio_tmp_files , stb_elem->aud_min_play_sec , stb_elem->aud_max_play_sec , vidhand ); if(aud_elem) { gap_story_render_audio_add_aud_list(vidhand, aud_elem); } } } break; default: break; } /* progress handling */ l_cnt_elems++; *vidhand->progress = (gdouble)l_cnt_elems / (gdouble)l_max_elems; if(vidhand->status_msg) { g_snprintf(vidhand->status_msg, vidhand->status_msg_len , _("analyze line %d (out of %d)") , (int)l_cnt_elems , (int)l_max_elems ); } } /* END Loop foreach Element in the current STB section */ if (stb_section->section_name == NULL) { gint vii; /* section_name NULL is the MAIN section */ vidhand->frn_list = vidhand->parsing_section->frn_list; vidhand->aud_list = vidhand->parsing_section->aud_list; /* findout total frame_count of the main section * (is the max frame_count of all tracks * within the MAIN section) */ for(vii=0; vii <= vtarr->max_tracknum; vii++) { if (*mainsection_frame_count < vtarr->attr[vii].frame_count) { *mainsection_frame_count = vtarr->attr[vii].frame_count; } } } } /* END loop for all sections of the storyboard */ } /* end p_storyboard_analyze */ /* ---------------------------------------------------- * p_framerange_list_from_storyboard * ---------------------------------------------------- * this procedure builds up a framerange list * from the given storyboard structure in MEMORY * or by parsing the specified storyboard_file. * * return the framerange_list (scanned from storyboard or storyboard_file) */ static GapStoryRenderFrameRangeElem * p_framerange_list_from_storyboard(const char *storyboard_file ,gint32 *frame_count ,GapStoryRenderVidHandle *vidhand ,GapStoryBoard *stb_mem_ptr ) { GapStoryRenderErrors *sterr; sterr=vidhand->sterr; *frame_count = 0; if(gap_debug) { printf("p_framerange_list_from_storyboard: START vidhand:%d stb_mem_ptr;%d" , (int)vidhand , (int)stb_mem_ptr ); if (storyboard_file == NULL) { printf(" storyboard_file: (null)"); } else { printf(" storyboard_file:%s" , storyboard_file ); } printf("\n"); } /* convert from GapStoryBoard to render representation * of the storyboard. */ { GapStoryBoard *stb; stb = NULL; if(stb_mem_ptr) { /* we have a storyboard already available in MEMORY * make a full copy for further processing. */ stb = gap_story_duplicate_full(stb_mem_ptr); } if(stb == NULL) { /* load and parse the storyboard structure from file */ stb = gap_story_parse(storyboard_file); } if(stb) { if(stb->errtext != NULL) { /* report the 1.st error */ sterr->curr_nr = stb->errline_nr; sterr->currline = stb->errline; p_set_stb_error(sterr, stb->errtext); } else { /* findout min and max playtime for audio clip references * that are to extract from videofiles */ gap_story_set_aud_movie_min_max(stb); /* analyze the stb list and transform this list * to vidhand->section_list->frn_list and vidhand->section_list->aud_list */ p_storyboard_analyze(stb ,frame_count ,vidhand ); /* mask definitions */ p_copy_mask_definitions_to_vidhand(stb, vidhand); } gap_story_free_storyboard(&stb); } } /* select MAIN section (has section_name NULL) per default * (Note: this sets vidhand->frn_list to the frn_list of the MAIN section) */ p_select_section_by_name(vidhand, NULL); if((vidhand->frn_list == 0) || (*frame_count == 0)) { *frame_count = 0; sterr->currline = "(eof)"; p_set_stb_error(sterr, _("No Frames or Images found ....")); /* note: this can occure if there are non empty sub sections * but the MAIN section is empty. * (in such a case nothing will be rendered). */ } if(gap_debug) { printf("p_framerange_list_from_storyboard: END vidhand:%d\n" , (int)vidhand ); } return (vidhand->frn_list); } /* end p_framerange_list_from_storyboard */ /* ---------------------------------------------------- * p_free_framerange_list * ---------------------------------------------------- */ static void p_free_framerange_list(GapStoryRenderFrameRangeElem * frn_list) { GapStoryRenderFrameRangeElem *frn_elem; GapStoryRenderFrameRangeElem *frn_next; for(frn_elem = frn_list; frn_elem != NULL; frn_elem = frn_next) { if(frn_elem->basename) { g_free(frn_elem->basename);} if(frn_elem->ext) { g_free(frn_elem->ext);} if(frn_elem->filtermacro_file) { g_free(frn_elem->filtermacro_file);} #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if(frn_elem->gvahand) { GVA_close(frn_elem->gvahand);} #endif frn_next = (GapStoryRenderFrameRangeElem *)frn_elem->next; g_free(frn_elem); } } /* end p_free_framerange_list */ /* ---------------------------------------------------- * p_new_render_section * ---------------------------------------------------- */ static GapStoryRenderSection * p_new_render_section(const char *section_name) { GapStoryRenderSection *new_render_section; new_render_section = g_new(GapStoryRenderSection, 1); new_render_section->frn_list = NULL; new_render_section->aud_list = NULL; new_render_section->section_name = NULL; if (section_name != NULL) { new_render_section->section_name = g_strdup(section_name); } new_render_section->next = NULL; return (new_render_section); } /* end p_new_render_section */ /* ---------------------------------------------------- * p_append_render_section_to_vidhand * ---------------------------------------------------- * append the specified new_render_section at end of the section_list * of the specified video handle. */ static void p_append_render_section_to_vidhand(GapStoryRenderVidHandle *vidhand , GapStoryRenderSection *new_render_section) { GapStoryRenderSection *render_section; for(render_section = vidhand->section_list; render_section != NULL; render_section = render_section->next) { if(render_section->next == NULL) { break; } } if (render_section != NULL) { render_section->next = new_render_section; } else { vidhand->section_list = new_render_section; } } /* end p_append_render_section_to_vidhand */ /* ---------------------------------------------------- * p_open_mask_vidhand * ---------------------------------------------------- */ static void p_open_mask_vidhand(GapStoryElem *stb_elem, GapStoryRenderMaskDefElem *maskdef_elem) { GapLibTypeInputRange input_mode; input_mode = GAP_RNGTYPE_IMAGE; switch(stb_elem->record_type) { case GAP_STBREC_VID_IMAGE: input_mode = GAP_RNGTYPE_IMAGE; break; case GAP_STBREC_VID_ANIMIMAGE: input_mode = GAP_RNGTYPE_LAYER; break; case GAP_STBREC_VID_FRAMES: input_mode = GAP_RNGTYPE_FRAMES; break; case GAP_STBREC_VID_MOVIE: input_mode = GAP_RNGTYPE_MOVIE; break; default: break; } if(gap_debug) { printf("p_open_mask_vidhand: MASK_ELEM\n"); gap_story_debug_print_elem(stb_elem); } maskdef_elem->mask_vidhand = p_open_video_handle_private( TRUE /* ignore_audio */ , FALSE /* dont ignore_video */ , FALSE /* create_audio_tmp_files */ , NULL /* progress_ptr */ , NULL /* status_msg */ , 0 /* status_msg_len */ , NULL /* storyboard_file */ ,stb_elem->basename ,stb_elem->ext ,stb_elem->from_frame ,stb_elem->to_frame ,&maskdef_elem->frame_count ,FALSE /* do_gimp_progress */ ,input_mode ,stb_elem->orig_filename /* imagename */ ,stb_elem->preferred_decoder ,stb_elem->seltrack ,stb_elem->exact_seek ,stb_elem->delace ,FALSE /* compensate_framerange */ ,NULL /* stb_mem_ptr */ ); if(maskdef_elem->mask_vidhand) { maskdef_elem->mask_vidhand->is_mask_handle = TRUE; } } /* end p_open_mask_vidhand */ /* ---------------------------------------------------- * p_copy_mask_definitions * ---------------------------------------------------- * copy mask definitions and open a sub GapStoryRenderVidHandle * for each mask definition. * those handles are used to fetch masks from any type of clips. */ static void p_copy_mask_definitions_to_vidhand(GapStoryBoard *stb_ptr, GapStoryRenderVidHandle *vidhand) { GapStoryElem *stb_elem; vidhand->maskdef_elem = NULL; /* start with empty mask definition list */ if (stb_ptr->mask_section == NULL) { return; } for(stb_elem = stb_ptr->mask_section->stb_elem; stb_elem != NULL; stb_elem = stb_elem->next) { if(stb_elem->track != GAP_STB_MASK_TRACK_NUMBER) { /* mask definitions are restricted to internal track number 0, * ignore other tracks for maskdefinition (shall not occure) */ continue; } if ((stb_elem->record_type == GAP_STBREC_VID_SECTION) || (stb_elem->record_type == GAP_STBREC_VID_BLACKSECTION)) { /* section playback is NOT supported for mask definitions. * ignore such elements (that shall not occure in regular case) */ continue; } if(stb_elem->mask_name) { GapStoryRenderMaskDefElem *maskdef_elem; GapStoryElem *stb_elem_ref; /* check if there are references (in any section) to this mask definition */ stb_elem_ref = gap_story_find_mask_reference_by_name(stb_ptr, stb_elem->mask_name); if(stb_elem_ref == NULL) { /* this mask definition is not refered, * no processing is necessary */ continue; } if(gap_debug) { printf("p_copy_mask_definitions_to_vidhand: \n"); gap_story_debug_print_elem(stb_elem); } maskdef_elem = g_new(GapStoryRenderMaskDefElem, 1); if(maskdef_elem) { maskdef_elem->mask_name = g_strdup(stb_elem->mask_name); maskdef_elem->record_type = (gint32)stb_elem->record_type; maskdef_elem->frame_count = 0; maskdef_elem->flip_request = stb_elem->flip_request; maskdef_elem->mask_vidhand = NULL; maskdef_elem->next = vidhand->maskdef_elem; p_open_mask_vidhand(stb_elem, maskdef_elem); /* link mask definition element as 1st element to the list */ vidhand->maskdef_elem = maskdef_elem; } } } } /* end p_copy_mask_definitions */ /* ---------------------------------------------------- * p_free_mask_definitions * ---------------------------------------------------- * free all mask definitions and close sub GapStoryRenderVidHandle * for all mask definitions. */ static void p_free_mask_definitions(GapStoryRenderVidHandle *vidhand) { GapStoryRenderMaskDefElem *maskdef_elem; GapStoryRenderMaskDefElem *maskdef_next; for(maskdef_elem = vidhand->maskdef_elem; maskdef_elem != NULL; maskdef_elem = maskdef_next) { if(maskdef_elem->mask_vidhand) { gap_story_render_close_vid_handle(maskdef_elem->mask_vidhand); } if(maskdef_elem->mask_name) { g_free(maskdef_elem->mask_name); } maskdef_next = maskdef_elem->next; g_free(maskdef_elem); } } /* end p_free_mask_definitions */ /* ---------------------------------------------------- * gap_story_render_close_vid_handle * ---------------------------------------------------- * close video handle (free framelist and errors) */ void gap_story_render_close_vid_handle(GapStoryRenderVidHandle *vidhand) { GapStoryRenderSection *render_section; render_section = vidhand->section_list; while(render_section != NULL) { GapStoryRenderSection *next_render_section; next_render_section = render_section->next; p_free_framerange_list(render_section->frn_list); if (render_section->section_name != NULL) { g_free(render_section->section_name); } g_free(render_section); render_section = next_render_section; } 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; } /* end gap_story_render_close_vid_handle */ /* ---------------------------------------------------- * gap_story_render_set_audio_resampling_program * ---------------------------------------------------- */ void gap_story_render_set_audio_resampling_program(GapStoryRenderVidHandle *vidhand , char *util_sox , char *util_sox_options ) { if(vidhand) { if(vidhand->util_sox) { g_free(vidhand->util_sox); vidhand->util_sox = NULL; } if(vidhand->util_sox_options) { g_free(vidhand->util_sox_options); vidhand->util_sox_options = NULL; } if(util_sox) { vidhand->util_sox = g_strdup(util_sox); } if(util_sox_options) { vidhand->util_sox_options = g_strdup(util_sox_options); } } } /* end gap_story_render_set_audio_resampling_program */ /* ---------------------------------------------------- * p_find_maskdef_by_name * ---------------------------------------------------- */ static GapStoryRenderMaskDefElem * p_find_maskdef_by_name(GapStoryRenderVidHandle *vidhand, const char *mask_name) { GapStoryRenderMaskDefElem *maskdef_elem; for(maskdef_elem = vidhand->maskdef_elem; maskdef_elem != NULL; maskdef_elem = maskdef_elem->next) { if(strcmp(maskdef_elem->mask_name, mask_name) == 0) { return(maskdef_elem); } } return (NULL); } /* end p_find_maskdef_by_name */ /* ---------------------------------------------------- * p_mask_image_fetcher * ---------------------------------------------------- * fetch specified mask frame as gray image with only one composite layer. * if the mask definition is not found, * then deliver -1. * if the mask definition has less frames than master_frame_nr, then deliver the * last available frame as mask. * return the image id. */ static gint32 p_mask_fetcher(GapStoryRenderVidHandle *vidhand , const char *mask_name , gint32 master_frame_nr , gint32 mask_width , gint32 mask_height , gint32 *layer_id_ptr /* OUT: Id of the only layer in the composite image */ , gboolean *was_last_maskframe /* OUT: true if this was the last maskframe */ ) { GapStoryRenderMaskDefElem *maskdef_elem; gint32 image_id; *was_last_maskframe = FALSE; image_id = -1; maskdef_elem = p_find_maskdef_by_name(vidhand, mask_name); if(maskdef_elem == NULL) { printf("\n** Error MASK fetch could not find maskdef_elem (== NULL) MASK: %s IGNORED\n" , mask_name); } else { gint32 l_framenr; /* limit access to last available frame */ l_framenr = MIN(master_frame_nr, maskdef_elem->frame_count); if(gap_debug) { printf("\n############# MASK start FETCH ##########\n"); printf("MASK relevant framenr:%d\n" , (int)l_framenr ); gap_story_render_debug_print_maskdef_elem(maskdef_elem, -7); } /* the composite image fecther already converts to gray when called * with a mask videohandle (marked with is_mask_handle flag) */ image_id = p_story_render_fetch_composite_image_private(maskdef_elem->mask_vidhand , l_framenr /* starts at 1 */ , mask_width /* desired Width in pixels */ , mask_height /* desired Height in pixels */ , NULL /* NULL if no filtermacro is used */ , layer_id_ptr /* OUT: Id of the only layer in the composite image */ , NULL /* each mask has its own mask_vidhand where * the elements are in main section (section_name = NULL) */ ); if(gap_debug) { printf("\n.........#### MASK end FETCH ####......\n"); } *layer_id_ptr = gap_layer_flip(*layer_id_ptr, maskdef_elem->flip_request); if(gimp_drawable_has_alpha(*layer_id_ptr)) { *layer_id_ptr = gimp_image_flatten(image_id); } if(gap_debug) { printf("p_mask_fetcher: flip_request:%d\n" ,(int)maskdef_elem->flip_request ); } if (l_framenr == maskdef_elem->frame_count) { *was_last_maskframe = TRUE; } } return(image_id); } /* end p_mask_fetcher */ /* ---------------------------------------------------- * p_fetch_and_add_layermask * ---------------------------------------------------- */ static void p_fetch_and_add_layermask(GapStoryRenderVidHandle *vidhand , GapStoryRenderFrameRangeElem *frn_elem , gint32 local_stepcount , gint32 image_id , gint32 layer_id ) { gint32 l_tmp_mask_image_id; gint32 l_tmp_mask_layer_id; gint32 l_master_framenr; gdouble l_framenr; gboolean l_found_in_cache; gboolean l_was_last_maskframe; /* both local_stepcount and mask_framecount start with 0 for the 1st element */ l_framenr = frn_elem->mask_stepsize * (gdouble)(frn_elem->mask_framecount + local_stepcount); l_master_framenr = 1 + (gint32)(l_framenr); if(gap_debug) { printf("\n============--------------====\n"); printf("p_fetch_and_add_layermask: local_stepcount: %d master_framenr:%d\n" ,(int)local_stepcount ,(int)l_master_framenr ); gap_story_render_debug_print_frame_elem(frn_elem, -5); } l_found_in_cache = FALSE; // l_tmp_mask_image_id = TODO lookup in the cache ################ if(l_found_in_cache) { if(gap_debug) { printf("FOUND MASK in cache: mask_name:%s master_framenr:%d\n" ,frn_elem->mask_name ,(int)l_master_framenr ); } } else { l_tmp_mask_image_id = p_mask_fetcher(vidhand , frn_elem->mask_name , l_master_framenr , gimp_drawable_width(layer_id) , gimp_drawable_height(layer_id) ,&l_tmp_mask_layer_id ,&l_was_last_maskframe ); } if(gap_debug) { printf("MASK image_id: %d l_tmp_mask_layer_id:%d\n" ,(int)l_tmp_mask_image_id ,(int)l_tmp_mask_layer_id ); } if(l_tmp_mask_image_id >= 0) { gint32 l_new_layer_mask_id; if(1==0) { p_debug_dup_image(l_tmp_mask_image_id); } /* add aplha channel if necessary * (this is required to allow adding the layermask */ if(!gimp_drawable_has_alpha(layer_id)) { gimp_layer_add_alpha(layer_id); } l_new_layer_mask_id = gimp_layer_create_mask(layer_id, GIMP_ADD_WHITE_MASK); gimp_layer_add_mask(layer_id, l_new_layer_mask_id); /* overwrite the white layer mask with the fetched mask */ gap_layer_copy_content(l_new_layer_mask_id /* dst_drawable_id */ ,l_tmp_mask_layer_id /* src_drawable_id */ ); if(!l_found_in_cache) { // TODO: decide if l_tmp_mask_image_id should be stored in cache or to delete immediate. // store if: // - there are more than one references // - if mask stepsize < 1.0 // - the last frame of the mask sequence (l_framenr == maskdef_elem->frame_count) // (that has to be repeated for all remaining frame in the clip) // if((frn_elem->mask_stepsize < 1.0) // || (l_was_last_maskframe) // ) gap_image_delete_immediate(l_tmp_mask_image_id); } } } /* end p_fetch_and_add_layermask */ /* ---------------------------------------------------- * p_open_video_handle_private * ---------------------------------------------------- * this procedure builds a framerange list from * the given storyboard file. * if NULL is passed as storyboard_file * the list is built with just one entry. * from basename and ext parameters. * * return framerange list */ static GapStoryRenderVidHandle * p_open_video_handle_private( gboolean ignore_audio , gboolean ignore_video , gboolean create_audio_tmp_files , gdouble *progress_ptr , char *status_msg , gint32 status_msg_len , const char *storyboard_file , const char *basename , const char *ext , gint32 frame_from , gint32 frame_to , gint32 *frame_count /* output total frame_count , or 0 on failure */ , gboolean do_gimp_progress , GapLibTypeInputRange input_mode , const char *imagename , const char *preferred_decoder , gint32 seltrack , gint32 exact_seek , gdouble delace , gboolean compensate_framerange , GapStoryBoard *stb_mem_ptr ) { GapStoryRenderVidHandle *vidhand; GapStoryRenderSection *render_section; GapStoryRenderFrameRangeElem *frn_elem; vidhand = g_malloc0(sizeof(GapStoryRenderVidHandle)); render_section = NULL; if(gap_debug) { printf("p_open_video_handle_private: new vidhand:%d\n", (int)vidhand); } if(progress_ptr) { vidhand->progress = progress_ptr; } else { vidhand->progress = &vidhand->dummy_progress; } if(status_msg) { vidhand->status_msg = status_msg; vidhand->status_msg_len = status_msg_len; } else { vidhand->status_msg = NULL; 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->master_insert_area_format = NULL; vidhand->master_insert_area_format_has_videobasename = FALSE; vidhand->master_insert_area_format_has_framenumber = FALSE; vidhand->do_gimp_progress = do_gimp_progress; *vidhand->progress = 0.0; vidhand->sterr = p_new_stb_error(); vidhand->master_framerate = 25.0; vidhand->master_width = 0; vidhand->master_height = 0; vidhand->master_samplerate = 44100; /* 44.1 kHZ CD standard Quality */ vidhand->master_volume = 1.0; vidhand->util_sox = NULL; /* use DEFAULT resample program (sox), where needed */ vidhand->util_sox_options = NULL; /* use DEFAULT options */ vidhand->ignore_audio = ignore_audio; vidhand->ignore_video = ignore_video; vidhand->create_audio_tmp_files = create_audio_tmp_files; vidhand->maskdef_elem = NULL; vidhand->is_mask_handle = FALSE; vidhand->parsing_section = NULL; vidhand->section_list = NULL; global_monitor_image_id = -1; *frame_count = 0; if((storyboard_file) && (input_mode == GAP_RNGTYPE_STORYBOARD)) { if(*storyboard_file != '\0') { vidhand->frn_list = p_framerange_list_from_storyboard(storyboard_file , frame_count , vidhand , stb_mem_ptr); } render_section = vidhand->section_list; } if (vidhand->section_list == NULL) { /* make sure that the video handle always has a main section * with section Name NULL. * (this can occure if not directly created from a storyboard * or when creating sub video handle for mask processing) */ vidhand->section_list = p_new_render_section(NULL); vidhand->parsing_section = vidhand->section_list; render_section = vidhand->section_list; if(gap_debug) { printf("p_open_video_handle_private: added default MAIN render_section\n"); } } if(gap_debug) { printf("p_open_video_handle_private: OPENING vidhand:%d\n" , (int)vidhand ); p_debug_print_render_section_names(vidhand); } if((render_section->frn_list == NULL) && (input_mode == GAP_RNGTYPE_LAYER) && (imagename)) { gint32 l_from; gint32 l_to; l_from = frame_from; l_to = frame_to; if(compensate_framerange) { /* layerindex starts with 0, but master_index should start with 1 * increment by 1 to compensate. (only needed for single multilayer image encoding) */ l_from = 1; l_to = 1+ MAX(frame_to, frame_from); } /* add element for animimage (one multilayer image) */ frn_elem = p_new_framerange_element(GAP_FRN_ANIMIMAGE , 1 /* track */ , imagename , NULL , l_from , l_to , NULL /* storyboard_file */ , NULL /* preferred_decoder */ , NULL /* filtermacro_file */ , NULL /* frn_list */ , vidhand->sterr , 1 /* seltrack */ , 0 /* exact_seek*/ , 0.0 /* delace */ , 1.0 /* step_density */ , GAP_STB_FLIP_NONE /* flip_request */ , NULL /* mask_name */ , 1.0 /* mask_stepsize */ , GAP_MSK_ANCHOR_CLIP /* mask_anchor */ , TRUE /* mask_disable */ , 1 /* fmac_total_steps */ ); if(frn_elem) { *frame_count = frn_elem->frames_to_handle; } if(compensate_framerange) { /* add a layer 0 (as separate 1.st listelement) * to compensate framenumbers if the range does not start with 1 */ render_section->frn_list = p_new_framerange_element(GAP_FRN_ANIMIMAGE , 1 /* track */ , imagename , NULL , 1 /* from */ , 1 /* to */ , NULL /* storyboard_file */ , NULL /* preferred_decoder */ , NULL /* filtermacro_file */ , NULL /* frn_list */ , vidhand->sterr , 1 /* seltrack */ , 0 /* exact_seek*/ , 0.0 /* delace */ , 1.0 /* step_density */ , GAP_STB_FLIP_NONE /* flip_request */ , NULL /* mask_name */ , 1.0 /* mask_stepsize */ , GAP_MSK_ANCHOR_CLIP /* mask_anchor */ , TRUE /* mask_disable */ , 1 /* fmac_total_steps */ ); render_section->frn_list->frames_to_handle = l_from -1; render_section->frn_list->next = frn_elem; if(gap_debug) { printf("***************************\n"); printf("COMPENSATE LAYERS (ANIMIMAGE):\n"); gap_story_render_debug_print_framerange_list(render_section->frn_list , -1); printf("***************************\n"); } } else { render_section->frn_list = frn_elem; } } if((render_section->frn_list == NULL) && (basename) && (ext)) { gint32 l_from; gint32 l_to; l_from = frame_from; l_to = frame_to; if(compensate_framerange) { /* layerindex starts with 0, but master_index should start with 1 * increment by 1 to compensate. (only needed for single multilayer image encoding) */ l_from = MIN(frame_from, frame_to); l_to = MAX(frame_to, frame_from); } if(input_mode == GAP_RNGTYPE_FRAMES) { /* element for framerange */ frn_elem = p_new_framerange_element(GAP_FRN_FRAMES , 1 /* track */ , basename , ext , l_from , l_to , NULL /* storyboard_file */ , NULL /* preferred_decoder */ , NULL /* filtermacro_file */ , NULL /* frn_list */ , vidhand->sterr , 1 /* seltrack */ , 0 /* exact_seek*/ , 0.0 /* delace */ , 1.0 /* step_density */ , GAP_STB_FLIP_NONE /* flip_request */ , NULL /* mask_name */ , 1.0 /* mask_stepsize */ , GAP_MSK_ANCHOR_CLIP /* mask_anchor */ , TRUE /* mask_disable */ , 1 /* fmac_total_steps */ ); if(frn_elem) *frame_count = frn_elem->frames_to_handle; if(compensate_framerange) { /* add a SILENCE dummy (as 1.st listelement) * to compensate framenumbers if the range does not start with 1 */ render_section->frn_list = p_new_framerange_element(GAP_FRN_SILENCE , 1 /* track */ , NULL , NULL , 0 /* frame_from */ , l_from -1 /* frame_to */ , NULL /* storyboard_file */ , NULL /* preferred_decoder */ , NULL /* filtermacro_file */ , NULL /* frn_list */ , vidhand->sterr , 1 /* seltrack */ , 0 /* exact_seek*/ , 0.0 /* delace */ , 1.0 /* step_density */ , GAP_STB_FLIP_NONE /* flip_request */ , NULL /* mask_name */ , 1.0 /* mask_stepsize */ , GAP_MSK_ANCHOR_CLIP /* mask_anchor */ , TRUE /* mask_disable */ , 1 /* fmac_total_steps */ ); render_section->frn_list->frames_to_handle = l_from -1; render_section->frn_list->next = frn_elem; if(gap_debug) { printf("***************************\n"); printf("COMPENSATE FRAMES:\n"); gap_story_render_debug_print_framerange_list(render_section->frn_list , -1); printf("***************************\n"); } } else { render_section->frn_list = frn_elem; } } } if((render_section->frn_list == NULL) && (input_mode == GAP_RNGTYPE_IMAGE) && (imagename)) { /* add element for single image * (typical used only for mask definitions) */ frn_elem = p_new_framerange_element(GAP_FRN_IMAGE , 1 /* track */ , imagename , NULL , 1 /* frame_from */ , 1 /* frame_to */ , NULL /* storyboard_file */ , NULL /* preferred_decoder */ , NULL /* filtermacro_file */ , NULL /* frn_list */ , vidhand->sterr , 1 /* seltrack */ , 0 /* exact_seek*/ , 0.0 /* delace */ , 1.0 /* step_density */ , GAP_STB_FLIP_NONE /* flip_request */ , NULL /* mask_name */ , 1.0 /* mask_stepsize */ , GAP_MSK_ANCHOR_CLIP /* mask_anchor */ , TRUE /* mask_disable */ , 1 /* fmac_total_steps */ ); if(frn_elem) { *frame_count = frn_elem->frames_to_handle; } render_section->frn_list = frn_elem; } if((render_section->frn_list == NULL) && (input_mode == GAP_RNGTYPE_MOVIE) && (imagename)) { /* add element for single movie input * (typical used only for mask definitions) */ frn_elem = p_new_framerange_element(GAP_FRN_MOVIE , 1 /* track */ , imagename , NULL , frame_from , frame_to , NULL /* storyboard_file */ , preferred_decoder , NULL /* filtermacro_file */ , NULL /* frn_list */ , vidhand->sterr , seltrack , exact_seek , delace , 1.0 /* step_density */ , GAP_STB_FLIP_NONE /* flip_request */ , NULL /* mask_name */ , 1.0 /* mask_stepsize */ , GAP_MSK_ANCHOR_CLIP /* mask_anchor */ , TRUE /* mask_disable */ , 1 /* fmac_total_steps */ ); if(frn_elem) { *frame_count = frn_elem->frames_to_handle; } render_section->frn_list = frn_elem; } /* select MAIN section (has section_name NULL) per default */ p_select_section_by_name(vidhand, NULL); /* p_free_stb_error(vidhand->sterr); */ if(gap_debug) { printf("\n\np_open_video_handle_private: END vidhand:%d\n\n", (int)vidhand); gap_story_render_debug_print_framerange_list(vidhand->frn_list, -1); } return(vidhand); } /* end p_open_video_handle_private */ /* ---------------------------------------------------- * gap_story_render_open_extended_video_handle * ---------------------------------------------------- * this procedure builds a framerange list from * the given storyboard file. * if NULL is passed as storyboard_file * the list is built with just one entry. * from basename and ext parameters. * * return framerange list */ GapStoryRenderVidHandle * gap_story_render_open_extended_video_handle( gboolean ignore_audio , gboolean ignore_video , gboolean create_audio_tmp_files , gdouble *progress_ptr , char *status_msg , gint32 status_msg_len , GapLibTypeInputRange input_mode , const char *imagename , const char *storyboard_file , const char *basename , const char *ext , gint32 frame_from , gint32 frame_to , gint32 *frame_count /* output total frame_count , or 0 on failure */ ) { return(p_open_video_handle_private( ignore_audio /* ignore_audio */ , ignore_video /* dont ignore_video */ , create_audio_tmp_files , progress_ptr /* progress_ptr */ , status_msg /* status_msg */ , status_msg_len /* status_msg_len */ ,storyboard_file ,basename ,ext ,frame_from ,frame_to ,frame_count ,FALSE /* DONT do_gimp_progress */ ,input_mode ,imagename ,NULL /* preferred_decoder */ ,1 /* seltrack */ ,0 /* exact_seek */ ,0.0 /* delace */ ,TRUE /* compensate_framerange */ ,NULL /* stb_mem_ptr */ ) ); } /* end gap_story_render_open_extended_video_handle */ /* ---------------------------------------------------- * gap_story_render_open_vid_handle_from_stb * ---------------------------------------------------- * this procedure builds a framerange list from * the given storyboard in MEMORY. * * this wrapper to p_open_video_handle * ignores AUDIO informations in the storyboard file * (Typically the Player uses this variant * for playback of composite storyboard video) * * return the video handle */ GapStoryRenderVidHandle * gap_story_render_open_vid_handle_from_stb(GapStoryBoard *stb_mem_ptr ,gint32 *frame_count /* output total frame_count , or 0 on failure */ ) { GapStoryRenderVidHandle *l_vidhand; l_vidhand = NULL; if(stb_mem_ptr) { l_vidhand = p_open_video_handle_private( TRUE /* ignore_audio */ , FALSE /* dont ignore_video */ , FALSE /* create_audio_tmp_files */ , NULL /* progress_ptr */ , NULL /* status_msg */ , 0 /* status_msg_len */ ,stb_mem_ptr->storyboardfile , NULL /* basename */ , NULL /* ext */ ,1 /* frame_from (not relevant) */ ,1 /* frame_to (not relevant) */ ,frame_count ,FALSE /* do_gimp_progress */ ,GAP_RNGTYPE_STORYBOARD /* input_mode */ ,NULL /* imagename */ ,NULL /* preferred_decoder */ ,1 /* seltrack */ ,0 /* exact_seek */ ,0.0 /* delace */ ,TRUE /* compensate_framerange */ ,stb_mem_ptr /* stb_mem_ptr */ ); } return(l_vidhand); } /* end gap_story_render_open_vid_handle_from_stb */ /* ---------------------------------------------------- * gap_story_render_open_vid_handle * ---------------------------------------------------- * this procedure builds a framerange list from * the given storyboard file. * if NULL is passed as storyboard_file * the list is built with just one entry * from basename and ext parameters. * * this wrapper to p_open_video_handle * ignores AUDIO informations in the storyboard file * (The encoders use this variant * because the common GUI usually creates * the composite audio track, and passes * the resulting WAV file ready to use) * * return the video handle */ GapStoryRenderVidHandle * gap_story_render_open_vid_handle(GapLibTypeInputRange input_mode , gint32 image_id , const char *storyboard_file , const char *basename , const char *ext , gint32 frame_from , gint32 frame_to , gint32 *frame_count /* output total frame_count , or 0 on failure */ ) { GapStoryRenderVidHandle *l_vidhand; char *imagename; imagename = NULL; if(image_id >= 0) { imagename = gimp_image_get_filename(image_id); } l_vidhand = p_open_video_handle_private( TRUE /* ignore_audio */ , FALSE /* dont ignore_video */ , FALSE /* create_audio_tmp_files */ , NULL /* progress_ptr */ , NULL /* status_msg */ , 0 /* status_msg_len */ ,storyboard_file ,basename ,ext ,frame_from ,frame_to ,frame_count ,TRUE /* do_gimp_progress */ ,input_mode ,imagename ,NULL /* preferred_decoder */ ,1 /* seltrack */ ,0 /* exact_seek */ ,0.0 /* delace */ ,TRUE /* compensate_framerange */ ,NULL /* stb_mem_ptr */ ); if(imagename) { g_free(imagename); } return(l_vidhand); } /* ---------------------------------------------------- * p_exec_filtermacro * ---------------------------------------------------- * - execute the (optional) filtermacro_file if not NULL * (filtermacro_file is a set of one or more gimp_filter procedures * with predefined parameter values) */ static gint32 p_exec_filtermacro(gint32 image_id, gint32 layer_id, const char *filtermacro_file , const char *filtermacro_file_to , gdouble current_step , gint32 total_steps ) { GimpParam* l_params; gint l_retvals; gint32 l_rc_layer_id; gint l_nlayers; gint32 *l_layers_list; l_rc_layer_id = layer_id; if (filtermacro_file) { if(*filtermacro_file != '\0') { if(gap_debug) { printf("DEBUG: before execute filtermacro_file:%s image_id:%d layer_id:%d current:%f total:%d\n" , filtermacro_file , (int)image_id , (int)layer_id , (float)current_step , (int)total_steps ); } if(! gimp_drawable_has_alpha (layer_id)) { /* some filtermacros do not work with layer that do not have an alpha channel * and cause gimp to fail on attempt to call gimp_pixel_rgn_init * with both dirty and shadow flag set to TRUE * in this situation GIMP displays the error message * "expected tile ack and received: 5" * and causes the called plug-in to exit immediate without success * Therfore always add an alpha channel before calling a filtermacro. */ gimp_layer_add_alpha(layer_id); } if((filtermacro_file_to == NULL) || (total_steps <= 1)) { /* execute simple GAP Filtermacro_file */ l_params = gimp_run_procedure (GAP_FMACNAME_PLUG_IN_NAME_FMAC, &l_retvals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, image_id, GIMP_PDB_DRAWABLE, layer_id, GIMP_PDB_STRING, filtermacro_file, GIMP_PDB_END); } else { if(current_step > total_steps) { current_step = total_steps; } if(current_step < 0.0) { current_step = 0.0; } /* execute varying value mix of 2 GAP Filtermacro_files */ l_params = gimp_run_procedure (GAP_FMACNAME_PLUG_IN_NAME_FMAC_VARYING, &l_retvals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, image_id, GIMP_PDB_DRAWABLE, layer_id, GIMP_PDB_STRING, filtermacro_file, GIMP_PDB_STRING, filtermacro_file_to, GIMP_PDB_FLOAT, current_step, /* 0.0 upto 1.0 */ GIMP_PDB_INT32, total_steps, GIMP_PDB_END); } if(l_params[0].data.d_status != GIMP_PDB_SUCCESS) { printf("ERROR: filtermacro_file:%s failed\n", filtermacro_file); l_rc_layer_id = -1; } g_free(l_params); l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list != NULL) { g_free (l_layers_list); } if(l_nlayers > 1 ) { /* merge visible layers (reduce to single layer) */ l_rc_layer_id = gap_image_merge_visible_layers(image_id, GIMP_CLIP_TO_IMAGE); } } } return(l_rc_layer_id); } /* end p_exec_filtermacro */ /* ---------------------------------------------------- * p_transform_and_add_layer * ---------------------------------------------------- * - copy the layer (layer_id) to the composite image * using copy/paste * - the source Layer (layer_id) must be part of tmp_image_id * - set opacity, scale and move layer_id according to video attributes * * return the new created layer id in the comp_image_id * (that is already added to the composte image on top of layerstack) */ static gint32 p_transform_and_add_layer( gint32 comp_image_id , gint32 tmp_image_id , gint32 layer_id , gboolean keep_proportions , gboolean fit_width , gboolean fit_height , gdouble opacity /* 0.0 upto 1.0 */ , gdouble scale_x /* 0.0 upto 10.0 where 1.0 = 1:1 */ , gdouble scale_y /* 0.0 upto 10.0 where 1.0 = 1:1 */ , gdouble move_x /* -1.0 upto +1.0 where 0 = no move, -1 is left outside */ , gdouble move_y /* -1.0 upto +1.0 where 0 = no move, -1 is top outside */ , char *filtermacro_file , gint32 flip_request , GapStoryRenderFrameRangeElem *frn_elem , GapStoryRenderVidHandle *vidhand , gint32 local_stepcount ) { gint32 vid_width; gint32 vid_height; gint32 l_new_layer_id; gint32 l_fsel_layer_id; GapStoryCalcAttr calculate_attributes; GapStoryCalcAttr *calculated; if(gap_debug) { printf("p_transform_and_add_layer: called at layer_id: %d, tmp_image_id:%d\n" , (int)layer_id ,(int)tmp_image_id ); gap_story_render_debug_print_frame_elem(frn_elem, -77); } /* execute input track specific filtermacro (optional if supplied) * local_stepcount (usually delivered by procedure p_fetch_framename) * is used to define fmac_current_step * (starts at 0) */ p_exec_filtermacro(tmp_image_id , layer_id , filtermacro_file , frn_elem->filtermacro_file_to , (gdouble)(local_stepcount) /* fmac_current_step */ , frn_elem->fmac_total_steps ); if(gap_debug) { printf("p_transform_and_add_layer: FILTERMACRO DONE at layer_id: %d, tmp_image_id:%d\n" , (int)layer_id ,(int)tmp_image_id ); } layer_id = gap_layer_flip(layer_id, flip_request); /* expand layer to tmp image size (before applying any scaling) */ gimp_layer_resize_to_image_size(layer_id); vid_width = gimp_image_width(comp_image_id); vid_height = gimp_image_height(comp_image_id); /* calculate scaling, offsets and opacity according to current attributes */ gap_story_file_calculate_render_attributes(&calculate_attributes , vid_width , vid_height , vid_width , vid_height , gimp_image_width(tmp_image_id) , gimp_image_height(tmp_image_id) , keep_proportions , fit_width , fit_height , opacity , scale_x , scale_y , move_x , move_y ); calculated = &calculate_attributes; /* check size and scale source layer_id to calculated size */ if ((gimp_image_width(tmp_image_id) != calculated->width) || (gimp_image_height(tmp_image_id) != calculated->height) ) { if(gap_debug) { printf("DEBUG: p_transform_and_add_layer scaling layer from %dx%d to %dx%d\n" , (int)gimp_image_width(tmp_image_id) , (int)gimp_image_height(tmp_image_id) , (int)calculated->width , (int)calculated->height ); } gimp_layer_scale(layer_id, calculated->width, calculated->height , FALSE /* FALSE: centered at image TRUE: centered local on layer */ ); } /* add a new layer to composite image */ l_new_layer_id = gimp_layer_new(comp_image_id , "pasted_track" , vid_width , vid_height , GIMP_RGBA_IMAGE , 0.0 /* Opacity full transparent */ ,GIMP_NORMAL_MODE); gimp_image_add_layer(comp_image_id, l_new_layer_id, 0); gap_layer_clear_to_color(l_new_layer_id, 0.0, 0.0, 0.0, 0.0); if((frn_elem->mask_name != NULL) && (frn_elem->mask_anchor == GAP_MSK_ANCHOR_CLIP)) { p_fetch_and_add_layermask(vidhand , frn_elem , local_stepcount , tmp_image_id , layer_id ); /* apply the mask (necessary because the following copy with this layer * as source would ignore the layer mask) */ gimp_layer_remove_mask(layer_id, GIMP_MASK_APPLY); } /* copy from tmp_image and paste to composite_image * force copying of the complete layer by clearing the selection */ gimp_selection_none(tmp_image_id); gimp_edit_copy(layer_id); l_fsel_layer_id = gimp_edit_paste(l_new_layer_id, FALSE); /* FALSE paste clear selection */ gimp_layer_set_offsets(l_fsel_layer_id , calculated->x_offs , calculated->y_offs ); gimp_floating_sel_anchor(l_fsel_layer_id); if((frn_elem->mask_name != NULL) && (frn_elem->mask_anchor == GAP_MSK_ANCHOR_MASTER)) { p_fetch_and_add_layermask(vidhand , frn_elem , local_stepcount , comp_image_id , l_new_layer_id ); } gimp_layer_set_opacity(l_new_layer_id, calculated->opacity); return(l_new_layer_id); } /* end p_transform_and_add_layer */ /* ---------------------------------------------------- * p_create_unicolor_image * ---------------------------------------------------- * - create a new image with one black filled layer * (both have the requested size) * * return the new created image_id * and the layer_id of the black_layer */ static gint32 p_create_unicolor_image(gint32 *layer_id, gint32 width , gint32 height , gdouble r_f, gdouble g_f, gdouble b_f, gdouble a_f) { gint32 l_empty_layer_id; gint32 l_image_id; *layer_id = -1; l_image_id = gimp_image_new(width, height, GIMP_RGB); if(l_image_id >= 0) { l_empty_layer_id = gimp_layer_new(l_image_id, "black_background", width, height, GIMP_RGBA_IMAGE, 100.0, /* Opacity full opaque */ GIMP_NORMAL_MODE); gimp_image_add_layer(l_image_id, l_empty_layer_id, 0); /* clear layer to unique color */ gap_layer_clear_to_color(l_empty_layer_id, r_f, g_f, b_f, a_f); *layer_id = l_empty_layer_id; } return(l_image_id); } /* end p_create_unicolor_image */ /* ---------------------------------------------------- * p_prepare_RGB_image * ---------------------------------------------------- * prepare image for encoding * - clear undo stack * - convert to RGB * - merge all visible layer to one layer that * fits the image size. * * return the resulting layer_id. */ static gint32 p_prepare_RGB_image(gint32 image_id) { gint l_nlayers; gint32 *l_layers_list; gint32 l_layer_id; l_layer_id = -1; /* dont waste time and memory for undo in noninteracive processing * of the frames */ /* gimp_image_undo_enable(image_id); */ /* clear undo stack */ /* no more gimp_image_undo_enable, because this results in Warnings since gimp-2.1.6 * Gimp-Core-CRITICAL **: file gimpimage.c: line 1708 (gimp_image_undo_thaw): assertion `gimage->undo_freeze_count > 0' failed */ gimp_image_undo_disable(image_id); /* NO Undo */ l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list != NULL) { l_layer_id = l_layers_list[0]; g_free (l_layers_list); } if((l_nlayers > 1 ) || (gimp_layer_get_mask (l_layer_id) >= 0)) { if(gap_debug) printf("DEBUG: p_prepare_image merge layers tmp image\n"); /* merge visible layers (reduce to single layer) */ l_layer_id = gap_image_merge_visible_layers(image_id, GIMP_CLIP_TO_IMAGE); } /* convert TO RGB if needed */ if(gimp_image_base_type(image_id) != GIMP_RGB) { gimp_image_convert_rgb(image_id); } if(l_layer_id >= 0) { gimp_layer_resize_to_image_size(l_layer_id); } return(l_layer_id); } /* end p_prepare_RGB_image */ /* ---------------------------------------------------- * p_limit_open_videohandles * ---------------------------------------------------- * if the number of currently_open_videohandles exceeds a limit, * then try to close the handle(s) until the number is below the limit. * (but do not close handles that are involved in fetching the current master_frame_nr) * * This kind of garbage collection is useful for storyboards that are using many * different videofile references and would run into memory and other resource problems * when all handles are kept open until the end of rendering process. * (note that each video handle has its own frame cache) */ static void p_limit_open_videohandles(GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr , gint32 currently_open_videohandles ) { #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT #define GAP_STB_DEFAULT_MAX_OPEN_VIDEOFILES 12 GapStoryRenderFrameRangeElem *frn_elem; gint32 l_count_open_videohandles; gint32 l_max_open_videohandles; l_max_open_videohandles = gap_base_get_gimprc_int_value("video-storyboard-max-open-videofiles" , GAP_STB_DEFAULT_MAX_OPEN_VIDEOFILES , 2 , 100 ); l_count_open_videohandles = currently_open_videohandles; if (l_count_open_videohandles <= l_max_open_videohandles) { /* we are below the limit, nothing left to do in that case */ return; } for (frn_elem = vidhand->frn_list; frn_elem != NULL; frn_elem = (GapStoryRenderFrameRangeElem *)frn_elem->next) { if((frn_elem->last_master_frame_access < master_frame_nr) && (frn_elem->gvahand != NULL)) { if(gap_debug) { printf("too many open videofiles %d detected (limit:%d) at master_frame_nr:%d\n" " CLOSING GVA handle for video read access %s\n" , (int)l_count_open_videohandles , (int)l_max_open_videohandles , (int)master_frame_nr , frn_elem->basename ); } GVA_close(frn_elem->gvahand); frn_elem->gvahand = NULL; l_count_open_videohandles--; if (l_count_open_videohandles <= l_max_open_videohandles) { return; } } } #endif return; } /* end p_limit_open_videohandles */ /* ---------------------------------------------------- * p_try_to_steal_gvahand * ---------------------------------------------------- * try to steal an alread open GVA handle for video read from another * element. * conditions: must use same videofile, and exact_seek mode * but steal only handles that are not in current access * (where the last accessed master_frame_nr is lower * than the current one) */ static t_GVA_Handle * p_try_to_steal_gvahand(GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr , char *basename /* the videofile name */ , gint32 exact_seek ) { #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT GapStoryRenderFrameRangeElem *frn_elem; gint32 l_count_open_videohandles; l_count_open_videohandles = 0; for (frn_elem = vidhand->frn_list; frn_elem != NULL; frn_elem = (GapStoryRenderFrameRangeElem *)frn_elem->next) { if (frn_elem->gvahand != NULL) { l_count_open_videohandles++; } if((frn_elem->exact_seek == exact_seek) && (frn_elem->last_master_frame_access < master_frame_nr) && (frn_elem->gvahand != NULL)) { if(strcmp(frn_elem->basename, basename) == 0) { t_GVA_Handle *gvahand; if(gap_debug) { printf("(RE)using an already open GVA handle for video read access %s\n" , frn_elem->basename ); } gvahand = frn_elem->gvahand; frn_elem->gvahand = NULL; /* steal from this element */ return(gvahand); } } } p_limit_open_videohandles(vidhand, master_frame_nr, l_count_open_videohandles); #endif return(NULL); /* nothing found to steal from, return NULL */ } /* end p_try_to_steal_gvahand */ /* ------------------------------------ * gap_story_render_calc_audio_playtime * ------------------------------------ * - check all audio tracks for audio playtime * set *aud_total_sec to the playtime of the * logest audio track playtime. */ void gap_story_render_calc_audio_playtime(GapStoryRenderVidHandle *vidhand, gdouble *aud_total_sec) { gap_story_render_audio_calculate_playtime(vidhand, aud_total_sec); } /* gap_story_render_calc_audio_playtime */ /* ------------------------------------------- * gap_story_render_create_composite_audiofile * ------------------------------------------- */ gboolean gap_story_render_create_composite_audiofile(GapStoryRenderVidHandle *vidhand , char *comp_audiofile ) { return (gap_story_render_audio_create_composite_audiofile(vidhand, comp_audiofile)); } /* end gap_story_render_create_composite_audiofile */ /* -------------------------------------------- * gap_story_convert_layer_to_RGB_thdata * -------------------------------------------- * convert the specified gimp drawable to thdata Buffer * (Bytesequence RGB 8) * if the drawable is a gray image it is converted * to RGB (red, green and blue are set to the same value). */ guchar * gap_story_convert_layer_to_RGB_thdata(gint32 layer_id, gint32 *RAW_size , gint32 *th_bpp , gint32 *th_width , gint32 *th_height ) { GimpDrawable *drawable; GimpPixelRgn pixel_rgn; GimpImageType drawable_type; guchar *RAW_data; guchar *RAW_ptr; guchar *pixelrow_data; guint l_row; gint32 l_idx; gint32 l_blue; gint32 l_green; gint32 l_red; gint32 l_rowstride; drawable = gimp_drawable_get (layer_id); drawable_type = gimp_drawable_type (drawable->drawable_id); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); l_rowstride = drawable->width * drawable->bpp; pixelrow_data = (guchar *)g_malloc0(l_rowstride); *RAW_size = drawable->width * drawable->height * 3; *th_bpp = 3; *th_width = drawable->width; *th_height = drawable->height; RAW_data = (guchar *)g_malloc0((drawable->width * drawable->height * 3)); RAW_ptr = RAW_data; l_red = 0; l_green = 1; l_blue = 2; if((drawable_type == GIMP_GRAY_IMAGE) || (drawable_type == GIMP_GRAYA_IMAGE)) { l_green = 0; l_blue = 0; } for(l_row = 0; l_row < drawable->height; l_row++) { gint32 l_src_row; l_src_row = l_row; gimp_pixel_rgn_get_rect (&pixel_rgn, pixelrow_data , 0 , l_src_row , drawable->width , 1); for(l_idx=0;l_idx < l_rowstride; l_idx += drawable->bpp) { *(RAW_ptr++) = pixelrow_data[l_idx + l_red]; *(RAW_ptr++) = pixelrow_data[l_idx + l_green]; *(RAW_ptr++) = pixelrow_data[l_idx + l_blue]; } } g_free(pixelrow_data); return(RAW_data); } /* end gap_story_convert_layer_to_RGB_thdata */ /* --------------------------------------- * gap_story_render_fetch_composite_vthumb * --------------------------------------- * render composite image and convert * to (RGB 8) thumbdata. */ guchar * gap_story_render_fetch_composite_vthumb(GapStoryRenderVidHandle *stb_comp_vidhand , gint32 framenumber , gint32 width, gint32 height ) { gint32 composite_image_id; gint32 l_layer_id; guchar *th_data; if(gap_debug) { printf("\n###\n###\nSTART VTHUMB rendering at master_frame_nr %d" " with this list of elements:\n" ,(int)framenumber ); gap_story_render_debug_print_framerange_list(stb_comp_vidhand->frn_list, -1); } th_data = NULL; composite_image_id = gap_story_render_fetch_composite_image( stb_comp_vidhand , framenumber , width , height , NULL /* filtermacro_file */ , &l_layer_id ); if(composite_image_id >= 0) { gint32 RAW_size; gint32 th_bpp; gint32 th_width; gint32 th_height; th_data = gap_story_convert_layer_to_RGB_thdata(l_layer_id , &RAW_size , &th_bpp , &th_width , &th_height ); if ((th_width != width) || (th_height != height)) { printf("ERROR: gap_story_render_fetch_composite_vthumb width/height" " expected:(%d/%d) actual:(%d/%d)\n" ,(int)width ,(int)height ,(int)th_width ,(int)th_height ); } gimp_image_delete(composite_image_id); } return (th_data); } /* end gap_story_render_fetch_composite_vthumb */ /* ---------------------------------------------------- * gap_story_render_fetch_composite_image * ---------------------------------------------------- * fetch composite VIDEO Image at a given master_frame_nr * within a storyboard framerange list. * * the returned image is flattend RGB and scaled to * desired video framesize. * * it is a merged result of all video tracks, * * frames at master_frame_nr were loaded * for all video tracks and added to the composite image * (track 0 on top, track N on bottom * of the layerstack) * opacity, scaling and move (decenter) attributes * were set to according to current Video Attributes. * * an (optional) filtermacro_file is performed on the * composite image. * * (simple animations without a storyboard file * are represented by a short storyboard framerange list that has * just one element entry at track 1). * * return image_id of resulting image and the flattened resulting layer_id */ gint32 gap_story_render_fetch_composite_image(GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr /* starts at 1 */ , gint32 vid_width /* desired Video Width in pixels */ , gint32 vid_height /* desired Video Height in pixels */ , char *filtermacro_file /* NULL if no filtermacro is used */ , gint32 *layer_id /* output: Id of the only layer in the composite image */ ) { return ( p_story_render_fetch_composite_image_private(vidhand ,master_frame_nr ,vid_width ,vid_height ,filtermacro_file ,layer_id ,NULL)); } /* end gap_story_render_fetch_composite_image */ /* ------------------------------------------------ * p_split_delace_value * ------------------------------------------------ * split the specified delace value: * integer part is deinterlace mode, * (0 NO, * 1 Odd, * 2 Even, * 3 Odd First, * 4 Even first) * rest is the threshold value. * The localframe_tween_rest is a positive value < 1.0. * This is only relevant in case delace mode is 3 Odd First or 4 Even first. * For clips with standard stepsize 1 localframe_tween_rest is always 0. * In Clips with non-integer stepsize localframe_tween_rest referes * between 2 framenumbers, where the value 0.5 is the middle. * An Interlaced frame contains 2 half-frames where one half-frame is represented by * the even, the other half-frame by the odd lines. * * therfore localframe_tween_rest values >= 0.5 selects the other half-frame, * in case the enable_interlace_tween_pick option is enabled. * * OUT: *deinterlace_ptr * 0 NO, * 1 Odd, * 2 Even, * OUT: *threshold_ptr The threshold < 1.0 for smooth mix of 2 pixel rows. */ static void p_split_delace_value(gdouble delace, gdouble localframe_tween_rest, gint32 *deinterlace_ptr, gdouble *threshold_ptr) { gint32 delace_int; delace_int = delace; *threshold_ptr = delace - (gdouble)delace_int; switch (delace_int) { case 4: *deinterlace_ptr = 2; if (localframe_tween_rest >= 0.5) { *deinterlace_ptr = 1; } break; case 3: *deinterlace_ptr = 1; if (localframe_tween_rest >= 0.5) { *deinterlace_ptr = 2; } break; case 2: *deinterlace_ptr = 2; break; case 1: *deinterlace_ptr = 1; break; default: *deinterlace_ptr = 0; break; } } /* end p_split_delace_value */ /* ------------------------------------------------------------------- * p_conditional_delace_drawable * ------------------------------------------------------------------- * general deinterlace handling for frames, images an animimages * (except cliptype movie) */ static void p_conditional_delace_drawable(GapStbFetchData *gfd, gint32 drawable_id) { gint32 l_deinterlace; gdouble l_threshold; if(gfd->frn_type == GAP_FRN_MOVIE) { /* deinterlace for cliptype movie is already handled by the API at fetching. */ return; } /* split delace value: integer part is deinterlace mode, rest is threshold */ p_split_delace_value(gfd->frn_elem->delace , gfd->localframe_tween_rest , &l_deinterlace , &l_threshold ); #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if (l_deinterlace != 0) { GVA_delace_drawable(drawable_id, l_deinterlace, l_threshold); } #endif } /* end p_conditional_delace_drawable */ /* ------------------------------------------------------------------- * p_stb_render_image_or_animimage (GAP_FRN_ANIMIMAGE or GAP_FRN_IMAGE * ------------------------------------------------------------------- * fetch a single image or animimage */ static void p_stb_render_image_or_animimage(GapStbFetchData *gfd , GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr) { gint32 l_orig_image_id; gint l_nlayers; gint32 *l_layers_list; l_orig_image_id = gap_frame_fetch_orig_image(vidhand->ffetch_user_id , gfd->framename /* full filename of the image */ , TRUE /* enable caching */ ); gimp_selection_none(l_orig_image_id); if(gfd->frn_type == GAP_FRN_IMAGE) { gfd->layer_id = p_prepare_RGB_image(l_orig_image_id); gfd->tmp_image_id = gimp_image_duplicate(l_orig_image_id); } else { /* GAP_FRN_ANIMIMAGE */ if(gap_debug) { printf("ANIM fetch gfd->localframe_index: %d master:%d from: %d to: %d\n" ,(int)gfd->localframe_index ,(int)master_frame_nr ,(int)gfd->frn_elem->frame_from ,(int)gfd->frn_elem->frame_to ); } gfd->tmp_image_id = p_create_unicolor_image(&gfd->layer_id , gimp_image_width(l_orig_image_id) , gimp_image_height(l_orig_image_id) , 0.0, 0.0, 0.0, 0.0); gimp_layer_add_alpha(gfd->layer_id); l_layers_list = gimp_image_get_layers(l_orig_image_id, &l_nlayers); if(l_layers_list != NULL) { if((gfd->localframe_index < l_nlayers) && (gfd->localframe_index >= 0)) { gint32 l_fsel_layer_id; if(gap_debug) { printf("ANIM-IMG: layer_id: %d gimp_layer_get_apply_mask:%d\n" ,(int)l_layers_list[gfd->localframe_index] ,(int)gimp_layer_get_apply_mask(l_layers_list[gfd->localframe_index]) ); } gimp_drawable_set_visible(l_layers_list[gfd->localframe_index], TRUE); if (0 != gimp_layer_get_apply_mask(l_layers_list[gfd->localframe_index])) { /* the layer has an active mask, apply the mask now * because copying from the layer ignores the mask */ gimp_layer_remove_mask(l_layers_list[gfd->localframe_index], GIMP_MASK_APPLY); } gimp_layer_resize_to_image_size(l_layers_list[gfd->localframe_index]); gimp_edit_copy(l_layers_list[gfd->localframe_index]); l_fsel_layer_id = gimp_edit_paste(gfd->layer_id, FALSE); /* FALSE paste clear selection */ gimp_floating_sel_anchor(l_fsel_layer_id); } g_free (l_layers_list); } } } /* end p_stb_render_image_or_animimage */ /* ------------------------------------------- * p_stb_render_movie (GAP_FRN_MOVIE) * ------------------------------------------- * fetch frame from a videofile (gfd->framename contains the videofile name) */ static void p_stb_render_movie(GapStbFetchData *gfd , GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr , gint32 vid_width, gint32 vid_height) { gfd->tmp_image_id = -1; #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if(gfd->frn_elem->gvahand == NULL) { /* before we open a new GVA videohandle, lets check * if another element has already opened this videofile, * and reuse the already open gvahand handle if possible */ gfd->frn_elem->gvahand = p_try_to_steal_gvahand(vidhand , master_frame_nr , gfd->frn_elem->basename , gfd->frn_elem->exact_seek ); if(gfd->frn_elem->gvahand == NULL) { if(vidhand->preferred_decoder) { gfd->frn_elem->gvahand = GVA_open_read_pref(gfd->framename , gfd->frn_elem->seltrack , 1 /* aud_track */ , vidhand->preferred_decoder , FALSE /* use MMX if available (disable_mmx == FALSE) */ ); } else { gfd->frn_elem->gvahand = GVA_open_read(gfd->framename ,gfd->frn_elem->seltrack ,1 /* aud_track */ ); } if(gfd->frn_elem->gvahand) { GVA_set_fcache_size(gfd->frn_elem->gvahand, GAP_STB_RENDER_GVA_FRAMES_TO_KEEP_CACHED); gfd->frn_elem->gvahand->do_gimp_progress = vidhand->do_gimp_progress; if(gfd->frn_elem->exact_seek == 1) { /* configure the GVA Procedures for exact (but slow) seek emulaion */ gfd->frn_elem->gvahand->emulate_seek = TRUE; } } } } if(gfd->frn_elem->gvahand) { gint32 l_deinterlace; gdouble l_threshold; t_GVA_RetCode l_fcr; /* split delace value: integer part is deinterlace mode, rest is threshold */ p_split_delace_value(gfd->frn_elem->delace , gfd->localframe_tween_rest , &l_deinterlace , &l_threshold ); /* set image and layer in the gvahand structure invalid, * to force creation of a new image in the following call of GVA_frame_to_gimp_layer */ gfd->frn_elem->gvahand->image_id = -1; gfd->frn_elem->gvahand->layer_id = -1; /* attempt to read frame from the GVA API internal framecache */ /* printf("\nST: before GVA_debug_print_fcache (2) #:%d\n", (int)gfd->localframe_index ); * GVA_debug_print_fcache(gfd->frn_elem->gvahand); * printf("ST: before GVA_frame_to_gimp_layer (2) attempt cache read #:%d\n", (int)gfd->localframe_index ); */ l_fcr = GVA_frame_to_gimp_layer(gfd->frn_elem->gvahand , TRUE /* delete_mode */ , gfd->localframe_index /* framenumber */ , l_deinterlace , l_threshold ); if (l_fcr != GVA_RET_OK) { /* if no success, we try explicite read that frame */ if(gfd->frn_elem->gvahand->current_seek_nr != gfd->localframe_index) { if(((gfd->frn_elem->gvahand->current_seek_nr + GAP_STB_RENDER_GVA_FRAMES_TO_KEEP_CACHED) > gfd->localframe_index) && (gfd->frn_elem->gvahand->current_seek_nr < gfd->localframe_index ) ) { /* near forward seek is performed by dummyreads to fill up the framecache */ while(gfd->frn_elem->gvahand->current_seek_nr < gfd->localframe_index) { GVA_get_next_frame(gfd->frn_elem->gvahand); } } else { if(vidhand->do_gimp_progress) { gimp_progress_init(_("Seek Inputvideoframe...")); } GVA_seek_frame(gfd->frn_elem->gvahand, (gdouble)gfd->localframe_index, GVA_UPOS_FRAMES); if(vidhand->do_gimp_progress) { gimp_progress_init(_("Continue Encoding...")); } } } if(GVA_get_next_frame(gfd->frn_elem->gvahand) == GVA_RET_OK) { GVA_frame_to_gimp_layer(gfd->frn_elem->gvahand , TRUE /* delete_mode */ , gfd->localframe_index /* framenumber */ , l_deinterlace , l_threshold ); } } /* take the newly created image from gvahand stucture */ gfd->tmp_image_id = gfd->frn_elem->gvahand->image_id; gfd->frn_elem->gvahand->image_id = -1; gfd->frn_elem->gvahand->layer_id = -1; } #endif } /* end p_stb_render_movie */ /* ------------------------------------------- * p_stb_render_section (GAP_FRN_SECTION) * ------------------------------------------- * handle section rendering (via recursive call) */ static void p_stb_render_section(GapStbFetchData *gfd , GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr , gint32 vid_width, gint32 vid_height , const char *section_name) { gint32 sub_layer_id; gint32 sub_master_frame_nr; const char *sub_section_name; gboolean orig_do_progress; gdouble orig_progress; if(gap_debug) { printf("SUB-SECTION: before RECURSIVE call\n"); } orig_do_progress = vidhand->do_gimp_progress; orig_progress = *vidhand->progress; vidhand->do_gimp_progress = FALSE; sub_section_name = gfd->framename; sub_master_frame_nr = gfd->localframe_index; gfd->tmp_image_id = p_story_render_fetch_composite_image_private(vidhand , sub_master_frame_nr , vid_width , vid_height , NULL /* filtrmacro_file */ , &sub_layer_id , sub_section_name ); if(gap_debug) { printf("SUB-SECTION: after RECURSIVE call\n"); } /* The recursive call of p_story_render_fetch_composite_image_private * has set frn_list and aud_list to a sub_section. * therefore switch back to current section after the call. * furthermore restore progress settings. */ p_select_section_by_name(vidhand, section_name); vidhand->do_gimp_progress = orig_do_progress; *vidhand->progress = orig_progress; } /* end p_stb_render_section */ /* ------------------------------------------- * p_stb_render_frame_images (GAP_FRN_FRAMES) * ------------------------------------------- * gfd->framename is one single imagefile out of a series of numbered imagefiles. * (note that the gfd->framename is already full qualified * and includes path name, numberpart and extension) */ static void p_stb_render_frame_images(GapStbFetchData *gfd, gint32 master_frame_nr) { if(gap_debug) { printf("FRAME fetch gfd->framename: %s\n ===> master:%d from: %d to: %d\n" ,gfd->framename ,(int)master_frame_nr ,(int)gfd->frn_elem->frame_from ,(int)gfd->frn_elem->frame_to ); } gfd->tmp_image_id = gap_lib_load_image(gfd->framename); } /* end p_stb_render_frame_images */ /* ------------------------------------------- * p_stb_render_composite_image_postprocessing * ------------------------------------------- * perform postprocessing on the composite frame image. * this includes * - convert to gray (only when fetching masks) * - optional applying the global filtermacro * - check size and scale (if filtermacro has changed size of the composite image) * - check layers and flatten in case there is more than one layer * The result is a single layer ( gfd->layer_id ) in the composite image. */ static void p_stb_render_composite_image_postprocessing(GapStbFetchData *gfd , GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr , gint32 vid_width, gint32 vid_height , char *filtermacro_file , const char *section_name ) { gint l_nlayers; gint32 *l_layers_list; if(gfd->comp_image_id < 0) { /* none of the tracks had a frame image on this master_frame_nr position * create a blank image (VID_SILENNCE) */ gfd->comp_image_id = p_create_unicolor_image(&gfd->layer_id , vid_width , vid_height , 0.0 , 0.0 , 0.0 , 1.0 ); } if(vidhand->is_mask_handle == TRUE) { /* we are running as mask fetcher, * therefore convert to GRAY image */ if(gimp_image_base_type(gfd->comp_image_id) != GIMP_GRAY) { gimp_image_convert_grayscale(gfd->comp_image_id); } } /* debug: disabled code to display a copy of the image */ if(1==0) { p_debug_dup_image(gfd->comp_image_id); } /* check the layerstack */ l_layers_list = gimp_image_get_layers(gfd->comp_image_id, &l_nlayers); if(l_layers_list != NULL) { gfd->layer_id = l_layers_list[0]; g_free (l_layers_list); } if((vidhand->is_mask_handle != TRUE) && (section_name == NULL)) { /* debug feature: save the multilayer composite frame * before it is passed to the filtermacro * (always off for mask fetching) */ p_frame_backup_save( GAP_VID_ENC_SAVE_MULTILAYER , gfd->comp_image_id , gfd->layer_id , master_frame_nr , TRUE /* can be multilayer */ ); } if((l_nlayers > 1 ) || (gimp_drawable_has_alpha(gfd->layer_id))) { if(gap_debug) { printf("DEBUG: p_stb_render_composite_image_postprocessing flatten Composite image\n"); } /* flatten current frame image (reduce to single layer) */ gfd->layer_id = gimp_image_flatten (gfd->comp_image_id); } /* execute filtermacro (optional if supplied) */ p_exec_filtermacro(gfd->comp_image_id , gfd->layer_id , filtermacro_file , NULL /* have no 2nd filtermacro_file_to for varying parametersets */ , 0.0 /* current_step */ , 1 /* total_steps */ ); /* check again size and scale image to desired Videosize if needed */ if ((gimp_image_width(gfd->comp_image_id) != vid_width) || (gimp_image_height(gfd->comp_image_id) != vid_height) ) { if(gap_debug) printf("DEBUG: p_story_render_fetch_composite_image_private: scaling tmp image\n"); gimp_image_scale(gfd->comp_image_id, vid_width, vid_height); } /* check again for layerstack (macro could have add more layers) * or there might be an alpha channel */ l_layers_list = gimp_image_get_layers(gfd->comp_image_id, &l_nlayers); if(l_layers_list != NULL) { gfd->layer_id = l_layers_list[0]; g_free (l_layers_list); } if((l_nlayers > 1 ) || (gimp_drawable_has_alpha(gfd->layer_id))) { if(gap_debug) printf("DEBUG: p_story_render_fetch_composite_image_private FINAL flatten Composite image\n"); /* flatten current frame image (reduce to single layer) */ gfd->layer_id = gimp_image_flatten (gfd->comp_image_id); } } /* end p_stb_render_composite_image_postprocessing */ /* ------------------------------------------- * p_stb_render_result_monitoring * ------------------------------------------- * */ static void p_stb_render_result_monitoring(GapStbFetchData *gfd, gint32 master_frame_nr) { /* debug feature: save the flattened composite as jpg frame before it is passed to the encoder */ p_frame_backup_save( GAP_VID_ENC_SAVE_FLAT , gfd->comp_image_id , gfd->layer_id , master_frame_nr , FALSE /* is no multilayer, use jpeg */ ); /* debug feature: monitor composite image while encoding */ p_encoding_monitor(GAP_VID_ENC_MONITOR , gfd->comp_image_id , gfd->layer_id , master_frame_nr ); } /* end p_stb_render_result_monitoring */ /* ------------------------ * p_paste_logo_pattern * ------------------------ * replace logo area with the specified logo pattern */ static void p_paste_logo_pattern(gint32 drawable_id , gint32 logo_pattern_id , gint32 offsetX , gint32 offsetY ) { gint32 l_fsel_layer_id; gint l_src_offset_x; gint l_src_offset_y; gint32 image_id; image_id = gimp_drawable_get_image(drawable_id); gimp_selection_all(gimp_drawable_get_image(logo_pattern_id)); /* findout the offsets of the replacement_pattern layer within the source Image */ gimp_drawable_offsets(logo_pattern_id, &l_src_offset_x, &l_src_offset_y ); gimp_edit_copy(logo_pattern_id); l_fsel_layer_id = gimp_edit_paste(drawable_id, TRUE); /* FALSE paste clear selection */ gimp_selection_none(gimp_drawable_get_image(logo_pattern_id)); if(gap_debug) { gint l_fsel_offset_x; gint l_fsel_offset_y; gimp_drawable_offsets(l_fsel_layer_id, &l_fsel_offset_x, &l_fsel_offset_y ); printf("p_paste_logo_pattern: l_src_offsets: (%d %d) fsel:(%d %d) final offsets: (%d %d) rep_id:%d\n" ,(int)l_src_offset_x ,(int)l_src_offset_y ,(int)l_fsel_offset_x ,(int)l_fsel_offset_y ,(int)(offsetX + l_src_offset_x) ,(int)(offsetY + l_src_offset_y) ,(int)logo_pattern_id ); } gimp_layer_set_offsets(l_fsel_layer_id , offsetX + l_src_offset_x , offsetY + l_src_offset_y); gimp_floating_sel_anchor(l_fsel_layer_id); } /* end p_copy_and_paste_replacement_pattern */ /* ------------------------------------- * p_do_insert_area_processing * ------------------------------------- */ static void p_do_insert_area_processing(GapStbFetchData *gfd , GapStoryRenderVidHandle *vidhand) { char *logo_imagename; char *videofilename_without_path; videofilename_without_path = gap_story_build_basename(gfd->framename); if (vidhand->master_insert_area_format_has_framenumber) { if (vidhand->master_insert_area_format_has_videobasename) { logo_imagename = g_strdup_printf(vidhand->master_insert_area_format , videofilename_without_path , gfd->localframe_index /* videoFrameNr */ ); } else { logo_imagename = g_strdup_printf(vidhand->master_insert_area_format , gfd->localframe_index /* videoFrameNr */ ); } } else { if (vidhand->master_insert_area_format_has_videobasename) { logo_imagename = g_strdup_printf(vidhand->master_insert_area_format , videofilename_without_path ); } else { logo_imagename = g_strdup(vidhand->master_insert_area_format); } } if(gap_debug) { printf("p_do_insert_area_processing: format:%s\n video:%s\n logo_imagename:%s\n" , vidhand->master_insert_area_format , videofilename_without_path , logo_imagename ); } if(g_file_test(logo_imagename, G_FILE_TEST_EXISTS)) { gint32 logo_image_id; gint32 logo_layer_id; if (vidhand->master_insert_area_format_has_framenumber) { logo_image_id = gap_lib_load_image(logo_imagename); } else { /* use framefetcher cache in case all frames shall get the same logo */ logo_image_id = gap_frame_fetch_orig_image(vidhand->ffetch_user_id , logo_imagename , TRUE /* enable caching */ ); } if(logo_image_id < 0) { printf("p_do_insert_area_processing: ERROR could not load logo_imagename:%s\n", logo_imagename); return; } gimp_selection_none(logo_image_id); logo_layer_id = p_prepare_RGB_image(logo_image_id); p_paste_logo_pattern(gfd->layer_id , logo_layer_id , 0, 0 /* offest_X, offset_Y */ ); if (vidhand->master_insert_area_format_has_framenumber) { /* do not keep individual per frame logo images cached */ gap_image_delete_immediate(logo_image_id); } } } /* end p_do_insert_area_processing */ /* -------------------------------------------- * p_story_render_fetch_composite_image_private * -------------------------------------------- * this procedure builds the composite image for the fram number specified by master_frame_nr. * Therefore all videotracks of the storyboard (specified via an already opened handle vidhand) * are fetched as layers. The track number is the layerstack index. * optional filtermacro processing is done for the separate layers (clip specific filtermacre) * and for the composite image (global filtermacro) */ static gint32 p_story_render_fetch_composite_image_private(GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr /* starts at 1 */ , gint32 vid_width /* desired Video Width in pixels */ , gint32 vid_height /* desired Video Height in pixels */ , char *filtermacro_file /* NULL if no filtermacro is used */ , gint32 *layer_id /* output: Id of the only layer in the composite image */ , const char *section_name /* NULL for main section */ ) { GapStbFetchData gapStbFetchData; GapStbFetchData *gfd; gint l_track; gint32 l_track_min; gint32 l_track_max; gdouble l_red_f; gdouble l_green_f; gdouble l_blue_f; gdouble l_alpha_f; gfd = &gapStbFetchData; gfd->localframe_tween_rest = 0.0; gfd->comp_image_id = -1; gfd->tmp_image_id = -1; gfd->layer_id = -1; *layer_id = -1; if(gap_debug) { printf("p_story_render_fetch_composite_image_private START master_frame_nr:%d %dx%d vidhand:%d\n" , (int)master_frame_nr , (int)vid_width , (int)vid_height , (int)vidhand ); if (section_name == NULL) { printf(" section_name: (null)\n"); } else { printf(" section_name: %s\n", section_name); } } p_select_section_by_name(vidhand, section_name); if(gap_debug) { if((vidhand->is_mask_handle == FALSE) && (master_frame_nr == 1) // && (section_name == NULL) ) { printf("\n###\n###\nSTART rendering at master_frame_nr 1 with this list of elements:\n"); gap_story_render_debug_print_framerange_list(vidhand->frn_list, -1); } } p_find_min_max_vid_tracknumbers(vidhand->frn_list, &l_track_min, &l_track_max); /* reverse order, has the effect, that track 0 is processed as last track * and will be put on top of the layerstack */ for(l_track = MIN(GAP_STB_MAX_VID_INTERNAL_TRACKS, l_track_max); l_track >= MAX(0, l_track_min); l_track--) { gfd->framename = p_fetch_framename(vidhand->frn_list , master_frame_nr /* starts at 1 */ , l_track , &gfd->frn_type , &gfd->trak_filtermacro_file , &gfd->localframe_index /* used only for ANIMIMAGE, SECTION and Videoframe Number, -1 for all other types */ , &gfd->local_stepcount /* nth frame within this clip */ , &gfd->localframe_tween_rest /* non integer part of local position (in case stepsize != 1) */ , &gfd->keep_proportions , &gfd->fit_width , &gfd->fit_height , &l_red_f , &l_green_f , &l_blue_f , &l_alpha_f , &gfd->opacity /* output opacity 0.0 upto 1.0 */ , &gfd->scale_x /* output 0.0 upto 10.0 where 1.0 is 1:1 */ , &gfd->scale_y /* output 0.0 upto 10.0 where 1.0 is 1:1 */ , &gfd->move_x /* output -1.0 upto 1.0 where 0.0 is centered */ , &gfd->move_y /* output -1.0 upto 1.0 where 0.0 is centered */ , &gfd->frn_elem /* output selected to the relevant framerange element */ ); if((gfd->framename) || (gfd->frn_type == GAP_FRN_COLOR)) { if(gfd->frn_type == GAP_FRN_COLOR) { gfd->tmp_image_id = p_create_unicolor_image(&gfd->layer_id , vid_width , vid_height , l_red_f , l_green_f , l_blue_f , l_alpha_f ); } else { if(gfd->framename) { if((gfd->frn_type == GAP_FRN_ANIMIMAGE) || (gfd->frn_type == GAP_FRN_IMAGE)) { p_stb_render_image_or_animimage(gfd, vidhand, master_frame_nr); } else { if(gfd->frn_type == GAP_FRN_MOVIE) { p_stb_render_movie(gfd, vidhand, master_frame_nr, vid_width, vid_height); } else { if(gfd->frn_type == GAP_FRN_SECTION) { p_stb_render_section(gfd, vidhand, master_frame_nr, vid_width, vid_height, section_name); } else { /* GAP_FRN_FRAMES */ p_stb_render_frame_images(gfd, master_frame_nr); } } } if(gfd->tmp_image_id < 0) { printf("\n** ERROR fetching master_frame_nr:%d, from framename:%s Current CLIP was:\n" , (int)master_frame_nr , (int)gfd->framename ); gap_story_render_debug_print_frame_elem(gfd->frn_elem, -1); printf("\n** storyboard render processing failed\n"); g_free(gfd->framename); return -1; } gfd->layer_id = p_prepare_RGB_image(gfd->tmp_image_id); if((gfd->frn_type == GAP_FRN_MOVIE) && (vidhand->master_insert_area_format)) { p_do_insert_area_processing(gfd, vidhand); } p_conditional_delace_drawable(gfd, gfd->layer_id); g_free(gfd->framename); } } if(gap_debug) { printf("p_prepare_RGB_image returned layer_id: %d, tmp_image_id:%d\n" , (int)gfd->layer_id , (int)gfd->tmp_image_id ); } if(gfd->comp_image_id < 0) { if((gfd->opacity == 1.0) && (gfd->scale_x == 1.0) && (gfd->scale_y == 1.0) && (gfd->move_x == 0.0) && (gfd->move_y == 0.0) && (gfd->fit_width) && (gfd->fit_height) && (!gfd->keep_proportions) && (gfd->frn_elem->flip_request == GAP_STB_FLIP_NONE) && (gfd->frn_elem->mask_name == NULL) && (gfd->trak_filtermacro_file == NULL) && (gfd->frn_type != GAP_FRN_ANIMIMAGE) ) { /* because there are no transformations in the first handled track, * we can save time and directly use the loaded tmp image as base for the composite image */ gfd->comp_image_id = gfd->tmp_image_id; /* scale image to desired Videosize */ if ((gimp_image_width(gfd->comp_image_id) != vid_width) || (gimp_image_height(gfd->comp_image_id) != vid_height) ) { if(gap_debug) printf("DEBUG: p_story_render_fetch_composite_image_private scaling composite image\n"); gimp_image_scale(gfd->comp_image_id, vid_width, vid_height); } } else { /* create empty backgound */ gint32 l_empty_layer_id; gfd->comp_image_id = p_create_unicolor_image(&l_empty_layer_id , vid_width , vid_height , 0.0 , 0.0 , 0.0 , 1.0 ); } } if(gfd->tmp_image_id != gfd->comp_image_id) { p_transform_and_add_layer(gfd->comp_image_id, gfd->tmp_image_id, gfd->layer_id ,gfd->keep_proportions ,gfd->fit_width ,gfd->fit_height ,gfd->opacity ,gfd->scale_x ,gfd->scale_y ,gfd->move_x ,gfd->move_y ,gfd->trak_filtermacro_file ,gfd->frn_elem->flip_request ,gfd->frn_elem ,vidhand ,gfd->local_stepcount ); gap_image_delete_immediate(gfd->tmp_image_id); } } } /* end for loop over all video tracks */ p_stb_render_composite_image_postprocessing(gfd , vidhand, master_frame_nr , vid_width, vid_height , filtermacro_file , section_name ); *layer_id = gfd->layer_id; if((vidhand->is_mask_handle != TRUE) && (section_name == NULL)) { p_stb_render_result_monitoring(gfd, master_frame_nr); } if(gap_debug) { printf("p_story_render_fetch_composite_image_private END master_frame_nr:%d image_id:%d layer_id:%d\n" , (int)master_frame_nr , (int)gfd->comp_image_id , (int)*layer_id ); } return(gfd->comp_image_id); } /* end p_story_render_fetch_composite_image_private */ /* ------------------------------------------------------------------- * gap_story_render_fetch_composite_image_or_chunk (see included file) * ------------------------------------------------------------------- * */ #include "gap_story_render_lossless.c" gimp-gap-2.6.0+dfsg.orig/gap/gap_drawable_vref_parasite.c0000644000175000017500000001427211212030253023210 0ustar thibautthibaut/* 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 * * * 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 #include #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 */ gimp-gap-2.6.0+dfsg.orig/gap/gap_story_properties.h0000644000175000017500000000277711212030253022165 0ustar thibautthibaut/* gap_story_properties.h * * This module handles GAP storyboard dialog properties window */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.26a; 2004/02/18 hof: created */ #ifndef _GAP_STORY_PROPERTIES_H #define _GAP_STORY_PROPERTIES_H #include "libgimp/gimp.h" #include "gap_story_main.h" GtkWidget * gap_story_pw_properties_dialog (GapStbPropWidget *pw); void gap_story_stb_elem_properties_dialog ( GapStbTabWidgets *tabw , GapStoryElem *stb_elem , GapStoryBoard *stb_dst); void gap_story_fw_properties_dialog (GapStbFrameWidget *fw); void gap_story_pw_trigger_refresh_properties(GapStbPropWidget *pw); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_wr_resynth.c0000755000175000017500000006360611212030253020731 0ustar thibautthibaut/* gap_wr_resynth.c * provides automated animated apply support for the 3rd party resynthesizer plug-in. * Useful to remove unwanted logos when processing video frames. * PRECONDITIONS: * Requires resynthesizer plug-in. * (resynthesizer-0.16.tar.gz is available in the gimp plug-in registry) * NOTE this wrapper also supports an extended variant plug-in-resynthesizer-s * that has an additional seed parameter. */ /* GIMP - The GNU Image Manipulation Program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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 "config.h" #include #include #include #include #include #include #include "gap_lastvaldesc.h" #include "gap_lastvaldesc.h" #include "gap_libgimpgap.h" #include "gap-intl.h" /***** Macro definitions *****/ #define PLUG_IN_PROC "plug-in-wr-resynth" #define PLUG_IN_VERSION "0.16" #define PLUG_IN_AUTHOR "Wolfgang Hofer (hof@gimp.org)" #define PLUG_IN_COPYRIGHT "Wolfgang Hofer" #define PLUG_IN_BINARY "gap_wr_resynth" #define PLUG_IN_RESYNTHESIZER "plug-in-resynthesizer" #define PLUG_IN_RESYNTHESIZER_WITH_SEED "plug-in-resynthesizer-s" /* unpublished prvate version */ /***** Magic numbers *****/ #define SCALE_WIDTH 200 #define SPIN_BUTTON_WIDTH 60 /***** Types *****/ typedef struct { gint32 corpus_border_radius; gint32 alt_selection; gint32 seed; } TransValues; static TransValues glob_vals = { 20 /* corpus_border_radius */ , -1 /* alt_selection (drawable id or -1 for using original selection) */ , 4711 /* seed for random number generator */ }; /***** Prototypes *****/ static void query (void); static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals); static gint p_selectionConstraintFunc (gint32 image_id, gint32 drawable_id, gpointer data); static gboolean p_dialog(TransValues *val_ptr, gint32 drawable_id); static gint32 p_process_layer(gint32 image_id, gint32 drawable_id, TransValues *val_ptr); /***** Variables *****/ const GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run /* run_proc */ }; static GimpParamDef in_args[] = { { GIMP_PDB_INT32, "run-mode", "Interactive, non-interactive" }, { GIMP_PDB_IMAGE, "image", "Input image" }, { GIMP_PDB_DRAWABLE, "drawable", "The drawable (typically a layer)" }, { GIMP_PDB_INT32, "corpus_border_radius", "Radius to take texture from" }, { GIMP_PDB_DRAWABLE, "alt_selection", "id of a drawable to replace the selection (use -1 to operate with selection of the input image)" }, { GIMP_PDB_INT32, "seed", "seed for random numbers (use -1 to init with current time)" } }; static GimpParamDef return_vals[] = { { GIMP_PDB_DRAWABLE, "the_drawable", "the handled drawable" } }; static gint global_number_in_args = G_N_ELEMENTS (in_args); static gint global_number_out_args = G_N_ELEMENTS (return_vals); /* Global Variables */ int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */ /***** Functions *****/ MAIN() /* ------------------ * query * ------------------ */ static void query (void) { static GimpLastvalDef lastvals[] = { GIMP_LASTVALDEF_GINT32 (GIMP_ITER_TRUE, glob_vals.corpus_border_radius, "corpus_border_radius"), GIMP_LASTVALDEF_DRAWABLE (GIMP_ITER_TRUE, glob_vals.alt_selection, "alt_selection"), GIMP_LASTVALDEF_GINT32 (GIMP_ITER_TRUE, glob_vals.seed, "seed") }; /* registration for last values buffer structure (useful for animated filter apply) */ gimp_lastval_desc_register(PLUG_IN_PROC, &glob_vals, sizeof(glob_vals), G_N_ELEMENTS (lastvals), lastvals); gimp_install_procedure (PLUG_IN_PROC, N_("Smart selection eraser."), "Remove an object from an image by extending surrounding texture to cover it. " "The object can be represented by the current selection " "or by an alternative selction (provided as parameter alt_selection) " "If the image, that is refered by the alt_selction drawable_id has a selction " "then the refred selection is used to identify the object. " "otherwise a grayscale copy of the alt_selection drawable_id will be used " "to identify the object that shall be replaced. " "alt_selection value -1 indicates that the selection of the input image shall be used. " "Requires resynthesizer plug-in. (available in the gimp plug-in registry) " "The smart selection eraser wrapper provides ability to run in GIMP_GAP filtermacros " "when processing video frames (typically for removing unwanted logos from video frames)." "(using the same seed value for all frames is recommanded) ", "Wolfgang Hofer", "Wolfgang Hofer", PLUG_IN_VERSION, N_("Smart selection eraser..."), "RGB*, GRAY*", GIMP_PLUGIN, global_number_in_args, global_number_out_args, in_args, return_vals); { /* Menu names */ const char *menupath_image_video_layer = N_("/Video/Layer/Enhance/"); gimp_plugin_menu_register (PLUG_IN_PROC, menupath_image_video_layer); } } /* end query */ static void run (const gchar *name, /* name of plugin */ gint nparams, /* number of in-paramters */ const GimpParam * param, /* in-parameters */ gint *nreturn_vals, /* number of out-parameters */ GimpParam ** return_vals) /* out-parameters */ { const gchar *l_env; gint32 image_id = -1; gint32 drawable_id = -1; gint32 trans_drawable_id = -1; /* Get the runmode from the in-parameters */ GimpRunMode run_mode = param[0].data.d_int32; /* status variable, use it to check for errors in invocation usualy only during non-interactive calling */ GimpPDBStatusType status = GIMP_PDB_SUCCESS; /* always return at least the status to the caller. */ static GimpParam values[2]; INIT_I18N(); l_env = g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } if(gap_debug) printf("\n\nDEBUG: run %s\n", name); /* initialize the return of the status */ values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; values[1].type = GIMP_PDB_DRAWABLE; values[1].data.d_drawable = -1; *nreturn_vals = 2; *return_vals = values; /* get image and drawable */ image_id = param[1].data.d_int32; drawable_id = param[2].data.d_int32; if (strcmp (name, PLUG_IN_PROC) == 0) { if(gimp_drawable_is_layer(drawable_id)) { gboolean run_flag; /* Initial values */ glob_vals.corpus_border_radius = 20; glob_vals.alt_selection = -1; run_flag = TRUE; /* Possibly retrieve data from a previous run */ gimp_get_data (name, &glob_vals); switch (run_mode) { case GIMP_RUN_INTERACTIVE: /* Get information from the dialog */ run_flag = p_dialog(&glob_vals, drawable_id); break; case GIMP_RUN_NONINTERACTIVE: /* check to see if invoked with the correct number of parameters */ if (nparams >= global_number_in_args) { glob_vals.corpus_border_radius = param[3].data.d_int32; glob_vals.alt_selection = param[4].data.d_int32; glob_vals.seed = param[5].data.d_int32; } else { status = GIMP_PDB_CALLING_ERROR; } break; case GIMP_RUN_WITH_LAST_VALS: break; default: break; } /* here the action starts, we transform the drawable */ if(run_flag) { trans_drawable_id = p_process_layer(image_id , drawable_id , &glob_vals ); if (trans_drawable_id < 0) { status = GIMP_PDB_CALLING_ERROR; } else { values[1].data.d_drawable = drawable_id; /* Store variable states for next run * (the parameters for the transform wrapper plugins are stored * even if they contain just a dummy * this is done to fullfill the GIMP-GAP LAST_VALUES conventions * for filtermacro and animated calls) */ if (run_mode == GIMP_RUN_INTERACTIVE) { gimp_set_data (name, &glob_vals, sizeof (TransValues)); } } } } else { status = GIMP_PDB_CALLING_ERROR; if (run_mode == GIMP_RUN_INTERACTIVE) { g_message(_("The plug-in %s\noperates only on layers\n" "(but was called on mask or channel)") , name ); } } } else { status = GIMP_PDB_CALLING_ERROR; } if (status == GIMP_PDB_SUCCESS) { /* If run mode is interactive, flush displays, else (script) don't * do it, as the screen updates would make the scripts slow */ if (run_mode != GIMP_RUN_NONINTERACTIVE) gimp_displays_flush (); } values[0].data.d_status = status; } /* end run */ /* ---------------------------- * p_selectionConstraintFunc * ---------------------------- * */ static gint p_selectionConstraintFunc (gint32 image_id, gint32 drawable_id, gpointer data) { if (image_id < 0) return FALSE; /* dont accept layers from indexed images */ if (gimp_drawable_is_indexed (drawable_id)) return FALSE; return TRUE; } /* end p_selectionConstraintFunc */ /* ---------------------------- * p_selectionComboCallback * ---------------------------- * */ static void p_selectionComboCallback (GtkWidget *widget) { gint idValue; if(gap_debug) { printf("p_selectionComboCallback START\n"); } gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &idValue); if(gap_debug) { printf("p_selectionComboCallback idValue:%d\n", idValue); } glob_vals.alt_selection = idValue; } /* end p_selectionComboCallback */ /* -------------------------- * p_dialog * -------------------------- */ static gboolean p_dialog (TransValues *val_ptr, gint32 drawable_id) { GtkWidget *dialog; GtkWidget *main_vbox; GtkWidget *label; GtkWidget *table; GtkWidget *combo; GtkObject *adj; gint row; gboolean run; gboolean isResynthesizerInstalled; gboolean foundResynth; gboolean foundResynthS; foundResynthS = gap_pdb_procedure_name_available(PLUG_IN_RESYNTHESIZER_WITH_SEED); foundResynth = gap_pdb_procedure_name_available(PLUG_IN_RESYNTHESIZER); isResynthesizerInstalled = ((foundResynthS) || (foundResynth)); val_ptr->alt_selection = -1; gimp_ui_init (PLUG_IN_BINARY, TRUE); if (isResynthesizerInstalled) { dialog = gimp_dialog_new (_("Smart selection eraser"), PLUG_IN_BINARY, NULL, 0, gimp_standard_help_func, PLUG_IN_PROC, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); } else { dialog = gimp_dialog_new (_("Smart selection eraser"), PLUG_IN_BINARY, NULL, 0, gimp_standard_help_func, PLUG_IN_PROC, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); } gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); gimp_window_set_transient (GTK_WINDOW (dialog)); main_vbox = gtk_vbox_new (FALSE, 12); gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12); gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox); gtk_widget_show (main_vbox); /* Controls */ table = gtk_table_new (3, 3, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 6); gtk_table_set_row_spacings (GTK_TABLE (table), 6); gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0); gtk_widget_show (table); row = 0; if (isResynthesizerInstalled != TRUE) { label = gtk_label_new (_("The Resynthesizer plug-in is required for this operation\n" "But this 3rd party plug-in is not installed\n" "Resynthesizer is available at the gimp plug-in registry")); gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 2, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); gtk_widget_show (label); row++; } else { adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row, _("Border Radius:"), SCALE_WIDTH, 7, val_ptr->corpus_border_radius, 0.0, 1000.0, 1.0, 10.0, 0, TRUE, 0, 0, NULL, NULL); g_signal_connect (adj, "value-changed", G_CALLBACK (gimp_int_adjustment_update), &val_ptr->corpus_border_radius); row++; if (foundResynthS) { adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row, _("Seed:"), SCALE_WIDTH, 7, val_ptr->seed, -1.0, 10000.0, 1.0, 10.0, 0, TRUE, 0, 0, NULL, NULL); g_signal_connect (adj, "value-changed", G_CALLBACK (gimp_int_adjustment_update), &val_ptr->seed); row++; } /* layer combo_box (alt_selection) */ label = gtk_label_new (_("Set Selection:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); gtk_widget_show (label); /* layer combo_box (Sample from where to pick the alternative selection */ combo = gimp_layer_combo_box_new (p_selectionConstraintFunc, NULL); gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), drawable_id, G_CALLBACK (p_selectionComboCallback), NULL); gtk_table_attach (GTK_TABLE (table), combo, 1, 3, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); gtk_widget_show (combo); } /* Done */ gtk_widget_show (dialog); run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK); gtk_widget_destroy (dialog); return run; } /* end p_dialog */ /* -------------------------------- * p_pdb_call_resynthesizer * -------------------------------- * check if non official variant with additional seed parameter * is installed. if not use the official published resynthesizer 0.16 */ static gboolean p_pdb_call_resynthesizer(gint32 image_id, gint32 layer_id, gint32 corpus_layer_id, gint32 seed) { char *l_called_proc; GimpParam *return_vals; int nreturn_vals; gint nparams_resynth_s; gboolean foundResynthS; l_called_proc = PLUG_IN_RESYNTHESIZER_WITH_SEED; foundResynthS = gap_pdb_procedure_name_available(l_called_proc); if (foundResynthS) { return_vals = gimp_run_procedure (l_called_proc, &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, image_id, GIMP_PDB_DRAWABLE, layer_id, /* input drawable (to be processed) */ GIMP_PDB_INT32, 0, /* vtile Make tilable vertically */ GIMP_PDB_INT32, 0, /* htile Make tilable horizontally */ GIMP_PDB_INT32, 1, /* Dont change border pixels */ GIMP_PDB_INT32, corpus_layer_id, /* corpus, Layer to use as corpus */ GIMP_PDB_INT32, -1, /* inmask Layer to use as input mask, -1 for none */ GIMP_PDB_INT32, -1, /* outmask Layer to use as output mask, -1 for none */ GIMP_PDB_FLOAT, 0.0, /* map_weight Weight to give to map, if map is used */ GIMP_PDB_FLOAT, 0.117, /* autism Sensitivity to outliers */ GIMP_PDB_INT32, 16, /* neighbourhood Neighbourhood size */ GIMP_PDB_INT32, 500, /* trys Search thoroughness */ GIMP_PDB_INT32, seed, /* seed for random number generation */ GIMP_PDB_END); } else { gboolean foundResynth; l_called_proc = PLUG_IN_RESYNTHESIZER; foundResynth = gap_pdb_procedure_name_available(l_called_proc); if(!foundResynth) { printf("GAP: Error: PDB %s PDB plug-in is NOT installed\n" , l_called_proc ); return(FALSE); } return_vals = gimp_run_procedure (l_called_proc, &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, image_id, GIMP_PDB_DRAWABLE, layer_id, /* input drawable (to be processed) */ GIMP_PDB_INT32, 0, /* vtile Make tilable vertically */ GIMP_PDB_INT32, 0, /* htile Make tilable horizontally */ GIMP_PDB_INT32, 1, /* Dont change border pixels */ GIMP_PDB_INT32, corpus_layer_id, /* corpus, Layer to use as corpus */ GIMP_PDB_INT32, -1, /* inmask Layer to use as input mask, -1 for none */ GIMP_PDB_INT32, -1, /* outmask Layer to use as output mask, -1 for none */ GIMP_PDB_FLOAT, 0.0, /* map_weight Weight to give to map, if map is used */ GIMP_PDB_FLOAT, 0.117, /* autism Sensitivity to outliers */ GIMP_PDB_INT32, 16, /* neighbourhood Neighbourhood size */ GIMP_PDB_INT32, 500, /* trys Search thoroughness */ GIMP_PDB_END); } if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { gimp_destroy_params(return_vals, nreturn_vals); return (TRUE); } g_message(_("The call of plug-in %s\nfailed.\n" "probably the 3rd party plug-in resynthesizer is not installed or is not compatible to version:%s") , l_called_proc , "resynthesizer-0.16" ); gimp_destroy_params(return_vals, nreturn_vals); printf("GAP: Error: PDB call of %s failed (image_id:%d), d_status:%d\n" , l_called_proc , (int)image_id , (int)return_vals[0].data.d_status ); return(FALSE); } /* end p_pdb_call_resynthesizer */ /* -------------------------- * p_create_corpus_layer * -------------------------- * create the corpus layer that builds the reference pattern * for the resynthesizer call. The reference pattern is built * as duplicate of the original image reduced to the area around the current selection. * (grown by corpus_border_radius) * Note that the duplicate image has a selection, that includes the gorwn area * around the orignal selection, but EXCLUDES the original selection * (that is the area holding the object that has to be replaced * by pattern of the surrounding area) * returns the layer_id of the reference pattern. */ static gint32 p_create_corpus_layer(gint32 image_id, gint32 drawable_id, TransValues *val_ptr) { gint32 dup_image_id; gint32 channel_id; gint32 channel_2_id; GimpRGB bck_color; GimpRGB white_opaque_color; gboolean has_selection; gboolean non_empty; gint x1, y1, x2, y2; gint32 active_layer_stackposition; gint32 active_dup_layer_id; active_layer_stackposition = gap_layer_get_stackposition(image_id, drawable_id); dup_image_id = gimp_image_duplicate(image_id); channel_id = gimp_selection_save(dup_image_id); gimp_selection_grow(dup_image_id, val_ptr->corpus_border_radius); gimp_selection_invert(dup_image_id); gimp_context_get_background(&bck_color); channel_2_id = gimp_selection_save(dup_image_id); gimp_selection_load(channel_id); gimp_rgba_set_uchar (&white_opaque_color, 255, 255, 255, 255); gimp_context_set_background(&white_opaque_color); gimp_edit_clear(channel_2_id); gimp_context_set_background(&bck_color); /* restore original background color */ gimp_selection_load(channel_2_id); gimp_selection_invert(dup_image_id); has_selection = gimp_selection_bounds(dup_image_id, &non_empty, &x1, &y1, &x2, &y2); gimp_image_crop(dup_image_id, (x2 - x1), (y2 - y1), x1, y1); gimp_selection_invert(dup_image_id); active_dup_layer_id = gap_layer_get_id_by_stackposition(dup_image_id, active_layer_stackposition); if (1==0) { /* debug code shows the duplicate image by adding a display */ gimp_display_new(dup_image_id); } return (active_dup_layer_id); } /* end p_create_corpus_layer */ /* -------------------------- * p_set_alt_selection * -------------------------- * create selection as Grayscale copy of the specified alt_selection layer * - operates on a duplicate of the image references by alt_selection * - this duplicate is scaled to same size as specified image_id * * - if alt_selection refers to an image that has a selction * then use this selction instead of the layer itself. */ static gboolean p_set_alt_selection(gint32 image_id, gint32 drawable_id, TransValues *val_ptr) { if(gap_debug) { printf("p_set_alt_selection: drawable_id:%d alt_selection:%d\n" ,(int)drawable_id ,(int)val_ptr->alt_selection ); } if ((drawable_id == val_ptr->alt_selection) || (drawable_id < 0)) { return (FALSE); } return (gap_image_set_selection_from_selection_or_drawable(image_id, val_ptr->alt_selection, FALSE)); } /* -------------------------- * p_process_layer * -------------------------- */ static gint32 p_process_layer(gint32 image_id, gint32 drawable_id, TransValues *val_ptr) { gboolean has_selection; gboolean non_empty; gboolean alt_selection_success; gint x1, y1, x2, y2; gint32 trans_drawable_id; if(gap_debug) { printf("corpus_border_radius: %d\n", (int)val_ptr->corpus_border_radius); printf("alt_selection: %d\n", (int)val_ptr->alt_selection); printf("seed: %d\n", (int)val_ptr->seed); } gimp_image_undo_group_start(image_id); trans_drawable_id = -1; alt_selection_success = FALSE; if(val_ptr->alt_selection >= 0) { if(gap_debug) { printf("creating alt_selection: %d\n", (int)val_ptr->alt_selection); } alt_selection_success = p_set_alt_selection(image_id, drawable_id, val_ptr); } has_selection = gimp_selection_bounds(image_id, &non_empty, &x1, &y1, &x2, &y2); /* here the action starts, we create the corpus_layer_id that builds the reference pattern * (the corpus is created in a spearate image and has an expanded selection * that excludes the unwanted parts) * then start the resynthesizer plug-in to replace selcted (e.g. unwanted parts) of the * processed layer (e.g. drawable_id) */ if (non_empty) { gint32 corpus_layer_id; gint32 corpus_image_id; trans_drawable_id = drawable_id; corpus_layer_id = p_create_corpus_layer(image_id, drawable_id, val_ptr); p_pdb_call_resynthesizer(image_id, drawable_id, corpus_layer_id, val_ptr->seed); /* delete the temporary working duplicate */ corpus_image_id = gimp_drawable_get_image(corpus_layer_id); gimp_image_delete(corpus_image_id); } else { g_message("Please make a selection (cant operate on empty selection)"); } if(alt_selection_success) { gimp_selection_none(image_id); } gimp_image_undo_group_end(image_id); return (trans_drawable_id); } /* end p_process_layer */ gimp-gap-2.6.0+dfsg.orig/gap/gap_fmac_main.c0000644000175000017500000012374511212030253020435 0ustar thibautthibaut/* gap_fmac_main.c * 2003.11.08 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * - filtermacros * * the GIMP-GAP filtermacro implementation introduces * LIMITED macro features into GIMP-1.3.x * * WARNING: * filtermacros are a temporary solution, useful for animations * but do not expect support for filtermacros in future releases of GIMP-GAP * because GIMP may have real makro features in the future ... * * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* SYTEM (UNIX) includes */ #include #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" #include "libgimp/gimpui.h" /* GAP includes */ #include "config.h" #include "gap-intl.h" #include "gap_lib.h" #include "gap_val_file.h" #include "gap_filter.h" #include "gap_filter_pdb.h" #include "gap_fmac_name.h" #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 * gimp 1.3.22c; 2003/11/12 hof: button sensitivity * gimp 1.3.22b; 2003/11/09 hof: created (based on old unpublished patches for gimp-1.2) */ /* from gap_fmac_name.h: GAP_FMACNAME_PLUG_IN_NAME_FMAC */ #define HELP_ID_NAME_FMAC "plug-in-filter-macro" #define GAP_DB_BROWSER_FMAC_HELP_ID "gap-filtermacro-db-browser" #define FMAC_FILE_LENGTH 1500 /* ------------------------ * global gap DEBUG switch * ------------------------ */ /* int gap_debug = 1; */ /* print debug infos */ /* int gap_debug = 0; */ /* 0: dont print debug infos */ int gap_debug = 0; /* ############################################################# */ typedef struct { GtkWidget *dialog; GtkListStore *store; GtkWidget *tv; GtkTreeSelection *sel; gint selected_number; GtkWidget *file_entry; GtkWidget *filesel; GtkWidget *ok_button; GtkWidget *add_button; GtkWidget *delete_button; GtkWidget *delete_all_button; gchar filtermacro_file[FMAC_FILE_LENGTH]; gint32 image_id; gint32 drawable_id; gboolean run_flag; } fmac_globalparams_t; /* gpp */ gint gap_fmac_dialog(GimpRunMode run_mode, gint32 image_id, gint32 drawable_id); static gchar * p_get_filtername(const char *line); static void p_procedure_select_callback (GtkTreeSelection *sel, fmac_globalparams_t *gpp); static void p_tree_fill (fmac_globalparams_t *gpp); static void p_close_callback (GtkWidget *widget, fmac_globalparams_t *gpp); static void p_ok_callback (GtkWidget *widget, fmac_globalparams_t *gpp); static void p_help_callback (GtkWidget *widget, fmac_globalparams_t *gpp); static void p_add_callback (GtkWidget *widget, fmac_globalparams_t *gpp); static void p_delete_callback (GtkWidget *widget, fmac_globalparams_t *gpp); static void p_delete_all_callback (GtkWidget *widget, fmac_globalparams_t *gpp); static void p_filebrowser_button_callback (GtkWidget *widget, fmac_globalparams_t *gpp); static void p_filesel_ok_callback(GtkWidget *widget, fmac_globalparams_t *gpp); static void p_file_entry_update_callback(GtkWidget *widget, fmac_globalparams_t *gpp); static void p_filesel_close_callback(GtkWidget *widget, fmac_globalparams_t *gpp); static void p_create_action_area_buttons(fmac_globalparams_t *gpp); static void p_setbutton_sensitivity(fmac_globalparams_t *gpp); 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); static int p_fmac_pdb_constraint_proc_sel1(gchar *proc_name, gint32 image_id); static int p_fmac_pdb_constraint_proc_sel2(gchar *proc_name, gint32 image_id); /* ############################################################# */ static void query(void); static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; MAIN () static void query () { static gchar filtermacro_file[FMAC_FILE_LENGTH]; static GimpLastvalDef lastvals[] = { GIMP_LASTVALDEF_ARRAY (GIMP_ITER_FALSE, filtermacro_file, "filtermacro_scriptname"), GIMP_LASTVALDEF_GCHAR (GIMP_ITER_FALSE, filtermacro_file[0], "filtermacro_scriptname"), }; static GimpParamDef args_fmac_dialog[] = { {GIMP_PDB_INT32, "run_mode", "Interactive"}, {GIMP_PDB_IMAGE, "image", "Input image"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable to be affected by the filtermacro"}, {GIMP_PDB_STRING, "filtermacro_name", "Name of the filtermacro_file to execute on the input drawable)"}, }; static GimpParamDef *return_vals = NULL; static int nreturn_vals = 0; gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); /* registration for last values buffer structure (useful for animated filter apply) */ gimp_lastval_desc_register(GAP_FMACNAME_PLUG_IN_NAME_FMAC, &filtermacro_file[0], sizeof(filtermacro_file), G_N_ELEMENTS (lastvals), lastvals); gimp_install_procedure(GAP_FMACNAME_PLUG_IN_NAME_FMAC, "This plug-in can create and execute filtermacro scriptfiles", "This plug-in allows the user to pick one or more filters " "that have already been called before in the current Gimp session. " "The internal PDB-name of the picked filter is stored in a " "filtermacro scriptfile, along with the parameter buffer that was " "used at the last call.\n" "You can execute a filtermacro scriptfile on the Input drawable " "(in the current or in any further Gimp session). " "The non-interactive API is limited to filtermacro script execution " "and does not allow creation or modification of filtermacro scripts " "WARNING: filtermacro scriptfiles are a temporary solution. " "They are machine dependent. Support may be dropped in future gimp " "versions.", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Filtermacro..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, G_N_ELEMENTS (args_fmac_dialog), nreturn_vals, args_fmac_dialog, return_vals); gimp_plugin_menu_register (GAP_FMACNAME_PLUG_IN_NAME_FMAC, N_("/Filters/")); } /* end query */ static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals) { static GimpParam values[1]; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; gint32 image_id; gint32 drawable_id; char *filtermacro_file; gint32 l_rc; const char *l_env; *nreturn_vals = 1; *return_vals = values; l_rc = 0; l_env = g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } run_mode = param[0].data.d_int32; image_id = param[1].data.d_image; drawable_id = param[2].data.d_drawable; filtermacro_file = NULL; INIT_I18N (); if(gap_debug) fprintf(stderr, "\n\ngap_filter_main: debug name = %s\n", name); if (strcmp (name, GAP_FMACNAME_PLUG_IN_NAME_FMAC) == 0) { if (run_mode == GIMP_RUN_INTERACTIVE) { l_rc = gap_fmac_dialog(run_mode, image_id, drawable_id); } else { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if(n_params == 4) { filtermacro_file = param[3].data.d_string; if(filtermacro_file == NULL) { status = GIMP_PDB_CALLING_ERROR; } } else { status = GIMP_PDB_CALLING_ERROR; } } else { gint l_len; l_len = gimp_get_data_size(GAP_FMACNAME_PLUG_IN_NAME_FMAC); if(l_len > 0) { filtermacro_file = g_malloc0(l_len); gimp_get_data(GAP_FMACNAME_PLUG_IN_NAME_FMAC, filtermacro_file); } else { filtermacro_file = g_strdup("\0"); } } if(status == GIMP_PDB_SUCCESS) { l_rc = gap_fmac_execute(run_mode, image_id, drawable_id , filtermacro_file , NULL /* filtermacro_file2 */ , 1.0 /* current_step */ , 1 /* total_steps */ ); } } } else { status = GIMP_PDB_CALLING_ERROR; } if(l_rc < 0) { status = GIMP_PDB_EXECUTION_ERROR; } if (run_mode != GIMP_RUN_NONINTERACTIVE) gimp_displays_flush(); values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; } /* end run */ /* ---------------------- * p_chk_filtermacro_file * ---------------------- */ static gboolean p_chk_filtermacro_file(const char *filtermacro_file) { FILE *l_fp; char l_buf[400]; gboolean l_rc; l_buf[0] = '\0'; l_rc = FALSE; l_fp = g_fopen(filtermacro_file, "r"); if (l_fp) { /* file exists, check for header */ fgets(l_buf, sizeof(l_buf)-1, l_fp); if (strncmp(l_buf, "# FILTERMACRO FILE", strlen("# FILTERMACRO FILE")) == 0) { l_rc = TRUE; } fclose(l_fp); } return l_rc; } /* end p_chk_filtermacro_file */ /* -------------------- * p_print_and_free_msg * -------------------- */ static void p_print_and_free_msg(char *msg, GimpRunMode run_mode) { if(run_mode == GIMP_RUN_INTERACTIVE) { g_message(msg); } printf("%s\n", msg); g_free(msg); } /* end p_print_and_free_msg */ /* ---------------------------- * p_get_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 * * 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_gap_filter_data_string(const char *plugin_name) { gint plugin_data_len; int l_byte; gint l_idx; gchar *l_str; gchar *l_str_tmp; guchar *plugin_data; gchar *data_string; data_string = NULL; plugin_data = NULL; 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) { /* retrieve the data */ plugin_data = g_malloc0(plugin_data_len); gimp_get_data(plugin_name, plugin_data); /* build the textstring, starting with quoted plug_in name and decimal datalength field */ l_str_tmp = g_strdup_printf("\"%s\" %4d ", plugin_name, (int)plugin_data_len); /* add hex databytes */ for (l_idx = 0; l_idx < plugin_data_len; l_idx++) { l_byte = plugin_data[l_idx]; l_str = g_strdup_printf("%s %02x", l_str_tmp, l_byte); g_free(l_str_tmp); l_str_tmp = g_strdup(l_str); g_free(l_str); } /* add terminating newline character */ l_str = g_strdup_printf("%s\n", l_str_tmp); g_free(l_str_tmp); if (gap_debug) { printf("p_get_gap_filter_data_string: %s", l_str); } data_string = l_str; g_free(plugin_data); } return (data_string); } /* 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 * ------------------------- */ static gint p_fmac_add_filter_to_file(const char *filtermacro_file, const char *plugin_name) { FILE *fp; gint l_rc; l_rc = -1; if(gap_lib_file_exists(filtermacro_file) == 0 ) { /* file does not exist, or is empty */ fp = g_fopen(filtermacro_file, "w"); if(fp) { fprintf(fp, "# FILTERMACRO FILE (GIMP-GAP-1.3)\n"); fprintf(fp, "# lineformat: \n"); fprintf(fp, "# 1.st item plug-in PDB name in double quotes\n"); fprintf(fp, "# 2.nd item decimal length of lastvalue data plug-in PDB name in double quotes\n"); fprintf(fp, "# 3.rd until N items hex bytevalues of lastvalue data buffer\n"); fprintf(fp, "#\n"); } } else { fp = g_fopen(filtermacro_file, "a"); } if (fp) { char *data_string; char *canonical_plugin_name; canonical_plugin_name = gimp_canonicalize_identifier(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); l_rc = 0; /* OK */ g_free(data_string); } fclose(fp); } return (l_rc); } /* end p_fmac_add_filter_to_file */ /* ----------------- * p_fmac_add_filter * ----------------- * pick a filter via GAP-DB-Browser dialog and add its name * and its last_values buffer (parameter settings of last call in the * current GIMP-session) to the end of thefiltermacro_file */ static gint p_fmac_add_filter(const char *filtermacro_file, gint32 image_id) { GapDbBrowserResult l_browser_result; if(gap_db_browser_dialog( _("Select Filtercalls of Current GIMP Session") , NULL /* dont use the 1.st action button at all */ , _("Add Filter") , p_fmac_pdb_constraint_proc , p_fmac_pdb_constraint_proc_sel1 , p_fmac_pdb_constraint_proc_sel2 , &l_browser_result , image_id , GAP_DB_BROWSER_FMAC_HELP_ID ) < 0) { if(gap_debug) printf("DEBUG: gap_db_browser_dialog cancelled\n"); return -1; } return(p_fmac_add_filter_to_file(filtermacro_file, l_browser_result.selected_proc_name)); } /* end p_fmac_add_filter */ /* --------------- * gap_fmac_dialog * --------------- * create and perform the flitermacro dialog */ gint gap_fmac_dialog(GimpRunMode run_mode, gint32 image_id, gint32 drawable_id) { GtkWidget *table; GtkWidget *vbox; GtkWidget *label; GtkWidget *entry; GtkWidget *button; GtkWidget *scrolled_window; GtkCellRenderer *renderer; fmac_globalparams_t *gpp; gint row; gimp_ui_init ("gap-filter-macro", FALSE); gpp = g_new0 (fmac_globalparams_t, 1); gpp->run_flag = FALSE; gpp->filtermacro_file[0] = '\0'; gpp->selected_number = -1; /* probably get filtermacro_file (form a previous call in the same GIMP-session) */ gimp_get_data(GAP_FMACNAME_PLUG_IN_NAME_FMAC, gpp->filtermacro_file); gpp->filesel = NULL; gpp->image_id = image_id; gpp->drawable_id = drawable_id; /* the dialog box */ gpp->dialog = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (gpp->dialog), _("Filter Macro Script")); gtk_window_set_position (GTK_WINDOW (gpp->dialog), GTK_WIN_POS_MOUSE); g_signal_connect (gpp->dialog, "destroy", G_CALLBACK (p_close_callback), gpp); /* vbox : the list and the search entry */ vbox = gtk_vbox_new (FALSE, 4); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (gpp->dialog)->vbox), vbox, TRUE, TRUE, 0); gtk_widget_show (vbox); /* table */ table = gtk_table_new (1, 3, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_container_set_border_width (GTK_CONTAINER (table), 4); gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); gtk_widget_show (table); row = 0; /* label */ label = gtk_label_new(_("Filename:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, 0, 0, 0, 0); gtk_widget_show(label); /* entry */ entry = gtk_entry_new(); gpp->file_entry = entry; gtk_widget_set_size_request(entry, 300, -1); gtk_entry_set_text(GTK_ENTRY(entry), gpp->filtermacro_file); gtk_table_attach(GTK_TABLE(table), entry, 1, 2, row, row + 1, GTK_FILL | GTK_EXPAND, GTK_FILL, 4, 0); gimp_help_set_help_data(entry , _("Name of the filtermacro scriptfile") ,NULL); gtk_widget_show(entry); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK (p_file_entry_update_callback), gpp); /* Button to invoke filebrowser */ button = gtk_button_new_with_label ("..."); gimp_help_set_help_data(button , _("Open filebrowser window to select a filename") ,NULL); gtk_table_attach( GTK_TABLE(table), button, 2, 3, row, row +1, 0, 0, 0, 0 ); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (p_filebrowser_button_callback), gpp); /* list : list in a scrolled_win */ scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0); gtk_widget_show (scrolled_window); gpp->tv = gtk_tree_view_new (); renderer = gtk_cell_renderer_text_new (); gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (gpp->tv), -1, _("Nr"), renderer, "text", 1, NULL); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (gpp->tv), -1, _("PDB Name"), renderer, "text", 2, NULL); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (gpp->tv), -1, _("Menu Path"), renderer, "text", 3, NULL); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (gpp->tv), TRUE); gtk_widget_set_size_request (gpp->tv, 320 /*WIDTH*/, 100 /*HEIGHT*/); gtk_container_add (GTK_CONTAINER (scrolled_window), gpp->tv); gtk_widget_show (gpp->tv); gpp->sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (gpp->tv)); g_signal_connect (gpp->sel, "changed", G_CALLBACK (p_procedure_select_callback), gpp); /* buttons in action_aera */ p_create_action_area_buttons(gpp); gtk_widget_show (gpp->dialog); /* now build the list */ p_tree_fill (gpp); /* GTK Main Loop */ gtk_main (); gdk_flush (); if(gpp->filtermacro_file[0] != '\0') { gimp_set_data(GAP_FMACNAME_PLUG_IN_NAME_FMAC, gpp->filtermacro_file, FMAC_FILE_LENGTH); if(gpp->run_flag) { if(gap_debug) printf("gap_fmac_dialog: RUN image_id:%d drawable_id:%d, filtermacro_file:%s\n" ,(int)image_id ,(int)drawable_id ,gpp->filtermacro_file ); return(gap_fmac_execute(run_mode, image_id, drawable_id , gpp->filtermacro_file , NULL /* filtermacro_file2 */ , 1.0 /* current_step */ , 1 /* total_steps */ )); } } return 0; } /* end gap_fmac_dialog */ /* ---------------------------- * p_get_filtername * ---------------------------- * input is a typical filtermacro file line * if the line contains a filtername (starting with double quotes character) * the return a copy of the extracted filtername (without quotes) * else: return NULL */ static gchar * p_get_filtername(const char *line) { if(*line == '"') { gchar *filtername; gchar *ptr; filtername = g_strdup(&line[1]); ptr = filtername; while(ptr) { if((*ptr == '\n') || (*ptr == '\0') || (*ptr == '"')) { *ptr = '\0'; break; } ptr++; } return(filtername); } return NULL; } /* end p_get_filtername */ /* ---------------------------- * p_procedure_select_callback * ---------------------------- * fill filternames into the treeview */ static void p_procedure_select_callback (GtkTreeSelection *sel, fmac_globalparams_t *gpp) { GtkTreeIter iter; gchar *numtxt; g_return_if_fail (sel != NULL); g_return_if_fail (gpp != NULL); if (gtk_tree_selection_get_selected (sel, NULL, &iter)) { /* get column 0 (the invisible intenal number) from the store */ gtk_tree_model_get (GTK_TREE_MODEL (gpp->store), &iter ,0, &numtxt , -1); if (gap_debug) printf("p_procedure_select_callback (3) numtxt:%s\n", numtxt); gpp->selected_number = atoi(numtxt); g_free (numtxt); } } /* ---------------------------- * p_tree_fill * ---------------------------- * fill filternames into the treeview */ static void p_tree_fill (fmac_globalparams_t *gpp) { GtkTreeIter iter; gint count_elem; gboolean parse_file; GapValTextFileLines *txf_ptr; GapValTextFileLines *txf_ptr_root; gpp->store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); gtk_tree_view_set_model (GTK_TREE_VIEW (gpp->tv) ,GTK_TREE_MODEL (gpp->store) ); g_object_unref (gpp->store); /* read filternames from filtermacro_file * and add them to the treeview widget */ count_elem = 0; parse_file = FALSE; if(gpp->filtermacro_file[0] != '\0') { if(p_chk_filtermacro_file(gpp->filtermacro_file)) { parse_file = TRUE; } } if(parse_file) { txf_ptr_root = gap_val_load_textfile(gpp->filtermacro_file); for(txf_ptr = txf_ptr_root; txf_ptr != NULL; txf_ptr = (GapValTextFileLines *) txf_ptr->next) { gchar *pdb_name; pdb_name = p_get_filtername(txf_ptr->line); if(pdb_name) { gchar *numtxt; gchar *label; gchar *menu_path; menu_path = gap_db_get_plugin_menupath(pdb_name); if(menu_path == NULL) { menu_path = g_strdup(_("** No menu path available **")); } label = g_strdup_printf("%3d.", (int)count_elem +1); numtxt = g_strdup_printf("%d", (int)count_elem); gtk_list_store_append (gpp->store, &iter); gtk_list_store_set (gpp->store, &iter ,0, numtxt /* internal invisible number starting at 0 */ ,1, label /* visible number starting at 1 */ ,2, pdb_name ,3, menu_path ,-1); g_free (numtxt); g_free (label); g_free (menu_path); g_free (pdb_name); count_elem++; } } if(txf_ptr_root) { gap_val_free_textfile_lines(txf_ptr_root); } } if (count_elem == 0) { gtk_list_store_append (gpp->store, &iter); if((p_chk_filtermacro_file(gpp->filtermacro_file)) || (gap_lib_file_exists(gpp->filtermacro_file) == 0 )) { gtk_list_store_set (gpp->store, &iter ,0, "-1" ,1, " " ,2, _("** Empty **") ,3, " " ,-1); } else { gtk_list_store_set (gpp->store, &iter ,0, "-1" ,1, " " ,2, _("** File is not a filtermacro **") ,3, " " ,-1); } } gtk_tree_model_get_iter_first (GTK_TREE_MODEL (gpp->store), &iter); gtk_tree_selection_select_iter (gpp->sel, &iter); p_setbutton_sensitivity (gpp); } /* end p_tree_fill */ /* ---------------------------- * p_create_action_area_buttons * ---------------------------- * create action area buttons for the flitermacro dialog */ static void p_create_action_area_buttons(fmac_globalparams_t *gpp) { GtkWidget *button; GtkWidget *hbox; hbox = gtk_hbutton_box_new (); gtk_box_set_spacing (GTK_BOX (hbox), 2); gtk_box_pack_end (GTK_BOX (GTK_DIALOG (gpp->dialog)->action_area), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG(gpp->dialog)->action_area), 0); /* Button HELP */ if (gimp_show_help_button ()) { button = gtk_button_new_from_stock ( GTK_STOCK_HELP); gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); gimp_help_set_help_data(button ,_("Show help page") , NULL); g_signal_connect (G_OBJECT (button), "clicked" ,G_CALLBACK (p_help_callback) ,gpp ); gtk_widget_show (button); } /* Button Delete All */ button = gtk_button_new_with_label (_("Delete All")); gpp->delete_all_button = button; gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); gimp_help_set_help_data(button ,_("Delete the filtermacro scriptfile") , NULL); g_signal_connect (G_OBJECT (button), "clicked" ,G_CALLBACK (p_delete_all_callback) ,gpp ); gtk_widget_show (button); /* Button Delete */ button = gtk_button_new_with_label (_("Delete")); gpp->delete_button = button; gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); gimp_help_set_help_data(button ,_("Delete the selected filtercall") , NULL); g_signal_connect (G_OBJECT (button), "clicked" ,G_CALLBACK (p_delete_callback) ,gpp ); gtk_widget_show (button); /* Button Add */ button = gtk_button_new_with_label (_("Add")); gpp->add_button = button; gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); gimp_help_set_help_data(button ,_("Open PDB-browser window to add a new filter " "to the filtermacro scriptfile.\n" "Important:\n" "The PDB-browser shows only filters " "that have already been used in the current session " "and have setup the internal buffer with the " "parameter settings of the last call") , NULL); g_signal_connect (G_OBJECT (button), "clicked" ,G_CALLBACK (p_add_callback) ,gpp ); gtk_widget_show (button); /* Button Cancel */ button = gtk_button_new_from_stock ( GTK_STOCK_CANCEL); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); gimp_help_set_help_data(button ,_("Close window") , NULL); g_signal_connect (G_OBJECT (button), "clicked" ,G_CALLBACK (p_close_callback) ,gpp ); gtk_widget_show (button); /* Button OK */ button = gtk_button_new_from_stock ( GTK_STOCK_OK); gpp->ok_button = button; GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); gimp_help_set_help_data(button ,_("Apply filtermacro script on current drawable and close window") , NULL); g_signal_connect (G_OBJECT (button), "clicked" ,G_CALLBACK (p_ok_callback) ,gpp ); gtk_widget_show (button); p_setbutton_sensitivity(gpp); } /* end p_create_action_area_buttons */ /* ---------------------------- * p_setbutton_sensitivity * ---------------------------- */ static void p_setbutton_sensitivity(fmac_globalparams_t *gpp) { gboolean sensitive_1; gboolean sensitive_2; sensitive_1 = FALSE; sensitive_2 = FALSE; if((gpp->filtermacro_file[0] != '\0') && (gpp->filtermacro_file[0] != ' ')) { sensitive_2 = TRUE; if(p_chk_filtermacro_file(gpp->filtermacro_file)) { sensitive_1 = TRUE; } } gtk_widget_set_sensitive(gpp->ok_button, sensitive_1); gtk_widget_set_sensitive(gpp->delete_all_button, sensitive_1); gtk_widget_set_sensitive(gpp->delete_button, sensitive_1); gtk_widget_set_sensitive(gpp->add_button, sensitive_2); } /* end p_setbutton_sensitivity */ /* ---------------------------- * p_close_callback * ---------------------------- */ static void p_close_callback (GtkWidget *widget, fmac_globalparams_t *gpp) { GtkWidget *dlg; if(gpp) { dlg = gpp->dialog; gpp->dialog = NULL; if(dlg) { gtk_widget_destroy (GTK_WIDGET (dlg)); /* close & destroy dialog window */ gtk_main_quit (); } } else { gtk_main_quit (); } } /* ---------------------------- * p_ok_callback * ---------------------------- */ static void p_ok_callback (GtkWidget *widget, fmac_globalparams_t *gpp) { if(gpp) { gpp->run_flag = TRUE; } p_close_callback(NULL, gpp); } /* ---------------------------- * p_help_callback * ---------------------------- */ static void p_help_callback (GtkWidget *widget, fmac_globalparams_t *gpp) { if(gpp) { gimp_standard_help_func(HELP_ID_NAME_FMAC, gpp->dialog); } } /* ---------------------------- * p_delete_callback * ---------------------------- * delete the selected line in the filtermacro_file * the selcted_number counts only lines with filtercalls. * (comment lines are kept, but are not counted) * * negative values in gpp->selected_number represent the * "** Empty **" Label (if no valid filtermacro file is present) * this line can not be deleted. */ static void p_delete_callback (GtkWidget *widget, fmac_globalparams_t *gpp) { if(gpp) { if(gap_lib_file_exists(gpp->filtermacro_file) != 0 ) { if(gap_debug) printf("p_delete_callback: selected_number:%d\n", (int)gpp->selected_number); if(gpp->selected_number >= 0) { GapValTextFileLines *txf_ptr; GapValTextFileLines *txf_ptr_root; gint count_elem; gchar *label; FILE *fp; gboolean copy_line; /* rewrite the filtermacro file * without the line that corresponds to gpp->selected_number */ txf_ptr_root = gap_val_load_textfile(gpp->filtermacro_file); fp = g_fopen(gpp->filtermacro_file, "w"); if(fp) { count_elem = 0; for(txf_ptr = txf_ptr_root; txf_ptr != NULL; txf_ptr = (GapValTextFileLines *) txf_ptr->next) { copy_line = TRUE; label = p_get_filtername(txf_ptr->line); if(label) { if(count_elem == gpp->selected_number) { copy_line = FALSE; } g_free(label); count_elem++; } if(gap_debug) printf("%4d %s", (int)count_elem, txf_ptr->line); if(copy_line) { fprintf(fp, "%s", txf_ptr->line); } } fclose(fp); } if(txf_ptr_root) { gap_val_free_textfile_lines(txf_ptr_root); } } } p_tree_fill (gpp); } } /* ---------------------------- * p_delete_all_callback * ---------------------------- */ static void p_delete_all_callback (GtkWidget *widget, fmac_globalparams_t *gpp) { if(gpp) { if(p_chk_filtermacro_file(gpp->filtermacro_file)) { g_remove(gpp->filtermacro_file); } p_tree_fill (gpp); } } /* ---------------------------- * p_add_callback * ---------------------------- */ static void p_add_callback (GtkWidget *widget, fmac_globalparams_t *gpp) { if(gpp) { if(gpp->filtermacro_file[0] != '\0') { gint l_rc; errno = 0; l_rc = p_fmac_add_filter(gpp->filtermacro_file, gpp->image_id); if((l_rc < 0) && (errno != 0)) { g_message(_("ERROR: Could not write filtermacro script\n" "filename: '%s'\n%s") ,gpp->filtermacro_file, g_strerror (errno)); } } p_tree_fill (gpp); } } /* ----------------------------- * p_filebrowser_button_callback * ----------------------------- */ static void p_filebrowser_button_callback (GtkWidget *widget, fmac_globalparams_t *gpp) { GtkWidget *filesel; if(gpp->filesel != NULL) { gtk_window_present(GTK_WINDOW(gpp->filesel)); return; /* filesel is already open */ } filesel = gtk_file_selection_new ( _("Select Filtermacro Scriptfile")); gpp->filesel = filesel; gtk_window_set_position (GTK_WINDOW (filesel), GTK_WIN_POS_MOUSE); g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button), "clicked", G_CALLBACK (p_filesel_ok_callback), gpp); g_signal_connect(G_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button), "clicked", G_CALLBACK (p_filesel_close_callback), gpp); gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), gpp->filtermacro_file); gtk_widget_show (filesel); /* "destroy" has to be the last signal, * (otherwise the other callbacks are never called) */ g_signal_connect (G_OBJECT (filesel), "destroy", G_CALLBACK (p_filesel_close_callback), gpp); } /* ---------------------------- * p_filesel_close_callback * ---------------------------- */ static void p_filesel_close_callback(GtkWidget *widget, fmac_globalparams_t *gpp) { GtkWidget *filesel; if(gpp == NULL) return; filesel = gpp->filesel; if(filesel == NULL) return; gpp->filesel = NULL; /* now filesel is closed */ gtk_widget_destroy(GTK_WIDGET(filesel)); } /* ---------------------------- * p_filesel_ok_callback * ---------------------------- */ static void p_filesel_ok_callback(GtkWidget *widget, fmac_globalparams_t *gpp) { const gchar *filename; if(gpp == NULL) return; filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (gpp->filesel)); g_snprintf(&gpp->filtermacro_file[0], sizeof(gpp->filtermacro_file), "%s", filename); gtk_entry_set_text(GTK_ENTRY(gpp->file_entry), filename); if (gap_debug) printf("p_filesel_ok_callback: %s\n", gpp->filtermacro_file); p_filesel_close_callback(gpp->filesel, gpp); } /* ---------------------------- * p_file_entry_update_callback * ---------------------------- */ static void p_file_entry_update_callback(GtkWidget *widget, fmac_globalparams_t *gpp) { if(gpp) { g_snprintf(gpp->filtermacro_file, sizeof(gpp->filtermacro_file), "%s" , gtk_entry_get_text(GTK_ENTRY(widget)) ); p_tree_fill (gpp); } } /* --------------------------------- * p_fmac_pdb_constraint_proc_sel1 * --------------------------------- */ static int p_fmac_pdb_constraint_proc(gchar *proc_name, gint32 image_id) { int l_rc; if(strncmp(proc_name, "file", 4) == 0) { /* Do not add file Plugins (check if name starts with "file") */ return 0; } if(strncmp(proc_name, "plug_in_gap_", 12) == 0) { /* Do not add GAP Plugins (check if name starts with "plug_in_gap_") */ return 0; } if(strcmp(proc_name, GAP_FMACNAME_PLUG_IN_NAME_FMAC) == 0) { /* Do not add the filtermacro plugin itself */ return 0; } l_rc = gap_filt_pdb_procedure_available(proc_name, GAP_PTYP_CAN_OPERATE_ON_DRAWABLE); if(l_rc < 0) { /* Do not add, Plug-in not available or wrong type */ return 0; } return(p_fmac_pdb_constraint_proc_sel1(proc_name, image_id)); } /* --------------------------------- * p_fmac_pdb_constraint_proc_sel1 * --------------------------------- */ static int p_fmac_pdb_constraint_proc_sel1(gchar *proc_name, gint32 image_id) { char *data_string; data_string = p_get_gap_filter_data_string(proc_name); if(data_string) { g_free(data_string); return 1; /* 1 .. set "Add Filter" Button sensitive */ } return 0; /* 0 .. set "Add Filter" Button insensitive */ } /* --------------------------------- * p_fmac_pdb_constraint_proc_sel2 * --------------------------------- */ static int p_fmac_pdb_constraint_proc_sel2(gchar *proc_name, gint32 image_id) { return (p_fmac_pdb_constraint_proc_sel1 (proc_name, image_id)); } gimp-gap-2.6.0+dfsg.orig/gap/gap_timeconv.h0000644000175000017500000000301711212030253020341 0ustar thibautthibaut/* gap_timeconv.h * * This module handles conversions framenumber/Rate --> timestring (mm:ss:msec) */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.19a; 2003/09/06 hof: added more converter procedures for audio * version 1.3.14c; 2003/06/14 hof: created */ #ifndef _GAP_TIMECONV_H #define _GAP_TIMECONV_H #include "libgimp/gimp.h" void gap_timeconv_msecs_to_timestr(gint32 tmsec, gchar *txt, gint txt_size); void gap_timeconv_framenr_to_timestr( gint32 framenr, gdouble framerate, gchar *txt, gint txt_size); void gap_timeconv_samples_to_timestr( gint32 samples, gdouble samplerate, gchar *txt, gint txt_size); gdouble gap_timeconv_samples_to_frames( gint32 samples, gdouble samplerate, gdouble framerate); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap-intl.h0000644000175000017500000000124711212030253017404 0ustar thibautthibaut#ifndef __GAP_INTL_H__ #define __GAP_INTL_H__ #ifndef GETTEXT_PACKAGE #error "config.h must be included prior to gap-intl.h" #endif #include #define _(String) gettext (String) #ifdef gettext_noop # define N_(String) gettext_noop (String) #else # define N_(String) (String) #endif #ifndef HAVE_BIND_TEXTDOMAIN_CODESET # define bind_textdomain_codeset(Domain, Codeset) (Domain) #endif #define INIT_I18N() G_STMT_START{ \ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); \ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); \ textdomain (GETTEXT_PACKAGE); \ }G_STMT_END #endif /* __GAP_INTL_H__ */ gimp-gap-2.6.0+dfsg.orig/gap/gap_morph_main.h0000644000175000017500000001073711212030253020655 0ustar thibautthibaut/* gap_morph_main.h * * creation of morphing animations (transform source image into des. image) by Wolfgang Hofer * 2004/02/11 */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.15a; 2004/02/12 hof: created */ #ifndef _GAP_MORPH_MAIN_H #define _GAP_MORPH_MAIN_H #include "libgimp/gimp.h" #include "gap_lib.h" #include #include #include #include "gap_pview_da.h" /* render_mode Radio Buttons */ #define GAP_MORPH_RENDER_MODE_MORPH 0 #define GAP_MORPH_RENDER_MODE_WARP 1 #define GAP_MORPH_WORKPOINT_FILENAME_MAX_LENGTH 1024 typedef struct GapMorphWorkPoint { /* nickname: wp */ gdouble fdst_x; /* final dest koord (as set by user for last dest. frame) */ gdouble fdst_y; gdouble osrc_x; /* start source koord (as set by user for the 1.st frame) */ gdouble osrc_y; gdouble dst_x; /* koord trans */ gdouble dst_y; gdouble src_x; /* osrc_x scaled to koords of current (dest) frame */ gdouble src_y; void *next; /* for calculations per pixel */ gdouble warp_weight; gdouble gravity; gdouble sqr_dist; gdouble dist; gdouble inv_dist; /* 1 / sqr_distance */ gdouble angle_deg; gint xy_relation; gint sek_idx; gboolean is_alive; void *next_selected; void *next_sek; } GapMorphWorkPoint; typedef struct GapMorphGlobalParams { /* nickname: mgpp */ GimpRunMode run_mode; gint32 image_id; gint32 tween_steps; gint32 fdst_layer_id; gint32 osrc_layer_id; GapMorphWorkPoint *master_wp_list; char workpoint_file_lower[GAP_MORPH_WORKPOINT_FILENAME_MAX_LENGTH]; char workpoint_file_upper[GAP_MORPH_WORKPOINT_FILENAME_MAX_LENGTH]; gboolean create_tween_layers; /* FALSE: operate on existing layers only */ gboolean have_workpointsets; /* FALSE: use the default workpointset master_wp_list * TRUE: use lower_wp_list and upper_wp_list * foreach handled frame the * lower and upper list are fetched from * best matching workpointfile. * (using the numberpart of the filename) */ gboolean use_quality_wp_selection; gboolean use_gravity; gdouble gravity_intensity; /* 1.0 upto 5 (gravity power) */ gdouble affect_radius; /* distortion pixelradius (0 == no gravity) */ gint32 render_mode; gboolean do_progress; gdouble master_progress; gdouble layer_progress_step; gdouble tween_mix_factor; /* 0.0 upto 1.0 wher 0.0 gives source layer 1.0 dest layer as resut */ gint32 range_from; gint32 range_to; gboolean overwrite_flag; gboolean do_simple_fade; /* bypass morph algortihm when renderiing tweens and use simple fade instead */ } GapMorphGlobalParams; typedef struct GapMorphWarpCoreAPI { /* nickname: wcap */ GapMorphWorkPoint *wp_list; gboolean use_quality_wp_selection; gboolean use_gravity; gdouble gravity_intensity; gdouble affect_radius; /* distortion pixelradius (0 == no gravity) */ gdouble sqr_affect_radius; gdouble scale_x; gdouble scale_y; gboolean printf_flag; } GapMorphWarpCoreAPI; #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_story_att_trans_dlg.c0000644000175000017500000027564711212030253022621 0ustar thibautthibaut/* gap_story_att_trans_dlg.c * * This module handles GAP storyboard dialog transition attribute properties window */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 2.3.0-238; 2006/06/18 hof: support overlapping frames within a video track * version 2.2.1-214; 2006/03/31 hof: created */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "gap_story_main.h" #include "gap_story_undo.h" #include "gap_story_dialog.h" #include "gap_story_file.h" #include "gap_story_att_trans_dlg.h" #include "gap_pview_da.h" #include "gap_stock.h" #include "gap_lib.h" #include "gap_vin.h" #include "gap_timeconv.h" #include "gap_layer_copy.h" #include "gap-intl.h" #define ATTW_COMMENT_WIDTH 480 #define CONVERT_TO_100PERCENT 100.0 #define GAP_STORY_ATTR_PROP_HELP_ID "plug-in-gap-storyboard-attr-prop" #define GAP_STORY_ATT_RESPONSE_RESET 1 #define GAP_STORY_ATT_RESPONSE_PLAYBACK 2 #define PVIEW_SIZE 256 #define LAYERNAME_ORIG "orig_layer" #define LAYERNAME_OPRE "opre_layer" #define LAYERNAME_DECO "deco_layer" #define LAYERNAME_CURR "curr_layer" #define LAYERNAME_PREF "pref_layer" #define LAYERNAME_BASE "base_layer" #define LAYERSTACK_TOP -1 #define LAYERSTACK_CURR 2 #define LAYERSTACK_PREF 1 #define LAYERSTACK_BASE 0 #define OBJ_DATA_KEY_ATTW "attw" #define OBJ_DATA_KEY_IMG_IDX "img_idx" #define PVIEW_TO_MASTER_SCALE 0.5 extern int gap_debug; /* 1 == print debug infos , 0 dont print debug infos */ static void p_attw_prop_response(GtkWidget *widget , gint response_id , GapStbAttrWidget *attw ); static void p_attw_push_undo_and_set_unsaved_changes(GapStbAttrWidget *attw); static void p_attw_prop_reset_all(GapStbAttrWidget *attw); static void p_playback_effect_range(GapStbAttrWidget *attw); static void p_attw_timer_job(GapStbAttrWidget *attw); static void p_attw_update_properties(GapStbAttrWidget *attw); static void p_attw_update_sensitivity(GapStbAttrWidget *attw); static gdouble p_get_default_attribute(GapStbAttrWidget *attw , GdkEventButton *bevent , gint att_type_idx , gboolean form_value); static void p_attw_start_button_clicked_callback(GtkWidget *widget , GdkEventButton *bevent , gint att_type_idx); static void p_attw_end_button_clicked_callback(GtkWidget *widget , GdkEventButton *bevent , gint att_type_idx); static void p_copy_duration_to_all(gint32 duration, GapStbAttrWidget *attw); static void p_attw_overlap_dur_button_clicked_callback(GtkWidget *widget , GdkEventButton *bevent , GapStbAttrWidget *attw); static void p_attw_dur_button_clicked_callback(GtkWidget *widget , GdkEventButton *bevent , gint att_type_idx); static void p_attw_gdouble_adjustment_callback(GtkObject *obj, gdouble *val); static void p_duration_dependent_refresh(GapStbAttrWidget *attw); static void p_attw_duration_adjustment_callback(GtkObject *obj, gint32 *val); static void p_attw_enable_toggle_update_callback(GtkWidget *widget, gboolean *val); static void p_attw_auto_update_toggle_update_callback(GtkWidget *widget, gboolean *val); static gboolean p_attw_preview_events_cb (GtkWidget *widget , GdkEvent *event , GapStbAttrWidget *attw); static void p_calculate_prefetch_render_attributes(GapStbAttrWidget *attw , gint img_idx , GapStoryCalcAttr *calc_attr_ptr ); static void p_calculate_render_attributes(GapStbAttrWidget *attw , gint img_idx , GapStoryCalcAttr *calc_attr ); static void p_check_and_make_opre_default_layer(GapStbAttrWidget *attw, gint img_idx); static void p_check_and_make_orig_default_layer(GapStbAttrWidget *attw, gint img_idx); static gint32 p_create_color_layer(GapStbAttrWidget *attw, gint32 image_id , const char *name, gint stackposition, gdouble opacity , gdouble red, gdouble green, gdouble blue); static gint32 p_create_base_layer(GapStbAttrWidget *attw, gint32 image_id); static gint32 p_create_deco_layer(GapStbAttrWidget *attw, gint32 image_id); static void p_create_gfx_image(GapStbAttrWidget *attw, gint img_idx); static void p_delete_gfx_images(GapStbAttrWidget *attw); static void p_adjust_stackposition(gint32 image_id, gint32 layer_id, gint position); static void p_create_transformed_layer(gint32 image_id , gint32 origsize_layer_id , gint32 *layer_id_ptr , GapStoryCalcAttr *calculated , gint32 stackposition, const char *layername); static gboolean p_calculate_prefetch_visibility(GapStbAttrWidget *attw, gint img_idx); static void p_render_gfx(GapStbAttrWidget *attw, gint img_idx); static void p_update_framenr_labels(GapStbAttrWidget *attw, gint img_idx, gint32 framenr); static gint32 p_get_relevant_duration(GapStbAttrWidget *attw, gint img_idx); static void p_update_full_preview_gfx(GapStbAttrWidget *attw); static gboolean p_stb_req_equals_layer_info(GapStbAttrLayerInfo *linfo , GapStoryLocateRet *stb_ret , const char *filename); static void p_destroy_orig_layer( gint32 image_id , gint32 *orig_layer_id_ptr , gint32 *derived_layer_id_ptr , GapStbAttrLayerInfo *linfo); static gboolean p_check_orig_layer_up_to_date(gint32 image_id , gint32 *orig_layer_id_ptr , gint32 *derived_layer_id_ptr , GapStbAttrLayerInfo *linfo , GapStoryLocateRet *stb_ret , const char *filename); static void p_orig_layer_frame_fetcher(GapStbAttrWidget *attw , gint32 master_framenr , gint32 image_id , gint32 *orig_layer_id_ptr , gint32 *derived_layer_id_ptr , GapStbAttrLayerInfo *linfo); static gint32 p_calc_and_set_display_framenr(GapStbAttrWidget *attw , gint img_idx , gint32 duration); static void p_create_or_replace_orig_and_opre_layer (GapStbAttrWidget *attw , gint img_idx , gint32 duration); static gint32 p_fetch_video_frame_as_layer(GapStbMainGlobalParams *sgpp , const char *video_filename , gint32 framenumber , gint32 seltrack , const char *preferred_decoder , gint32 image_id ); static gint32 p_fetch_imagefile_as_layer (const char *img_filename , gint32 image_id ); static void p_attw_comment_entry_update_cb(GtkWidget *widget, GapStbAttrWidget *attw); static void p_init_layer_info(GapStbAttrLayerInfo *linfo); static void p_create_and_attach_pv_widgets(GapStbAttrWidget *attw , GtkWidget *table , gint row , gint col_start , gint col_end , gint img_idx ); static void p_create_and_attach_att_arr_widgets(const char *row_title , GapStbAttrWidget *attw , GtkWidget *table , gint row , gint column , gint att_type_idx , gdouble lower_constraint , gdouble upper_constraint , gdouble step_increment , gdouble page_increment , gdouble page_size , gint digits , const char *enable_tooltip , gboolean *att_arr_enable_ptr , const char *from_tooltip , gdouble *att_arr_value_from_ptr , const char *to_tooltip , gdouble *att_arr_value_to_ptr , const char *dur_tooltip , gint32 *att_arr_value_dur_ptr ); /* --------------------------------- * p_attw_prop_response * --------------------------------- */ static void p_attw_prop_response(GtkWidget *widget , gint response_id , GapStbAttrWidget *attw ) { GtkWidget *dlg; GapStbMainGlobalParams *sgpp; sgpp = attw->sgpp; switch (response_id) { case GAP_STORY_ATT_RESPONSE_RESET: if((attw->stb_elem_bck) && (attw->stb_elem_refptr)) { p_attw_prop_reset_all(attw); } break; case GAP_STORY_ATT_RESPONSE_PLAYBACK: p_playback_effect_range(attw); break; case GTK_RESPONSE_CLOSE: default: dlg = attw->attw_prop_dialog; if(dlg) { p_delete_gfx_images(attw); if(attw->go_timertag >= 0) { g_source_remove(attw->go_timertag); } attw->go_timertag = -1; attw->attw_prop_dialog = NULL; attw->stb_elem_refptr = NULL; attw->stb_refptr = NULL; gtk_widget_destroy(dlg); } break; } } /* end p_attw_prop_response */ /* -------------------------------------- * p_attw_push_undo_and_set_unsaved_changes * -------------------------------------- * this procedure is called in most cases when * a transition attribute property has changed. * (note that the Undo push implementation filter out * multiple attribute property changes on the same object in sequence) */ static void p_attw_push_undo_and_set_unsaved_changes(GapStbAttrWidget *attw) { if(attw != NULL) { if((attw->stb_elem_refptr != NULL) && (attw->stb_refptr != NULL)) { gap_stb_undo_push_clip(attw->tabw , GAP_STB_FEATURE_PROPERTIES_TRANSITION , attw->stb_elem_refptr->story_id ); attw->stb_refptr->unsaved_changes = TRUE; if(attw->stb_refptr->active_section != NULL) { attw->stb_refptr->active_section->version++; } } } } /* end p_attw_push_undo_and_set_unsaved_changes */ /* --------------------------------- * p_attw_prop_reset_all * --------------------------------- */ static void p_attw_prop_reset_all(GapStbAttrWidget *attw) { gboolean comment_set; gint ii; if(attw) { if(attw->stb_elem_refptr) { p_attw_push_undo_and_set_unsaved_changes(attw); gap_story_elem_copy(attw->stb_elem_refptr, attw->stb_elem_bck); comment_set = FALSE; if(attw->stb_elem_refptr->comment) { if(attw->stb_elem_refptr->comment->orig_src_line) { gtk_entry_set_text(GTK_ENTRY(attw->comment_entry), attw->stb_elem_refptr->comment->orig_src_line); comment_set = TRUE; } } if(!comment_set) { gtk_entry_set_text(GTK_ENTRY(attw->comment_entry), ""); } for(ii=0; ii < GAP_STB_ATT_TYPES_ARRAY_MAX; ii++) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (attw->att_rows[ii].enable_toggle) , attw->stb_elem_refptr->att_arr_enable[ii]); gtk_adjustment_set_value(GTK_ADJUSTMENT(attw->att_rows[ii].spinbutton_from_adj) , attw->stb_elem_refptr->att_arr_value_from[ii] * CONVERT_TO_100PERCENT); gtk_adjustment_set_value(GTK_ADJUSTMENT(attw->att_rows[ii].spinbutton_to_adj) , attw->stb_elem_refptr->att_arr_value_to[ii] * CONVERT_TO_100PERCENT); gtk_adjustment_set_value(GTK_ADJUSTMENT(attw->att_rows[ii].spinbutton_dur_adj) , attw->stb_elem_refptr->att_arr_value_dur[ii]); } gtk_adjustment_set_value(GTK_ADJUSTMENT(attw->spinbutton_overlap_dur_adj) , attw->stb_elem_refptr->att_overlap); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (attw->fit_width_toggle) , attw->stb_elem_refptr->att_fit_width); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (attw->fit_height_toggle) , attw->stb_elem_refptr->att_fit_height); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (attw->keep_proportions_toggle) , attw->stb_elem_refptr->att_keep_proportions); attw->timer_full_update_request = TRUE; p_attw_update_properties(attw); } } } /* end p_attw_prop_reset_all */ /* ------------------------------ * p_playback_effect_range * ------------------------------ */ static void p_playback_effect_range(GapStbAttrWidget *attw) { gint32 begin_frame; gint32 end_frame; begin_frame = p_calc_and_set_display_framenr(attw, 0, 0); end_frame = begin_frame + p_get_relevant_duration(attw, 1); gap_story_attw_range_playback(attw, begin_frame, end_frame); } /* end p_playback_effect_range */ /* ------------------ * p_attw_timer_job * ------------------ * render both graphical previews * or do full update if timer_full_update_request flag is set. * (also reset this flag) */ static void p_attw_timer_job(GapStbAttrWidget *attw) { GapStbMainGlobalParams *sgpp; if(gap_debug) { printf("\np_attw_timer_job: START\n"); } sgpp = attw->sgpp; if((attw) && (sgpp)) { if(attw->go_timertag >= 0) { g_source_remove(attw->go_timertag); } attw->go_timertag = -1; if(attw->timer_full_update_request) { attw->timer_full_update_request = FALSE; p_update_full_preview_gfx(attw); /* it would be sufficient to update the labels * of all clips displayed in the storyboard, * but we simply render everything * (the code is already complex enough) */ gap_story_dlg_attw_render_all(attw); } else { p_render_gfx(attw, 0); p_render_gfx(attw, 1); } } } /* end p_attw_timer_job */ /* ------------------------------------ * p_attw_update_properties * ------------------------------------ * render graphical view respecting all enabled attributes * opacity, move X/Y and Zoom X/Y */ static void p_attw_update_properties(GapStbAttrWidget *attw) { gap_story_dlg_tabw_update_frame_label(attw->tabw, attw->sgpp); if(attw->go_timertag < 0) { gint32 delay_millisec; delay_millisec = 100; attw->go_timertag = (gint32) g_timeout_add(delay_millisec , (GtkFunction)p_attw_timer_job , attw ); } } /* end p_attw_update_properties */ /* ------------------------------------ * p_attw_update_sensitivity * ------------------------------------ * set sensitivity of all 5 from/to, dur attribute widgets * according to their enable flag. */ static void p_attw_update_sensitivity(GapStbAttrWidget *attw) { gint ii; gboolean sensitive; if(attw == NULL) { return; } if(attw->stb_elem_refptr == NULL) { return; } for(ii=0; ii < GAP_STB_ATT_TYPES_ARRAY_MAX; ii++) { sensitive = attw->stb_elem_refptr->att_arr_enable[ii]; gtk_widget_set_sensitive(attw->att_rows[ii].spinbutton_from, sensitive); gtk_widget_set_sensitive(attw->att_rows[ii].spinbutton_to, sensitive); gtk_widget_set_sensitive(attw->att_rows[ii].spinbutton_dur, sensitive); gtk_widget_set_sensitive(attw->att_rows[ii].button_from, sensitive); gtk_widget_set_sensitive(attw->att_rows[ii].button_to, sensitive); gtk_widget_set_sensitive(attw->att_rows[ii].button_dur, sensitive); } sensitive = ((attw->stb_elem_refptr->att_fit_width == TRUE) || (attw->stb_elem_refptr->att_fit_height == TRUE)); gtk_widget_set_sensitive(attw->keep_proportions_toggle, sensitive); } /* end p_attw_update_sensitivity */ /* -------------------------------- * p_get_default_attribute * -------------------------------- * get the typical default value depending * on the attribute type (specified via att_type_idx) * and depending on MODIFIER Keys held down when button was clicked * (specified via bevent) * * SHIFT: reset to start value (at dialog creation time) * CTRL: left/top outside, Half size, 50% opaque * ALT: right/bot outside, Double size, 75% opaque */ static gdouble p_get_default_attribute(GapStbAttrWidget *attw , GdkEventButton *bevent , gint att_type_idx , gboolean form_value) { if(bevent) { if (bevent->state & GDK_CONTROL_MASK) { if ((att_type_idx == GAP_STB_ATT_TYPE_MOVE_X) || (att_type_idx == GAP_STB_ATT_TYPE_MOVE_Y)) { return (-1.0); /* -1.0 indicates left/top outside */ } if ((att_type_idx == GAP_STB_ATT_TYPE_ZOOM_X) || (att_type_idx == GAP_STB_ATT_TYPE_ZOOM_Y)) { return (0.5); /* 1.0 scale to half size */ } return (0.5); /* indicates 50% opacity */ } if(bevent->state & GDK_MOD1_MASK) /* ALT */ { if ((att_type_idx == GAP_STB_ATT_TYPE_MOVE_X) || (att_type_idx == GAP_STB_ATT_TYPE_MOVE_Y)) { return (1.0); /* 1.0 indicates right/bottom outside */ } if ((att_type_idx == GAP_STB_ATT_TYPE_ZOOM_X) || (att_type_idx == GAP_STB_ATT_TYPE_ZOOM_Y)) { return (2.0); /* 1.0 scale to doble size */ } return (0.75); /* indicates 75% opacity */ } if(bevent->state & GDK_SHIFT_MASK) { if(attw->stb_elem_bck) { if(form_value) { return (attw->stb_elem_bck->att_arr_value_from[att_type_idx]); } return(attw->stb_elem_bck->att_arr_value_to[att_type_idx]); } } } return (gap_story_get_default_attribute(att_type_idx)); } /* end p_get_default_attribute */ /* ----------------------------------------- * p_attw_start_button_clicked_callback * ----------------------------------------- */ static void p_attw_start_button_clicked_callback(GtkWidget *widget , GdkEventButton *bevent , gint att_type_idx) { GapStbAttrWidget *attw; attw = g_object_get_data( G_OBJECT(widget), OBJ_DATA_KEY_ATTW ); if(attw) { if(attw->stb_elem_refptr) { gdouble attr_value; p_attw_push_undo_and_set_unsaved_changes(attw); attr_value = CONVERT_TO_100PERCENT * p_get_default_attribute(attw , bevent , att_type_idx , TRUE /* use from value for reset */ ); gtk_adjustment_set_value(GTK_ADJUSTMENT(attw->att_rows[att_type_idx].spinbutton_from_adj) , attr_value); } } } /* end p_attw_start_button_clicked_callback */ /* ----------------------------------------- * p_attw_end_button_clicked_callback * ----------------------------------------- */ static void p_attw_end_button_clicked_callback(GtkWidget *widget , GdkEventButton *bevent , gint att_type_idx) { GapStbAttrWidget *attw; attw = g_object_get_data( G_OBJECT(widget), OBJ_DATA_KEY_ATTW ); if(attw) { if(attw->stb_elem_refptr) { gdouble attr_value; p_attw_push_undo_and_set_unsaved_changes(attw); attr_value = CONVERT_TO_100PERCENT * p_get_default_attribute(attw , bevent , att_type_idx , FALSE /* use to value for reset */ ); gtk_adjustment_set_value(GTK_ADJUSTMENT(attw->att_rows[att_type_idx].spinbutton_to_adj) , attr_value); } } } /* end p_attw_end_button_clicked_callback */ /* ----------------------------------------- * p_copy_duration_to_all * ----------------------------------------- * copy to all duration attributes (except overlap) */ static void p_copy_duration_to_all(gint32 duration, GapStbAttrWidget *attw) { if(attw) { gint ii; p_attw_push_undo_and_set_unsaved_changes(attw); for(ii = 0; ii < GAP_STB_ATT_TYPES_ARRAY_MAX; ii++) { if(attw->stb_elem_refptr->att_arr_enable[ii] == TRUE) { gtk_adjustment_set_value(GTK_ADJUSTMENT(attw->att_rows[ii].spinbutton_dur_adj) , duration); } } } } /* end p_copy_duration_to_all */ /* ----------------------------------------- * p_attw_overlap_dur_button_clicked_callback * ----------------------------------------- */ static void p_attw_overlap_dur_button_clicked_callback(GtkWidget *widget , GdkEventButton *bevent , GapStbAttrWidget *attw) { if(attw) { if(attw->stb_elem_refptr) { gint32 duration; p_attw_push_undo_and_set_unsaved_changes(attw); duration = attw->stb_elem_refptr->att_overlap; p_copy_duration_to_all(duration, attw); } } } /* end p_attw_overlap_dur_button_clicked_callback */ /* ----------------------------------------- * p_attw_dur_button_clicked_callback * ----------------------------------------- */ static void p_attw_dur_button_clicked_callback(GtkWidget *widget , GdkEventButton *bevent , gint att_type_idx) { GapStbAttrWidget *attw; attw = g_object_get_data( G_OBJECT(widget), OBJ_DATA_KEY_ATTW ); if(attw) { if(attw->stb_elem_refptr) { gint32 duration; p_attw_push_undo_and_set_unsaved_changes(attw); duration = attw->stb_elem_refptr->att_arr_value_dur[att_type_idx]; p_copy_duration_to_all(duration, attw); } } } /* end p_attw_dur_button_clicked_callback */ /* ---------------------------------- * p_attw_gdouble_adjustment_callback * ---------------------------------- * * Notes: the value we get from the spinbutton is divided by 100 * because the GUI presents 100 percent as 100.0 * but internal representation uses the value 1.0 * for 100 percent. */ static void p_attw_gdouble_adjustment_callback(GtkObject *obj, gdouble *val) { GapStbAttrWidget *attw; gdouble l_val; attw = g_object_get_data( G_OBJECT(obj), OBJ_DATA_KEY_ATTW ); if(attw) { if(attw->stb_elem_refptr) { l_val = (GTK_ADJUSTMENT(obj)->value) / CONVERT_TO_100PERCENT; if(gap_debug) { printf("gdouble_adjustment_callback: old_val:%f val:%f\n" , (float)*val , (float)l_val ); } if(l_val != *val) { p_attw_push_undo_and_set_unsaved_changes(attw); *val = l_val; p_attw_update_properties(attw); } } } } /* end p_attw_gdouble_adjustment_callback */ /* --------------------------------- * p_duration_dependent_refresh * --------------------------------- * support of overlapping requires refresh of both previews in most situations * (in some sitations, where att_overlap == 0 it might be sufficient * to refresh only the preview that represents the TO value. * this simple implementation currently refreshes always both previews) */ static void p_duration_dependent_refresh(GapStbAttrWidget *attw) { attw->timer_full_update_request = TRUE; p_attw_update_properties(attw); } /* end p_duration_dependent_refresh */ /* ----------------------------------- * p_attw_duration_adjustment_callback * ----------------------------------- */ static void p_attw_duration_adjustment_callback(GtkObject *obj, gint32 *val) { GapStbAttrWidget *attw; gint32 l_val; attw = g_object_get_data( G_OBJECT(obj), OBJ_DATA_KEY_ATTW ); if(attw) { if(attw->stb_elem_refptr) { l_val = RINT (GTK_ADJUSTMENT(obj)->value); if(gap_debug) { printf("gint32_adjustment_callback: obj:%d old_val:%d val:%d\n" ,(int)obj ,(int)*val ,(int)l_val ); } if(l_val != *val) { p_attw_push_undo_and_set_unsaved_changes(attw); *val = l_val; p_duration_dependent_refresh(attw); } } } } /* end p_attw_duration_adjustment_callback */ /* ------------------------------------ * p_attw_enable_toggle_update_callback * ------------------------------------ */ static void p_attw_enable_toggle_update_callback(GtkWidget *widget, gboolean *val) { GapStbAttrWidget *attw; attw = g_object_get_data( G_OBJECT(widget), OBJ_DATA_KEY_ATTW ); if((attw) && (val)) { if(attw->stb_elem_refptr) { p_attw_push_undo_and_set_unsaved_changes(attw); if (GTK_TOGGLE_BUTTON (widget)->active) { *val = TRUE; } else { *val = FALSE; } p_attw_update_sensitivity(attw); p_duration_dependent_refresh(attw); p_attw_update_properties(attw); } } } /* end p_attw_enable_toggle_update_callback */ /* ----------------------------------------- * p_attw_auto_update_toggle_update_callback * ----------------------------------------- */ static void p_attw_auto_update_toggle_update_callback(GtkWidget *widget, gboolean *val) { GapStbAttrWidget *attw; attw = g_object_get_data( G_OBJECT(widget), OBJ_DATA_KEY_ATTW ); if((attw) && (val)) { if(attw->stb_elem_refptr) { p_attw_push_undo_and_set_unsaved_changes(attw); if (GTK_TOGGLE_BUTTON (widget)->active) { *val = TRUE; p_update_full_preview_gfx(attw); } else { *val = FALSE; } } } } /* end p_attw_auto_update_toggle_update_callback */ /* --------------------------------- * p_attw_preview_events_cb * --------------------------------- */ static gboolean p_attw_preview_events_cb (GtkWidget *widget , GdkEvent *event , GapStbAttrWidget *attw) { GdkEventExpose *eevent; GdkEventButton *bevent; GapStbMainGlobalParams *sgpp; gint img_idx; if ((attw->stb_elem_refptr == NULL) || (attw->stb_refptr == NULL)) { /* the attribute widget is not initialized no action allowed */ return FALSE; } sgpp = attw->sgpp; img_idx = (gint)g_object_get_data( G_OBJECT(widget), OBJ_DATA_KEY_IMG_IDX ); if(img_idx != 0) { img_idx = 1; } switch (event->type) { case GDK_BUTTON_PRESS: bevent = (GdkEventButton *) event; // TODO: define actions when button pressed. /* debug code to display a copy of the image */ if(1==0) { gint32 dup_id; dup_id = gimp_image_duplicate(attw->gfx_tab[img_idx].image_id); gimp_display_new(dup_id); } return FALSE; break; case GDK_EXPOSE: if(gap_debug) { printf("p_attw_preview_events_cb GDK_EXPOSE widget:%d img_idx:%d\n" , (int)widget , (int)img_idx ); } eevent = (GdkEventExpose *) event; gap_pview_repaint(attw->gfx_tab[img_idx].pv_ptr); gdk_flush (); break; default: break; } return FALSE; } /* end p_attw_preview_events_cb */ /* ----------------------------------------- * p_calculate_prefetch_render_attributes * ----------------------------------------- * Calculate render attributes for the prefetch frame * The prefetch frame is used for overlapping frames for * the "normal" track that is overlapped by the shadow track. * Defaults for all transitions transition settings are used here, * because the transition settings will apply to the curr_layer in the shadow track, * but settings for keep_proportions, fit_width and fit_height are respected. * NOTE: * for exact rendering the transition attribute settings at prefetch position * would be required, but defaults should be sufficient to visualizes the settings * of the current transition without interfering with settings of prior transitions. */ static void p_calculate_prefetch_render_attributes(GapStbAttrWidget *attw , gint img_idx , GapStoryCalcAttr *calc_attr_ptr ) { gint ii; gint32 pv_master_width; /* master width scaled to preview size */ gint32 pv_master_height; /* master height scaled to preview size */ gdouble master_scale; gdouble att_tab[GAP_STB_ATT_GFX_ARRAY_MAX][GAP_STB_ATT_TYPES_ARRAY_MAX]; gdouble pv_frame_width; gdouble pv_frame_height; pv_master_width = gimp_image_width(attw->gfx_tab[img_idx].image_id) * PVIEW_TO_MASTER_SCALE; pv_master_height = gimp_image_height(attw->gfx_tab[img_idx].image_id) * PVIEW_TO_MASTER_SCALE; master_scale = (gdouble)pv_master_width / (gdouble)(MAX( 1, attw->stb_refptr->master_width)); pv_frame_width = (gdouble)gimp_drawable_width(attw->gfx_tab[img_idx].opre_layer_id) * master_scale; pv_frame_height = (gdouble)gimp_drawable_height(attw->gfx_tab[img_idx].opre_layer_id) * master_scale; for(ii=0; ii < GAP_STB_ATT_TYPES_ARRAY_MAX; ii++) { att_tab[0][ii] = gap_story_get_default_attribute(ii); att_tab[1][ii] = gap_story_get_default_attribute(ii); } gap_story_file_calculate_render_attributes(calc_attr_ptr , gimp_image_width(attw->gfx_tab[img_idx].image_id) , gimp_image_height(attw->gfx_tab[img_idx].image_id) , pv_master_width , pv_master_height , (gint32)rint(pv_frame_width) , (gint32)rint(pv_frame_height) , attw->stb_elem_refptr->att_keep_proportions , attw->stb_elem_refptr->att_fit_width , attw->stb_elem_refptr->att_fit_height , att_tab [img_idx][GAP_STB_ATT_TYPE_OPACITY] , att_tab [img_idx][GAP_STB_ATT_TYPE_ZOOM_X] , att_tab [img_idx][GAP_STB_ATT_TYPE_ZOOM_Y] , att_tab [img_idx][GAP_STB_ATT_TYPE_MOVE_X] , att_tab [img_idx][GAP_STB_ATT_TYPE_MOVE_Y] ); } /* end p_calculate_prefetch_render_attributes */ /* ----------------------------------------- * p_calculate_render_attributes * ----------------------------------------- * NOTE: filtermacro processing is ignored, * the preview */ static void p_calculate_render_attributes(GapStbAttrWidget *attw , gint img_idx , GapStoryCalcAttr *calc_attr_ptr ) { gint ii; gint32 pv_master_width; /* master width scaled to preview size */ gint32 pv_master_height; /* master height scaled to preview size */ gdouble master_scale; gdouble att_tab[GAP_STB_ATT_GFX_ARRAY_MAX][GAP_STB_ATT_TYPES_ARRAY_MAX]; gdouble pv_frame_width; gdouble pv_frame_height; pv_master_width = gimp_image_width(attw->gfx_tab[img_idx].image_id) * PVIEW_TO_MASTER_SCALE; pv_master_height = gimp_image_height(attw->gfx_tab[img_idx].image_id) * PVIEW_TO_MASTER_SCALE; master_scale = (gdouble)pv_master_width / (gdouble)(MAX( 1, attw->stb_refptr->master_width)); pv_frame_width = (gdouble)gimp_drawable_width(attw->gfx_tab[img_idx].orig_layer_id) * master_scale; pv_frame_height = (gdouble)gimp_drawable_height(attw->gfx_tab[img_idx].orig_layer_id) * master_scale; for(ii=0; ii < GAP_STB_ATT_TYPES_ARRAY_MAX; ii++) { if(attw->stb_elem_refptr->att_arr_enable[ii] == TRUE) { att_tab[0][ii] = attw->stb_elem_refptr->att_arr_value_from[ii]; att_tab[1][ii] = attw->stb_elem_refptr->att_arr_value_to[ii]; } else { att_tab[0][ii] = gap_story_get_default_attribute(ii); att_tab[1][ii] = gap_story_get_default_attribute(ii); } } gap_story_file_calculate_render_attributes(calc_attr_ptr , gimp_image_width(attw->gfx_tab[img_idx].image_id) , gimp_image_height(attw->gfx_tab[img_idx].image_id) , pv_master_width , pv_master_height , (gint32)rint(pv_frame_width) , (gint32)rint(pv_frame_height) , attw->stb_elem_refptr->att_keep_proportions , attw->stb_elem_refptr->att_fit_width , attw->stb_elem_refptr->att_fit_height , att_tab [img_idx][GAP_STB_ATT_TYPE_OPACITY] , att_tab [img_idx][GAP_STB_ATT_TYPE_ZOOM_X] , att_tab [img_idx][GAP_STB_ATT_TYPE_ZOOM_Y] , att_tab [img_idx][GAP_STB_ATT_TYPE_MOVE_X] , att_tab [img_idx][GAP_STB_ATT_TYPE_MOVE_Y] ); } /* end p_calculate_render_attributes */ /* ----------------------------------------- * p_check_and_make_opre_default_layer * ----------------------------------------- * check if there is a valid original prefetch layer opre_layer_id (>= 0) * if NOT create a faked opre layer at master size. */ static void p_check_and_make_opre_default_layer(GapStbAttrWidget *attw, gint img_idx) { if(attw->gfx_tab[img_idx].opre_layer_id < 0) { gint32 image_id; gint32 layer_id; gdouble red, green, blue, alpha; image_id = attw->gfx_tab[img_idx].image_id; layer_id = gimp_layer_new(image_id , LAYERNAME_OPRE , attw->stb_refptr->master_width , attw->stb_refptr->master_height , GIMP_RGBA_IMAGE , 100.0 /* full opacity */ , 0 /* normal mode */ ); gimp_image_add_layer (image_id, layer_id, LAYERSTACK_TOP); red = 0.72; green = 0.80; blue = 0.25; alpha = 1.0; gap_layer_clear_to_color(layer_id, red, green, blue, alpha); attw->gfx_tab[img_idx].opre_layer_id = layer_id; attw->gfx_tab[img_idx].opre_info.layer_is_fake = TRUE; } gimp_drawable_set_visible(attw->gfx_tab[img_idx].opre_layer_id, FALSE); } /* end p_check_and_make_opre_default_layer */ /* ----------------------------------------- * p_check_and_make_orig_default_layer * ----------------------------------------- * check if there is a valid orig_layer_id (>= 0) * if NOT create a faked orig layers at master size. */ static void p_check_and_make_orig_default_layer(GapStbAttrWidget *attw, gint img_idx) { if(attw->gfx_tab[img_idx].orig_layer_id < 0) { gint32 image_id; gint32 layer_id; gdouble red, green, blue, alpha; image_id = attw->gfx_tab[img_idx].image_id; layer_id = gimp_layer_new(image_id , LAYERNAME_ORIG , attw->stb_refptr->master_width , attw->stb_refptr->master_height , GIMP_RGBA_IMAGE , 100.0 /* full opacity */ , 0 /* normal mode */ ); gimp_image_add_layer (image_id, layer_id, LAYERSTACK_TOP); red = 0.42; green = 0.90; blue = 0.35; alpha = 1.0; gap_layer_clear_to_color(layer_id, red, green, blue, alpha); attw->gfx_tab[img_idx].orig_layer_id = layer_id; attw->gfx_tab[img_idx].orig_info.layer_is_fake = TRUE; } gimp_drawable_set_visible(attw->gfx_tab[img_idx].orig_layer_id, FALSE); } /* end p_check_and_make_orig_default_layer */ /* ----------------------------------------- * p_create_color_layer * ----------------------------------------- * create a layer with specified color at image size (== preview size) * with a transparent rectangle at scaled master size in the center. */ static gint32 p_create_color_layer(GapStbAttrWidget *attw, gint32 image_id , const char *name, gint stackposition, gdouble opacity , gdouble red, gdouble green, gdouble blue) { gint32 layer_id; gdouble ofs_x; gdouble ofs_y; gdouble pv_master_width; /* master width scaled to preview size */ gdouble pv_master_height; /* master height scaled to preview size */ layer_id = gimp_layer_new(image_id , name , gimp_image_width(image_id) , gimp_image_height(image_id) , GIMP_RGBA_IMAGE , opacity , 0 /* normal mode */ ); gimp_image_add_layer (image_id, layer_id, stackposition); gap_layer_clear_to_color(layer_id, red, green, blue, 1.0); gimp_drawable_set_visible(layer_id, TRUE); pv_master_width = (gdouble)gimp_image_width(image_id) * PVIEW_TO_MASTER_SCALE; pv_master_height = (gdouble)gimp_image_height(image_id) * PVIEW_TO_MASTER_SCALE; ofs_x = ((gdouble)gimp_image_width(image_id) - pv_master_width) / 2.0; ofs_y = ((gdouble)gimp_image_height(image_id) - pv_master_height) / 2.0; /* green border */ { GimpRGB color; GimpRGB bck_color; color.r = 0.25; color.g = 0.80; color.b = 0.17; color.a = 1.0; /* selection for green rectangle (2 pixels border around master size) */ gimp_rect_select(image_id , ofs_x -2 , ofs_y -2 , pv_master_width +4 , pv_master_height +4 , GIMP_CHANNEL_OP_REPLACE , 0 /* gint32 feather */ , 0.0 /* gdouble feather radius */ ); gimp_context_get_background(&bck_color); gimp_context_set_background(&color); /* fill the drawable (ignoring selections) */ gimp_edit_fill(layer_id, GIMP_BACKGROUND_FILL); /* restore BG color in the context */ gimp_context_set_background(&bck_color); } gimp_rect_select(image_id , ofs_x , ofs_y , pv_master_width , pv_master_height , GIMP_CHANNEL_OP_REPLACE , 0 /* gint32 feather */ , 0.0 /* gdouble feather radius */ ); gimp_edit_clear(layer_id); gimp_selection_none(image_id); return (layer_id); } /* end p_create_color_layer */ /* ----------------------------------------- * p_create_base_layer * ----------------------------------------- */ static gint32 p_create_base_layer(GapStbAttrWidget *attw, gint32 image_id) { gint32 layer_id; gdouble red, green, blue, alpha; red = 0.86; green = 0.85; blue = 0.84; alpha = 1.0; layer_id = p_create_color_layer(attw , image_id , LAYERNAME_BASE , LAYERSTACK_BASE , 100.0 /* full opaque */ , red , green , blue ); return (layer_id); } /* end p_create_base_layer */ /* ----------------------------------------- * p_create_deco_layer * ----------------------------------------- */ static gint32 p_create_deco_layer(GapStbAttrWidget *attw, gint32 image_id) { gint32 layer_id; gdouble red, green, blue, alpha; red = 0.86; green = 0.85; blue = 0.84; alpha = 1.0; layer_id = p_create_color_layer(attw , image_id , LAYERNAME_DECO , LAYERSTACK_TOP , 60.0 /* 70% opaque */ , red , green , blue ); return (layer_id); } /* end p_create_deco_layer */ /* ----------------------------------------- * p_create_gfx_image * ----------------------------------------- */ static void p_create_gfx_image(GapStbAttrWidget *attw, gint img_idx) { gint32 image_id; image_id = gimp_image_new( attw->gfx_tab[img_idx].pv_ptr->pv_width , attw->gfx_tab[img_idx].pv_ptr->pv_height , GIMP_RGB ); gimp_image_undo_disable (image_id); attw->gfx_tab[img_idx].base_layer_id = p_create_base_layer(attw, image_id); attw->gfx_tab[img_idx].deco_layer_id = p_create_deco_layer(attw, image_id); attw->gfx_tab[img_idx].orig_layer_id = -1; /* to be created later */ attw->gfx_tab[img_idx].curr_layer_id = -1; /* to be created later */ attw->gfx_tab[img_idx].opre_layer_id = -1; /* to be created later */ attw->gfx_tab[img_idx].pref_layer_id = -1; /* to be created later */ attw->gfx_tab[img_idx].image_id = image_id; attw->gfx_tab[img_idx].opre_info.layer_is_fake = TRUE; attw->gfx_tab[img_idx].orig_info.layer_is_fake = TRUE; } /* end p_create_gfx_image */ /* ----------------------------------------- * p_delete_gfx_images * ----------------------------------------- */ static void p_delete_gfx_images(GapStbAttrWidget *attw) { gimp_image_delete(attw->gfx_tab[0].image_id); gimp_image_delete(attw->gfx_tab[1].image_id); attw->gfx_tab[0].image_id = -1; attw->gfx_tab[1].image_id = -1; } /* end p_delete_gfx_images */ /* ----------------------------------------- * p_adjust_stackposition * ----------------------------------------- */ static void p_adjust_stackposition(gint32 image_id, gint32 layer_id, gint position) { gint ii; /* adjust stack position */ gimp_image_lower_layer_to_bottom (image_id, layer_id); for (ii=0; ii < position; ii++) { gimp_image_raise_layer (image_id, layer_id); } } /* end p_adjust_stackposition */ /* ----------------------------------------- * p_create_transformed_layer * ----------------------------------------- * create transformed copy of the specified origsize_layer_id, * according to calculated transformation settings. */ static void p_create_transformed_layer(gint32 image_id , gint32 origsize_layer_id , gint32 *layer_id_ptr , GapStoryCalcAttr *calculated , gint32 stackposition, const char *layername) { /* if size is not equal calculated size remove curr layer * to force recreation in desired size */ if (*layer_id_ptr >= 0) { if ((gimp_drawable_width(*layer_id_ptr) != calculated->width) || (gimp_drawable_height(*layer_id_ptr) != calculated->height)) { gimp_image_remove_layer( image_id , *layer_id_ptr); *layer_id_ptr = -1; } } /* check and recreate the current layer at stackposition 2 */ if (*layer_id_ptr < 0) { gint32 new_layer_id; new_layer_id = gimp_layer_copy(origsize_layer_id); gimp_image_add_layer (image_id, new_layer_id, stackposition); gimp_drawable_set_name(new_layer_id, layername); gimp_layer_scale(new_layer_id, calculated->width, calculated->height, 0); gimp_drawable_set_visible(new_layer_id, TRUE); *layer_id_ptr = new_layer_id; } p_adjust_stackposition(image_id, *layer_id_ptr, stackposition); /* set offsets and opacity */ gimp_layer_set_offsets(*layer_id_ptr , calculated->x_offs , calculated->y_offs ); gimp_layer_set_opacity(*layer_id_ptr , calculated->opacity ); } /* end p_create_transformed_layer */ /* ----------------------------------------- * p_calculate_prefetch_visibility * ----------------------------------------- */ static gboolean p_calculate_prefetch_visibility(GapStbAttrWidget *attw, gint img_idx) { gboolean prefetch_visible; prefetch_visible = FALSE; if(attw->stb_elem_refptr->att_overlap > 0) { gint32 duration; duration = p_get_relevant_duration(attw, img_idx); if(attw->stb_elem_refptr->att_overlap >= duration) { prefetch_visible = TRUE; } } return (prefetch_visible); } /* end p_calculate_prefetch_visibility */ /* ----------------------------------------- * p_render_gfx * ----------------------------------------- * render graphical preview. * This procedure does not include fetching the referred frame * It assumes that the corresponding frame(s) have already been fetched * into the orig_layer (and opre_layer for overlapping frames within this track) * of the internal gimp image that will be used for * rendering of the preview. * If that image does not contain such a valid orig_layer and opre_layer, * it creates empty default representations, where master size is assumed. */ static void p_render_gfx(GapStbAttrWidget *attw, gint img_idx) { GapStoryCalcAttr calculate_curr_attributes; GapStoryCalcAttr calculate_pref_attributes; gint32 image_id; gboolean prefetch_visible; image_id = attw->gfx_tab[img_idx].image_id; p_check_and_make_orig_default_layer(attw, img_idx); p_check_and_make_opre_default_layer(attw, img_idx); p_calculate_prefetch_render_attributes(attw , img_idx , &calculate_pref_attributes ); p_create_transformed_layer(image_id , attw->gfx_tab[img_idx].opre_layer_id , &attw->gfx_tab[img_idx].pref_layer_id , &calculate_pref_attributes , LAYERSTACK_PREF , LAYERNAME_PREF ); p_calculate_render_attributes (attw , img_idx , &calculate_curr_attributes ); p_create_transformed_layer(image_id , attw->gfx_tab[img_idx].orig_layer_id , &attw->gfx_tab[img_idx].curr_layer_id , &calculate_curr_attributes , LAYERSTACK_CURR , LAYERNAME_CURR ); prefetch_visible = p_calculate_prefetch_visibility(attw, img_idx); gimp_drawable_set_visible(attw->gfx_tab[img_idx].opre_layer_id, FALSE); gimp_drawable_set_visible(attw->gfx_tab[img_idx].orig_layer_id, FALSE); gimp_drawable_set_visible(attw->gfx_tab[img_idx].deco_layer_id, TRUE); gimp_drawable_set_visible(attw->gfx_tab[img_idx].curr_layer_id, TRUE); gimp_drawable_set_visible(attw->gfx_tab[img_idx].pref_layer_id, prefetch_visible); gimp_drawable_set_visible(attw->gfx_tab[img_idx].base_layer_id, TRUE); /* render the preview from image */ gap_pview_render_from_image_duplicate (attw->gfx_tab[img_idx].pv_ptr , image_id ); gtk_widget_queue_draw(attw->gfx_tab[img_idx].pv_ptr->da_widget); gdk_flush(); } /* end p_render_gfx */ /* ----------------------------------- * p_update_framenr_labels * ----------------------------------- * update both frame number and time label 000001 00:00:000 * for the specified start or end gfx_preview (via img_idx) */ static void p_update_framenr_labels(GapStbAttrWidget *attw, gint img_idx, gint32 framenr) { char txt_buf[100]; gdouble l_speed_fps; if(attw == NULL) { return; } if(attw->stb_elem_refptr == NULL) { return; } g_snprintf(txt_buf, sizeof(txt_buf), "%d " ,(int)framenr ); gtk_label_set_text ( GTK_LABEL(attw->gfx_tab[img_idx].framenr_label), txt_buf); l_speed_fps = GAP_STORY_DEFAULT_FRAMERATE; if(attw->stb_refptr) { if(attw->stb_refptr->master_framerate > 0) { l_speed_fps = attw->stb_refptr->master_framerate; } } gap_timeconv_framenr_to_timestr(framenr -1 , l_speed_fps , txt_buf , sizeof(txt_buf) ); gtk_label_set_text ( GTK_LABEL(attw->gfx_tab[img_idx].frametime_label), txt_buf); } /* end p_update_framenr_labels */ /* ----------------------------------------- * p_get_relevant_duration * ----------------------------------------- */ static gint32 p_get_relevant_duration(GapStbAttrWidget *attw, gint img_idx) { gint32 duration; /* for the start frame ( img_idx ==0) always use duration 0 */ duration = 0; if (img_idx != 0) { gint ii; /* for the end frame pick the duration from the first enabled attribute */ for(ii=0; ii < GAP_STB_ATT_TYPES_ARRAY_MAX; ii++) { if(attw->stb_elem_refptr->att_arr_enable[ii] == TRUE) { duration = attw->stb_elem_refptr->att_arr_value_dur[ii]; break; } } } return(duration); } /* end p_get_relevant_duration */ /* ----------------------------------------- * p_update_full_preview_gfx * ----------------------------------------- * update the previews (both start and end) with the corresponding auto_update flag set. * for rendering of the preview(s) * and fetching of the refered frame at orig size into orig_layer. */ static void p_update_full_preview_gfx(GapStbAttrWidget *attw) { gint img_idx; for(img_idx = 0; img_idx < GAP_STB_ATT_GFX_ARRAY_MAX; img_idx++) { if(attw->gfx_tab[img_idx].auto_update) { gint32 duration; duration = p_get_relevant_duration(attw, img_idx); p_create_or_replace_orig_and_opre_layer (attw, img_idx, duration); p_render_gfx (attw, img_idx); } } } /* end p_update_full_preview_gfx */ /* --------------------------------- * p_stb_req_equals_layer_info * --------------------------------- * check if required position (specified via stb_ret and filename) * refers to the same frame as stored in the specified layer info structure. * the relevant infornmation of the orig_layer is stored in * linfo->layer_record_type; * linfo->layer_local_framenr; * linfo->layer_seltrack; * *linfo->layer_filename; * */ static gboolean p_stb_req_equals_layer_info(GapStbAttrLayerInfo *linfo , GapStoryLocateRet *stb_ret , const char *filename) { if (stb_ret->stb_elem->record_type != linfo->layer_record_type) { return(FALSE); } if (stb_ret->stb_elem->seltrack != linfo->layer_seltrack) { return(FALSE); } if (stb_ret->ret_framenr != linfo->layer_local_framenr) { return(FALSE); } if (linfo->layer_filename == NULL) { if(filename != NULL) { return(FALSE); } } else { if(filename == NULL) { return(FALSE); } if(strcmp(filename, linfo->layer_filename) != 0) { return(FALSE); } } return(TRUE); } /* end p_stb_req_equals_layer_info */ /* --------------------------------- * p_destroy_orig_layer * --------------------------------- * destroy orig layer and corresponding derived layer * if they are already existing */ static void p_destroy_orig_layer( gint32 image_id , gint32 *orig_layer_id_ptr , gint32 *derived_layer_id_ptr , GapStbAttrLayerInfo *linfo) { if(*orig_layer_id_ptr >= 0) { /* not up to date: destroy orig layer */ gimp_image_remove_layer(image_id , *orig_layer_id_ptr); *orig_layer_id_ptr = -1; } linfo->layer_record_type = GAP_STBREC_VID_UNKNOWN; linfo->layer_local_framenr = -1; linfo->layer_seltrack = -1; if (linfo->layer_filename != NULL) { g_free(linfo->layer_filename); linfo->layer_filename = NULL; } /* remove curr layer if already exists */ if(*derived_layer_id_ptr >= 0) { gimp_image_remove_layer(image_id , *derived_layer_id_ptr); *derived_layer_id_ptr = -1; } } /* end p_destroy_orig_layer */ /* --------------------------------- * p_check_orig_layer_up_to_date * --------------------------------- * check if there is an orig layer and if it is still * up to date. (return TRUE in that case) * else return FALSE. * * if there is a non-up to date orig layer destroy this outdated * orig layer and the correspondig derived layer too. */ static gboolean p_check_orig_layer_up_to_date(gint32 image_id , gint32 *orig_layer_id_ptr , gint32 *derived_layer_id_ptr , GapStbAttrLayerInfo *linfo , GapStoryLocateRet *stb_ret , const char *filename) { if(*orig_layer_id_ptr >= 0) { if (p_stb_req_equals_layer_info(linfo, stb_ret, filename) == TRUE) { return (TRUE); /* OK orig layer already up to date */ } } /* remove orig layer and derived layer if already exists */ p_destroy_orig_layer(image_id ,orig_layer_id_ptr ,derived_layer_id_ptr ,linfo ); return (FALSE); } /* end p_check_orig_layer_up_to_date */ /* -------------------------------------- * p_orig_layer_frame_fetcher * -------------------------------------- */ static void p_orig_layer_frame_fetcher(GapStbAttrWidget *attw , gint32 master_framenr , gint32 image_id , gint32 *orig_layer_id_ptr , gint32 *derived_layer_id_ptr , GapStbAttrLayerInfo *linfo) { gint32 l_layer_id; char *l_filename; l_layer_id = -1; l_filename = NULL; { GapStoryLocateRet *stb_ret; GapStorySection *section; section = gap_story_find_section_by_stb_elem(attw->stb_refptr, attw->stb_elem_refptr); stb_ret = gap_story_locate_expanded_framenr(section , master_framenr , attw->stb_elem_refptr->track ); if(stb_ret) { if ((stb_ret->locate_ok) && (stb_ret->stb_elem)) { gboolean is_up_to_date; l_filename = gap_story_get_filename_from_elem_nr(stb_ret->stb_elem , stb_ret->ret_framenr ); is_up_to_date = p_check_orig_layer_up_to_date(image_id ,orig_layer_id_ptr ,derived_layer_id_ptr ,linfo ,stb_ret ,l_filename ); if(is_up_to_date) { g_free(stb_ret); if(l_filename) { g_free(l_filename); } return; /* orig_layer is still up to date, done */ } if(stb_ret->stb_elem->record_type == GAP_STBREC_VID_MOVIE) { if(l_filename) { /* fetch_full_sized_frame */ l_layer_id = p_fetch_video_frame_as_layer(attw->sgpp ,l_filename ,stb_ret->ret_framenr ,stb_ret->stb_elem->seltrack ,gap_story_get_preferred_decoder(attw->stb_refptr ,stb_ret->stb_elem ) ,image_id ); if(l_layer_id > 0) { l_layer_id = gap_layer_flip(l_layer_id, stb_ret->stb_elem->flip_request); linfo->layer_record_type = stb_ret->stb_elem->record_type; linfo->layer_local_framenr = stb_ret->ret_framenr; linfo->layer_seltrack = stb_ret->stb_elem->seltrack; if (linfo->layer_filename != NULL) { g_free(linfo->layer_filename); linfo->layer_filename = g_strdup(l_filename); } } } } else { /* record type is IMAGE or FRAME, fetch full size image * TODO: anim frame and COLOR not handled */ l_layer_id = p_fetch_imagefile_as_layer(l_filename ,image_id ); if(l_layer_id > 0) { l_layer_id = gap_layer_flip(l_layer_id, stb_ret->stb_elem->flip_request); linfo->layer_record_type = stb_ret->stb_elem->record_type; linfo->layer_local_framenr = 0; linfo->layer_seltrack = 1; if (linfo->layer_filename != NULL) { g_free(linfo->layer_filename); linfo->layer_filename = g_strdup(l_filename); } } } } g_free(stb_ret); } } *orig_layer_id_ptr = l_layer_id; if(l_layer_id >= 0) { linfo->layer_is_fake = FALSE; } else { p_destroy_orig_layer(image_id ,orig_layer_id_ptr ,derived_layer_id_ptr ,linfo ); } if(l_filename) { g_free(l_filename); } } /* end p_orig_layer_frame_fetcher */ /* --------------------------------------- * p_create_or_replace_orig_and_opre_layer * --------------------------------------- */ static gint32 p_calc_and_set_display_framenr(GapStbAttrWidget *attw , gint img_idx , gint32 duration) { gint32 l_framenr_start; gint32 l_framenr; gint32 l_prefetch_framenr; gint32 l_dsiplay_framenr; GapStorySection *section; section = gap_story_find_section_by_stb_elem(attw->stb_refptr, attw->stb_elem_refptr); /* calculate the absolute frame number for the frame to access */ l_framenr_start = gap_story_get_framenr_by_story_id(section ,attw->stb_elem_refptr->story_id ,attw->stb_elem_refptr->track ); /* stb_elem_refptr refers to the transition attribute stb_elem */ l_framenr = l_framenr_start + MAX(0, (duration -1)); l_prefetch_framenr = -1; l_dsiplay_framenr = l_framenr; if(attw->stb_elem_refptr->att_overlap > 0) { l_prefetch_framenr = CLAMP((l_framenr - attw->stb_elem_refptr->att_overlap), 0, l_framenr_start); if(l_prefetch_framenr > 0) { l_dsiplay_framenr = l_prefetch_framenr; } } p_update_framenr_labels(attw, img_idx, l_dsiplay_framenr); return (l_dsiplay_framenr); } /* end p_calc_and_set_display_framenr */ /* --------------------------------------- * p_create_or_replace_orig_and_opre_layer * --------------------------------------- * fetch the frame that is refered by the stb_elem_refptr + duration (frames) * If there is no frame found, use a default image. * (possible reasons: duration refers behind valid frame range, * video support is turned off at compile time, but reference points * into a movie clip) * * the fetched (or default) frame is added as invisible layer with alpha channel * on top of the layerstack in the specified image as orig_layer_id. * (an already existing orig_layer_id will be replaced if there exists one) * * If the orig_layer is up to date the fetch is not performed. * * if overlapping is used (att_overap > 0) * we prefetch a 2.nd original (the opre_layer) that shall be rendered * below the orig_layer. its position is current - att_overap * */ static void p_create_or_replace_orig_and_opre_layer (GapStbAttrWidget *attw , gint img_idx , gint32 duration) { gint32 l_framenr_start; gint32 l_framenr; gint32 l_prefetch_framenr; GapStorySection *section; section = gap_story_find_section_by_stb_elem(attw->stb_refptr, attw->stb_elem_refptr); /* calculate the absolute expanded frame number for the frame to access * (we operate with expanded frame number, where the track overlapping * is ignored. this allows access to frames that otherwise were skipped due to * overlapping in the shadow track) */ l_framenr_start = gap_story_get_expanded_framenr_by_story_id(section ,attw->stb_elem_refptr->story_id ,attw->stb_elem_refptr->track ); /* stb_elem_refptr refers to the transition attribute stb_elem */ l_framenr = l_framenr_start + MAX(0, (duration -1)); l_prefetch_framenr = -1; if(attw->stb_elem_refptr->att_overlap > 0) { l_prefetch_framenr = l_framenr - attw->stb_elem_refptr->att_overlap; } p_calc_and_set_display_framenr(attw, img_idx, duration ); /* OPRE_LAYER (re)creation */ if(l_prefetch_framenr > 0) { p_orig_layer_frame_fetcher(attw , l_prefetch_framenr , attw->gfx_tab[img_idx].image_id ,&attw->gfx_tab[img_idx].opre_layer_id /* orig_layer_id_ptr */ ,&attw->gfx_tab[img_idx].pref_layer_id /* derived_layer_id_ptr */ ,&attw->gfx_tab[img_idx].opre_info /* linfo */ ); } p_check_and_make_opre_default_layer(attw, img_idx); /* ORIG_LAYER (re)creation */ p_orig_layer_frame_fetcher(attw , l_framenr , attw->gfx_tab[img_idx].image_id ,&attw->gfx_tab[img_idx].orig_layer_id /* orig_layer_id_ptr */ ,&attw->gfx_tab[img_idx].curr_layer_id /* derived_layer_id_ptr */ ,&attw->gfx_tab[img_idx].orig_info /* linfo */ ); /* check if we have a valid orig layer, create it if have not * (includes setting invisible) */ p_check_and_make_orig_default_layer(attw, img_idx); } /* end p_create_or_replace_orig_and_opre_layer */ /* --------------------------------- * p_fetch_video_frame_as_layer * --------------------------------- */ static gint32 p_fetch_video_frame_as_layer(GapStbMainGlobalParams *sgpp , const char *video_filename , gint32 framenumber , gint32 seltrack , const char *preferred_decoder , gint32 image_id ) { guchar *img_data; gint32 img_width; gint32 img_height; gint32 img_bpp; gboolean do_scale; gint32 l_new_layer_id; l_new_layer_id = -1; do_scale = FALSE; /* Fetch the wanted Frame from the Videofile */ img_data = gap_story_dlg_fetch_videoframe(sgpp , video_filename , framenumber , seltrack , preferred_decoder , 1.5 /* delace */ , &img_bpp , &img_width , &img_height , do_scale ); if(img_data != NULL) { GimpDrawable *drawable; GimpPixelRgn pixel_rgn; GimpImageType type; /* Fill in the alpha channel (for RGBA type) */ if(img_bpp == 4) { gint i; for (i=(img_width * img_height)-1; i>=0; i--) { img_data[3+(i*4)] = 255; } } type = GIMP_RGB_IMAGE; if(img_bpp == 4) { type = GIMP_RGBA_IMAGE; } l_new_layer_id = gimp_layer_new (image_id , LAYERNAME_ORIG , img_width , img_height , type , 100.0 , GIMP_NORMAL_MODE); drawable = gimp_drawable_get (l_new_layer_id); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0 , drawable->width, drawable->height , TRUE /* dirty */ , FALSE /* shadow */ ); gimp_pixel_rgn_set_rect (&pixel_rgn, img_data , 0 , 0 , img_width , img_height); if(! gimp_drawable_has_alpha (l_new_layer_id)) { /* implicite add an alpha channel before we try to raise */ gimp_layer_add_alpha(l_new_layer_id); } gimp_drawable_flush (drawable); gimp_drawable_detach(drawable); gimp_image_add_layer (image_id,l_new_layer_id, LAYERSTACK_TOP); } return(l_new_layer_id); } /* end p_fetch_video_frame_as_layer */ /* --------------------------------- * p_fetch_imagefile_as_layer * --------------------------------- */ static gint32 p_fetch_imagefile_as_layer (const char *img_filename , gint32 image_id ) { gint32 l_tmp_image_id; gint32 l_new_layer_id; l_new_layer_id = -1; { char *l_filename; l_filename = g_strdup(img_filename); l_tmp_image_id = gap_lib_load_image(l_filename); g_free(l_filename); } if(l_tmp_image_id >= 0) { gint32 l_layer_id; gint l_src_offset_x, l_src_offset_y; gimp_image_undo_disable (l_tmp_image_id); l_layer_id = gimp_image_flatten(l_tmp_image_id); if(l_layer_id < 0) { l_layer_id = gimp_layer_new(l_tmp_image_id, LAYERNAME_ORIG, 1, 1, ((gint)(gimp_image_base_type(l_tmp_image_id)) * 2), 100.0, /* Opacity full opaque */ 0); /* NORMAL */ gimp_image_add_layer(l_tmp_image_id, l_layer_id, LAYERSTACK_TOP); gimp_layer_set_offsets(l_layer_id, -1, -1); l_layer_id = gimp_image_flatten(l_tmp_image_id); } gimp_layer_add_alpha(l_layer_id); /* copy the layer from the temp image to the preview multilayer image */ l_new_layer_id = gap_layer_copy_to_dest_image(image_id, l_layer_id, 100.0, /* opacity full */ 0, /* NORMAL */ &l_src_offset_x, &l_src_offset_y ); gimp_image_add_layer (image_id, l_new_layer_id, LAYERSTACK_TOP); /* destroy the tmp image */ gimp_image_delete(l_tmp_image_id); } return(l_new_layer_id); } /* end p_fetch_imagefile_as_layer */ /* ------------------------------ * p_attw_comment_entry_update_cb * ------------------------------ */ static void p_attw_comment_entry_update_cb(GtkWidget *widget, GapStbAttrWidget *attw) { if(attw == NULL) { return; } if(attw->stb_elem_refptr == NULL) { return; } if(attw->stb_refptr) { attw->stb_refptr->unsaved_changes = TRUE; } if(attw->stb_elem_refptr->comment == NULL) { attw->stb_elem_refptr->comment = gap_story_new_elem(GAP_STBREC_VID_COMMENT); } if(attw->stb_elem_refptr->comment) { if(attw->stb_elem_refptr->comment->orig_src_line) { g_free(attw->stb_elem_refptr->comment->orig_src_line); } attw->stb_elem_refptr->comment->orig_src_line = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget))); } } /* end p_attw_comment_entry_update_cb */ /* --------------------------------------- * p_init_layer_info * --------------------------------------- */ static void p_init_layer_info(GapStbAttrLayerInfo *linfo) { linfo->layer_record_type = GAP_STBREC_VID_UNKNOWN; linfo->layer_local_framenr = -1; linfo->layer_seltrack = -1; linfo->layer_filename = NULL; } /* end p_init_layer_info */ /* ----------------------------------- * p_create_and_attach_pv_widgets * ----------------------------------- * creates preview widgets */ static void p_create_and_attach_pv_widgets(GapStbAttrWidget *attw , GtkWidget *table , gint row , gint col_start , gint col_end , gint img_idx ) { GtkWidget *vbox2; GtkWidget *hbox; GtkWidget *alignment; GtkWidget *check_button; GtkWidget *label; GtkWidget *event_box; GtkWidget *aspect_frame; gint32 l_check_size; gdouble thumb_scale; /* the vox2 */ vbox2 = gtk_vbox_new (FALSE, 1); /* aspect_frame is the CONTAINER for the video preview */ aspect_frame = gtk_aspect_frame_new (NULL /* without label */ , 0.5 /* xalign center */ , 0.5 /* yalign center */ , attw->stb_refptr->master_width / attw->stb_refptr->master_height /* ratio */ , TRUE /* obey_child */ ); gtk_widget_show (aspect_frame); /* Create an EventBox (container for the preview drawing_area) */ event_box = gtk_event_box_new (); gtk_container_add (GTK_CONTAINER (event_box), vbox2); gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK); /* The preview */ alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); gtk_box_pack_start (GTK_BOX (vbox2), alignment, FALSE, FALSE, 1); gtk_widget_show (alignment); /* calculate scale factor (the preview has same proportions as the master * and fits into a sqare of size PVIEW_SIZE x PVIEW_SIZE) */ { gdouble master_size; master_size = (gdouble)MAX(attw->stb_refptr->master_width, attw->stb_refptr->master_height); thumb_scale = (gdouble)PVIEW_SIZE / master_size; } l_check_size = PVIEW_SIZE / 32; attw->gfx_tab[img_idx].pv_ptr = gap_pview_new( (thumb_scale * (gdouble)attw->stb_refptr->master_width) + 4.0 , (thumb_scale * (gdouble)attw->stb_refptr->master_height) + 4.0 , l_check_size , aspect_frame ); gtk_widget_set_events (attw->gfx_tab[img_idx].pv_ptr->da_widget, GDK_EXPOSURE_MASK); gtk_container_add (GTK_CONTAINER (aspect_frame), attw->gfx_tab[img_idx].pv_ptr->da_widget); gtk_container_add (GTK_CONTAINER (alignment), aspect_frame); gtk_widget_show (attw->gfx_tab[img_idx].pv_ptr->da_widget); /* create a gimp image that is internally used for rendering the preview * (create no view for this image, to keep it invisible for the user) */ p_create_gfx_image(attw, img_idx); g_object_set_data(G_OBJECT(attw->gfx_tab[img_idx].pv_ptr->da_widget) , OBJ_DATA_KEY_IMG_IDX, (gpointer)img_idx); g_object_set_data(G_OBJECT(event_box) , OBJ_DATA_KEY_IMG_IDX, (gpointer)img_idx); g_signal_connect (G_OBJECT (attw->gfx_tab[img_idx].pv_ptr->da_widget), "event", G_CALLBACK (p_attw_preview_events_cb), attw); g_signal_connect (G_OBJECT (event_box), "button_press_event", G_CALLBACK (p_attw_preview_events_cb), attw); hbox = gtk_hbox_new (FALSE, 1); gtk_widget_show (hbox); gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 1); /* auto update toggle check button */ check_button = gtk_check_button_new_with_label (_("Update")); attw->gfx_tab[img_idx].auto_update_toggle = check_button; gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 1); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button) , attw->gfx_tab[img_idx].auto_update); gimp_help_set_help_data(check_button, _("automatic update using the referred frame"), NULL); gtk_widget_show(check_button); g_object_set_data(G_OBJECT(check_button), OBJ_DATA_KEY_ATTW, attw); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (p_attw_auto_update_toggle_update_callback), &attw->gfx_tab[img_idx].auto_update); /* the framenr label */ label = gtk_label_new ("000000"); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 1); gtk_widget_show (label); attw->gfx_tab[img_idx].framenr_label = label; /* the framenr label */ label = gtk_label_new ("mm:ss:msec"); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 1); gtk_widget_show (label); attw->gfx_tab[img_idx].frametime_label = label; gtk_widget_show(vbox2); gtk_widget_show (event_box); gtk_table_attach ( GTK_TABLE (table), event_box, col_start, col_end, row, row+1, GTK_FILL, 0, 0, 0); } /* end p_create_and_attach_pv_widgets */ /* ----------------------------------- * p_create_and_attach_att_arr_widgets * ----------------------------------- * creates widgets for attribute array values (enable, from, to duration) * and attaches them to the specified table in the specified row. * * Notes: attribute values for the from and to spinbuttons are multiplied by 100 * because the internal representation uses the value 1.0 * for 100 percent. */ static void p_create_and_attach_att_arr_widgets(const char *row_title , GapStbAttrWidget *attw , GtkWidget *table , gint row , gint column , gint att_type_idx , gdouble lower_constraint , gdouble upper_constraint , gdouble step_increment , gdouble page_increment , gdouble page_size , gint digits , const char *enable_tooltip , gboolean *att_arr_enable_ptr , const char *from_tooltip , gdouble *att_arr_value_from_ptr , const char *to_tooltip , gdouble *att_arr_value_to_ptr , const char *dur_tooltip , gint32 *att_arr_value_dur_ptr ) { GtkWidget *label; GtkWidget *button; GtkWidget *check_button; GtkObject *adj; GtkWidget *spinbutton; gint col; col = column; /* enable label */ label = gtk_label_new(row_title); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE (table), label, col, col+1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); col++; /* enable check button */ check_button = gtk_check_button_new_with_label (" "); attw->att_rows[att_type_idx].enable_toggle = check_button; gtk_table_attach ( GTK_TABLE (table), check_button, col, col+1, row, row+1, GTK_FILL, 0, 0, 0); { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), *att_arr_enable_ptr); } gimp_help_set_help_data(check_button, enable_tooltip, NULL); gtk_widget_show(check_button); g_object_set_data(G_OBJECT(check_button), OBJ_DATA_KEY_ATTW, attw); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (p_attw_enable_toggle_update_callback), att_arr_enable_ptr); col++; /* from start label */ button = gtk_button_new_with_label(_("Start:")); attw->att_rows[att_type_idx].button_from = button; gtk_table_attach(GTK_TABLE (table), button, col, col+1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gimp_help_set_help_data(button, _("Reset to: defaults, " "use modifyer keys CTRL, ALT for alternative defaults. " "SHIFT resets to initial value"), NULL); gtk_widget_show(button); g_object_set_data(G_OBJECT(button), OBJ_DATA_KEY_ATTW, attw); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (p_attw_start_button_clicked_callback), (gpointer)att_type_idx); col++; /* From (Start value of transition) button */ adj = gtk_adjustment_new ( *att_arr_value_from_ptr * CONVERT_TO_100PERCENT , lower_constraint , upper_constraint , step_increment , page_increment , page_size ); spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, digits); attw->att_rows[att_type_idx].spinbutton_from_adj = adj; attw->att_rows[att_type_idx].spinbutton_from = spinbutton; gtk_widget_show (spinbutton); gtk_table_attach (GTK_TABLE (table), spinbutton, col, col+1, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (spinbutton, 80, -1); gimp_help_set_help_data (spinbutton, from_tooltip, NULL); g_object_set_data(G_OBJECT(adj), OBJ_DATA_KEY_ATTW, attw); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (p_attw_gdouble_adjustment_callback), att_arr_value_from_ptr); col++; /* to (end value of transition) button */ button = gtk_button_new_with_label(_("End:")); attw->att_rows[att_type_idx].button_to = button; gtk_table_attach(GTK_TABLE (table), button, col, col+1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gimp_help_set_help_data(button, _("Reset to: defaults, " "use modifyer keys CTRL, ALT for alternative defaults. " "SHIFT resets to initial value"), NULL); gtk_widget_show(button); g_object_set_data(G_OBJECT(button), OBJ_DATA_KEY_ATTW, attw); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (p_attw_end_button_clicked_callback), (gpointer)att_type_idx); col++; /* the To value spinbutton */ adj = gtk_adjustment_new ( *att_arr_value_to_ptr * CONVERT_TO_100PERCENT , lower_constraint , upper_constraint , step_increment , page_increment , page_size ); spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, digits); attw->att_rows[att_type_idx].spinbutton_to_adj = adj; attw->att_rows[att_type_idx].spinbutton_to = spinbutton; gtk_widget_show (spinbutton); gtk_table_attach (GTK_TABLE (table), spinbutton, col, col+1, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (spinbutton, 80, -1); gimp_help_set_help_data (spinbutton, to_tooltip, NULL); g_object_set_data(G_OBJECT(adj), OBJ_DATA_KEY_ATTW, attw); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (p_attw_gdouble_adjustment_callback), att_arr_value_to_ptr); col++; /* Frames Duration button */ button = gtk_button_new_with_label(_("Frames:")); attw->att_rows[att_type_idx].button_dur = button; gtk_table_attach(GTK_TABLE (table), button, col, col+1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gimp_help_set_help_data(button, _("Copy this number of frames to all enabled rows"), NULL); gtk_widget_show(button); g_object_set_data(G_OBJECT(button), OBJ_DATA_KEY_ATTW, attw); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (p_attw_dur_button_clicked_callback), (gpointer)att_type_idx); col++; /* the Duration value spinbutton */ adj = gtk_adjustment_new ( *att_arr_value_dur_ptr , 0 , 999999 , 1 , 10 , 0 ); spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); attw->att_rows[att_type_idx].spinbutton_dur_adj = adj; attw->att_rows[att_type_idx].spinbutton_dur = spinbutton; gtk_widget_show (spinbutton); gtk_table_attach (GTK_TABLE (table), spinbutton, col, col+1, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (spinbutton, 80, -1); gimp_help_set_help_data (spinbutton, _("Number of frames (duration of transition from start to end value)"), NULL); g_object_set_data(G_OBJECT(adj), OBJ_DATA_KEY_ATTW, attw); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (p_attw_duration_adjustment_callback), att_arr_value_dur_ptr); col++; /* the time duration label */ label = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE(table), label, col, col+1, row, row+1); gtk_widget_show (label); attw->att_rows[att_type_idx].dur_time_label = label; } /* end p_create_and_attach_att_arr_widgets */ /* -------------------------------- * gap_story_attw_properties_dialog * -------------------------------- */ GtkWidget * gap_story_attw_properties_dialog (GapStbAttrWidget *attw) { GtkWidget *dlg; GtkWidget *main_vbox; GtkWidget *frame; GtkWidget *table; GtkWidget *label; GtkWidget *entry; GtkWidget *check_button; gint row; GapStbTabWidgets *tabw; if(attw == NULL) { return (NULL); } if(attw->attw_prop_dialog != NULL) { return(NULL); } /* is already open */ tabw = (GapStbTabWidgets *)attw->tabw; if(tabw == NULL) { return (NULL); } if(attw->stb_elem_bck) { dlg = gimp_dialog_new (_("Transition Attributes"), "gap_story_attr_properties" ,NULL, 0 ,gimp_standard_help_func, GAP_STORY_ATTR_PROP_HELP_ID ,GAP_STOCK_PLAY, GAP_STORY_ATT_RESPONSE_PLAYBACK ,GIMP_STOCK_RESET, GAP_STORY_ATT_RESPONSE_RESET ,GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE ,NULL); } else { dlg = gimp_dialog_new (_("Transition Attributes"), "gap_story_attr_properties" ,NULL, 0 ,gimp_standard_help_func, GAP_STORY_ATTR_PROP_HELP_ID ,GAP_STOCK_PLAY, GAP_STORY_ATT_RESPONSE_PLAYBACK ,GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE ,NULL); } attw->attw_prop_dialog = dlg; g_signal_connect (G_OBJECT (dlg), "response", G_CALLBACK (p_attw_prop_response), attw); main_vbox = gtk_vbox_new (FALSE, 4); gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6); gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dlg)->vbox), main_vbox); /* the frame */ frame = gimp_frame_new (_("Properties")); gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); table = gtk_table_new (16, 10, FALSE); attw->master_table = table; gtk_container_set_border_width (GTK_CONTAINER (table), 4); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_container_add (GTK_CONTAINER (frame), table); gtk_widget_show (table); row = 0; /* the fit size label */ label = gtk_label_new (_("FitSize:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 1, row, row+1); gtk_widget_show (label); /* the fit width check button */ check_button = gtk_check_button_new_with_label (_("Width")); attw->fit_width_toggle = check_button; gtk_table_attach ( GTK_TABLE (table), check_button, 1, 2, row, row+1, GTK_FILL, 0, 0, 0); { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button) , attw->stb_elem_refptr->att_fit_width); } gimp_help_set_help_data(check_button, _("scale width of frame to fit master width"), NULL); gtk_widget_show(check_button); g_object_set_data(G_OBJECT(check_button), OBJ_DATA_KEY_ATTW, attw); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (p_attw_enable_toggle_update_callback), &attw->stb_elem_refptr->att_fit_width); /* the fit height check button */ check_button = gtk_check_button_new_with_label (_("Height")); attw->fit_height_toggle = check_button; gtk_table_attach ( GTK_TABLE (table), check_button, 2, 3, row, row+1, GTK_FILL, 0, 0, 0); { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button) , attw->stb_elem_refptr->att_fit_height); } gimp_help_set_help_data(check_button, _("scale height of frame to fit master height"), NULL); gtk_widget_show(check_button); g_object_set_data(G_OBJECT(check_button), OBJ_DATA_KEY_ATTW, attw); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (p_attw_enable_toggle_update_callback), &attw->stb_elem_refptr->att_fit_height); /* the keep proportions check button */ check_button = gtk_check_button_new_with_label (_("Keep Proportion")); attw->keep_proportions_toggle = check_button; gtk_table_attach ( GTK_TABLE (table), check_button, 3, 5, row, row+1, GTK_FILL, 0, 0, 0); { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button) , attw->stb_elem_refptr->att_keep_proportions); } gimp_help_set_help_data(check_button, _("ON: keep proportions at scaling. " " (this may result in black borders)" "OFF: allow changes of image proportions at scaling"), NULL); gtk_widget_show(check_button); g_object_set_data(G_OBJECT(check_button), OBJ_DATA_KEY_ATTW, attw); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (p_attw_enable_toggle_update_callback), &attw->stb_elem_refptr->att_keep_proportions); /* overlap attributes */ { GtkObject *adj; GtkWidget *spinbutton; GtkWidget *button; /* the overlap label (same row as FitSize) */ label = gtk_label_new (_("Overlap:")); gtk_misc_set_alignment (GTK_MISC (label), 0.9, 0.5); gtk_table_attach_defaults (GTK_TABLE(table), label, 5, 6, row, row+1); gtk_widget_show (label); /* Frames Overlap duration button */ button = gtk_button_new_with_label(_("Frames:")); attw->button_overlap_dur = button; gtk_table_attach(GTK_TABLE (table), button, 6, 7, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gimp_help_set_help_data(button, _("Copy this number of frames to all enabled rows"), NULL); gtk_widget_show(button); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (p_attw_overlap_dur_button_clicked_callback), (gpointer)attw); /* the frames overlap duration value spinbutton */ adj = gtk_adjustment_new ( attw->stb_elem_refptr->att_overlap , 0 , 999999 , 1 , 10 , 0 ); spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); attw->spinbutton_overlap_dur_adj = adj; attw->spinbutton_overlap_dur = spinbutton; gtk_widget_show (spinbutton); gtk_table_attach (GTK_TABLE (table), spinbutton, 7, 8, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (spinbutton, 80, -1); gimp_help_set_help_data (spinbutton, _("Number of overlapping frames within this track"), NULL); g_object_set_data(G_OBJECT(adj), OBJ_DATA_KEY_ATTW, attw); g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (p_attw_duration_adjustment_callback), &attw->stb_elem_refptr->att_overlap); } /* end overlap attributes */ row++; { gint att_type_idx; gint col = 0; att_type_idx = GAP_STB_ATT_TYPE_OPACITY; p_create_and_attach_att_arr_widgets(_("Opacity:") , attw , table , row , col , att_type_idx , 0.0 /* lower constraint for the from/to values */ , 100.0 /* upper constraint for the from/to values */ , 1.0 /* step increment for the from/to values */ , 10.0 /* page increment for the from/to values */ , 0.0 /* page size for the from/to values */ , 0 /* digits for the from/to values */ , _("ON: Enable opacity settings") , &attw->stb_elem_refptr->att_arr_enable[att_type_idx] , _("opacity value for the first handled frame " "where 100 is fully opaque, 0 is fully transparent") , &attw->stb_elem_refptr->att_arr_value_from[att_type_idx] , _("opacity value for the last handled frame " "where 100 is fully opaque, 0 is fully transparent") , &attw->stb_elem_refptr->att_arr_value_to[att_type_idx] , _("number of frames") , &attw->stb_elem_refptr->att_arr_value_dur[att_type_idx] ); row++; att_type_idx = GAP_STB_ATT_TYPE_MOVE_X; p_create_and_attach_att_arr_widgets(_("Move X:") , attw , table , row , col , att_type_idx , -1000.0 /* lower constraint for the from/to values */ , 1000.0 /* upper constraint for the from/to values */ , 1.0 /* step increment for the from/to values */ , 10.0 /* page increment for the from/to values */ , 0.0 /* page size for the from/to values */ , 2 /* digits for the from/to values */ , _("ON: Enable move horizontal settings") , &attw->stb_elem_refptr->att_arr_enable[att_type_idx] , _("move horizontal value for the first handled frame " " where 0.0 is centered, 100.0 is outside right, -100.0 is outside left)") , &attw->stb_elem_refptr->att_arr_value_from[att_type_idx] , _("move horizontal value for the last handled frame " " where 0.0 is centered, 100.0 is outside right, -100.0 is outside left)") , &attw->stb_elem_refptr->att_arr_value_to[att_type_idx] , _("number of frames") , &attw->stb_elem_refptr->att_arr_value_dur[att_type_idx] ); row++; att_type_idx = GAP_STB_ATT_TYPE_MOVE_Y; p_create_and_attach_att_arr_widgets(_("Move Y:") , attw , table , row , col , att_type_idx , -1000.0 /* lower constraint for the from/to values */ , 1000.0 /* upper constraint for the from/to values */ , 1.0 /* step increment for the from/to values */ , 10.0 /* page increment for the from/to values */ , 0.0 /* page size for the from/to values */ , 2 /* digits for the from/to values */ , _("ON: Enable move vertical settings") , &attw->stb_elem_refptr->att_arr_enable[att_type_idx] , _("move vertical value for the first handled frame " " where 0.0 is centered, 100.0 is outside at bottom, -100.0 is outside at top)") , &attw->stb_elem_refptr->att_arr_value_from[att_type_idx] , _("move vertical value for the last handled frame " " where 0.0 is centered, 100.0 is outside at bottom, -100.0 is outside at top)") , &attw->stb_elem_refptr->att_arr_value_to[att_type_idx] , _("number of frames") , &attw->stb_elem_refptr->att_arr_value_dur[att_type_idx] ); row++; att_type_idx = GAP_STB_ATT_TYPE_ZOOM_X; p_create_and_attach_att_arr_widgets(_("Scale Width:") , attw , table , row , col , att_type_idx , 0.0 /* lower constraint for the from/to values */ , 1000.0 /* upper constraint for the from/to values */ , 1.0 /* step increment for the from/to values */ , 10.0 /* page increment for the from/to values */ , 0.0 /* page size for the from/to values */ , 2 /* digits for the from/to values */ , _("ON: Enable scale width settings") , &attw->stb_elem_refptr->att_arr_enable[att_type_idx] , _("scale width value for the first handled frame" " where 100 is 1:1, 50 is half, 200 is double width") , &attw->stb_elem_refptr->att_arr_value_from[att_type_idx] , _("scale width value for the last handled frame" " where 100 is 1:1, 50 is half, 200 is double width") , &attw->stb_elem_refptr->att_arr_value_to[att_type_idx] , _("number of frames") , &attw->stb_elem_refptr->att_arr_value_dur[att_type_idx] ); row++; att_type_idx = GAP_STB_ATT_TYPE_ZOOM_Y; p_create_and_attach_att_arr_widgets(_("Scale Height:") , attw , table , row , col , att_type_idx , -1000.0 /* lower constraint for the from/to values */ , 1000.0 /* upper constraint for the from/to values */ , 1.0 /* step increment for the from/to values */ , 10.0 /* page increment for the from/to values */ , 0.0 /* page size for the from/to values */ , 2 /* digits for the from/to values */ , _("ON: Enable scale height settings") , &attw->stb_elem_refptr->att_arr_enable[att_type_idx] , _("scale height value for the first handled frame" " where 100 is 1:1, 50 is half, 200 is double height") , &attw->stb_elem_refptr->att_arr_value_from[att_type_idx] , _("scale height value for the last handled frame" " where 100 is 1:1, 50 is half, 200 is double height") , &attw->stb_elem_refptr->att_arr_value_to[att_type_idx] , _("number of frames") , &attw->stb_elem_refptr->att_arr_value_dur[att_type_idx] ); } row++; { GtkWidget *gfx_table; gfx_table = gtk_table_new (1, 3, FALSE); gtk_widget_show (gfx_table); gtk_table_attach ( GTK_TABLE (table), gfx_table, 1, 8, row, row+1, GTK_FILL, 0, 0, 0); /* the graphical preview(s) of the attributes at start and end */ p_create_and_attach_pv_widgets(attw , gfx_table , 1 /* row */ , 0 /* col_start */ , 1 /* col_end */ , 0 /* img_idx */ ); label = gtk_label_new (" "); gtk_widget_show (label); gtk_table_attach ( GTK_TABLE (gfx_table), label, 1, 2, 1, 1+1, GTK_FILL, 0, 0, 0); p_create_and_attach_pv_widgets(attw , gfx_table , 1 /* row */ , 2 /* col_start */ , 3 /* col_end */ , 1 /* img_idx */ ); } row++; /* the comment label */ label = gtk_label_new (_("Comment:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 1, row, row+1); gtk_widget_show (label); /* the comment entry */ entry = gtk_entry_new (); gtk_widget_set_size_request(entry, ATTW_COMMENT_WIDTH, -1); if(attw->stb_elem_refptr) { if(attw->stb_elem_refptr->comment) { if(attw->stb_elem_refptr->comment->orig_src_line) { gtk_entry_set_text(GTK_ENTRY(entry), attw->stb_elem_refptr->comment->orig_src_line); } } } gtk_table_attach_defaults (GTK_TABLE(table), entry, 1, 8, row, row+1); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(p_attw_comment_entry_update_cb), attw); gtk_widget_show (entry); attw->comment_entry = entry; p_attw_update_sensitivity(attw); /* Show the main containers */ gtk_widget_show (main_vbox); return(dlg); } /* end gap_story_attw_properties_dialog */ /* ---------------------------------------- * gap_story_att_stb_elem_properties_dialog * ---------------------------------------- */ void gap_story_att_stb_elem_properties_dialog ( GapStbTabWidgets *tabw , GapStoryElem *stb_elem , GapStoryBoard *stb_dst) { GapStbAttrWidget *attw; gint ii; /* check if already open */ for(attw=tabw->attw; attw!=NULL; attw=(GapStbAttrWidget *)attw->next) { if ((attw->attw_prop_dialog == NULL) || (attw->stb_elem_refptr == NULL)) { /* we found a dead element (that is already closed) * reuse that element to open a new clip properties dialog window */ break; } else { if(attw->stb_elem_refptr->story_id == stb_elem->story_id) { /* Properties for the selected element already open * bring the window to front */ gtk_window_present(GTK_WINDOW(attw->attw_prop_dialog)); return ; } } } if(attw==NULL) { attw = g_new(GapStbAttrWidget ,1); attw->next = tabw->attw; tabw->attw = attw; attw->stb_elem_bck = NULL; } if(attw->stb_elem_bck) { gap_story_elem_free(&attw->stb_elem_bck); } attw->stb_elem_bck = NULL; attw->attw_prop_dialog = NULL; attw->stb_elem_refptr = stb_elem; attw->stb_refptr = stb_dst; attw->sgpp = tabw->sgpp; attw->tabw = tabw; attw->go_timertag = -1; attw->timer_full_update_request = FALSE; for (ii=0; ii < GAP_STB_ATT_GFX_ARRAY_MAX; ii++) { attw->gfx_tab[ii].auto_update = FALSE; p_init_layer_info(&attw->gfx_tab[ii].opre_info); p_init_layer_info(&attw->gfx_tab[ii].orig_info); } attw->gfx_tab[1].auto_update = FALSE; attw->close_flag = FALSE; if(stb_elem) { attw->stb_elem_bck = gap_story_elem_duplicate(stb_elem); if(stb_elem->comment) { if(stb_elem->comment->orig_src_line) { attw->stb_elem_bck->comment = gap_story_elem_duplicate(stb_elem->comment); } } } attw->attw_prop_dialog = gap_story_attw_properties_dialog(attw); if(attw->attw_prop_dialog) { gtk_widget_show(attw->attw_prop_dialog); /* initial rendering (must be done after pview widgets are realised) */ p_render_gfx(attw, 0); p_render_gfx(attw, 1); } } /* end gap_story_att_stb_elem_properties_dialog */ /* ---------------------------------- * gap_story_att_fw_properties_dialog * ---------------------------------- */ void gap_story_att_fw_properties_dialog (GapStbFrameWidget *fw) { GapStbTabWidgets *tabw; if(fw == NULL) { return; } if(fw->stb_elem_refptr == NULL) { return; } /* type check, this dialog handles only transition and fit size attributes */ if (fw->stb_elem_refptr->record_type == GAP_STBREC_ATT_TRANSITION) { tabw = (GapStbTabWidgets *)fw->tabw; if(tabw == NULL) { return; } gap_story_att_stb_elem_properties_dialog(tabw, fw->stb_elem_refptr, fw->stb_refptr); } } /* end gap_story_att_fw_properties_dialog */ gimp-gap-2.6.0+dfsg.orig/gap/gap_filter_foreach.c0000644000175000017500000005026111212030253021467 0ustar thibautthibaut/* gap_filter_foreach.c * 1997.12.23 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * - GAP_filter foreach: call any Filter (==Plugin Proc) * with varying settings for all * layers within one Image. * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 1.3.26c; 2004/03/09 hof: bugfix (gimp_destroy_params) * gimp 1.3.20b; 2003/09/20 hof: gap_db_browser_dialog new param image_id * gimp 1.3.12a; 2003/05/02 hof: merge into CVS-gimp-gap project * gimp 1.3.8a; 2002/09/21 hof: gap_lastvaldesc * gimp 1.3.4b; 2002/03/24 hof: support COMMON_ITERATOR * 1.1.29b; 2000/11/30 hof: use g_snprintf * 1.1.28a; 2000/11/05 hof: check for GIMP_PDB_SUCCESS (not for FALSE) * version 0.97.00 hof: - modul splitted (2.nd part is now gap_filter_pdb.c) * version 0.96.03 hof: - pitstop dialog provides optional backup on each step * (and skip option) * version 0.96.00 hof: - now using gap_arr_dialog.h * version 0.92.00 hof: - pitstop dialog * give user a chance to stop after interactive plugin calls * if you dont want the dialog export GAP_FILTER_PITSTOP="N" * - fixed bug in restore of layervisibility * - codegen via explicite button (in gap_debug mode) * version 0.91.01; Tue Dec 23 hof: 1.st (pre) release */ #include "config.h" /* SYTEM (UNIX) includes */ #include #include #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif /* GIMP includes */ #include "gtk/gtk.h" #include "config.h" #include "gap-intl.h" #include "libgimp/gimp.h" /* GAP includes */ #include "gap_lastvaldesc.h" #include "gap_arr_dialog.h" #include "gap_filter.h" #include "gap_filter_pdb.h" #include "gap_dbbrowser_utils.h" #include "gap_lib.h" #define GAP_DB_BROWSER_FILTERALL_HELP_ID "gap-filterall-db-browser" /* ------------------------ * global gap DEBUG switch * ------------------------ */ /* int gap_debug = 1; */ /* print debug infos */ /* int gap_debug = 0; */ /* 0: dont print debug infos */ extern int gap_debug; static void p_gdisplays_update_full(gint32 image_id); static gint p_pitstop(GimpRunMode run_mode, char *plugin_name, gint text_flag, char *step_backup_file, gint len_step_backup_file, gint32 layer_idx); static void p_visibilty_restore(gint32 image_id, gint nlayers, int *visible_tab, char *plugin_name); static gint32 p_get_indexed_layerid(gint32 image_id, gint *nlayers, gint32 idx, char *plugin_name); static int p_foreach_multilayer(GimpRunMode run_mode, gint32 image_id, const char *plugin_name, GapFiltPdbApplyMode apply_mode); static int p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id, char *canonical_plugin_name, GapFiltPdbApplyMode apply_mode); /* ------------------------ * p_gdisplays_update_full * ------------------------ */ static void p_gdisplays_update_full(gint32 image_id) { gimp_displays_flush(); } /* ------------------------ * p_pitstop * ------------------------ * return -1 on cancel, 0 .. on continue, 1 .. on skip */ static gint p_pitstop(GimpRunMode run_mode, char *plugin_name, gint text_flag, char *step_backup_file, gint len_step_backup_file, gint32 layer_idx) { const gchar *l_env; gchar *l_msg; static GapArrButtonArg l_but_argv[3]; gint l_but_argc; gint l_argc; static GapArrArg l_argv[1]; int l_continue; char l_skip_txt[32]; gap_arr_arg_init(&l_argv[0], GAP_ARR_WGT_FILESEL); l_argv[0].label_txt = _("Backup to file"); l_argv[0].entry_width = 140; /* pixel */ l_argv[0].help_txt = _("Make backup of the image after each step"); l_argv[0].text_buf_len = len_step_backup_file; l_argv[0].text_buf_ret = step_backup_file; l_but_argv[0].but_txt = _("Continue"); l_but_argv[0].but_val = 0; l_but_argv[1].but_txt = GTK_STOCK_CANCEL; l_but_argv[1].but_val = -1; g_snprintf(l_skip_txt, sizeof(l_skip_txt), _("Skip %d"), (int)layer_idx); l_but_argv[2].but_txt = l_skip_txt; l_but_argv[2].but_val = 1; l_but_argc = 2; l_argc = 0; /* optional dialog between both calls (to see the effect of 1.call) */ if(run_mode == GIMP_RUN_INTERACTIVE) { l_env = g_getenv("GAP_FILTER_PITSTOP"); if(l_env != NULL) { if((*l_env == 'N') || (*l_env == 'n')) { return 0; /* continue without question */ } } if(text_flag == 0) { l_msg = g_strdup_printf (_("2nd call of %s\n(define end-settings)"), plugin_name); } else { l_msg = g_strdup_printf (_("Non-Interactive call of %s\n(for all layers in between)"), plugin_name); l_but_argc = 3; l_argc = 1; } l_continue = gap_arr_std_dialog (_("Animated Filter Apply"), l_msg, l_argc, l_argv, l_but_argc, l_but_argv, 0); g_free (l_msg); if(l_continue < 0) return -1; else return l_continue; } return 0; /* continue without question */ } /* end p_pitstop */ /* ------------------------ * p_visibilty_restore * ------------------------ */ static void p_visibilty_restore(gint32 image_id, gint nlayers, int *visible_tab, char *plugin_name) { gint32 *l_layers_list; gint l_nlayers2; gint32 l_idx; l_layers_list = gimp_image_get_layers(image_id, &l_nlayers2); if(l_nlayers2 == nlayers) { for(l_idx = 0; l_idx < nlayers; l_idx++) { gimp_drawable_set_visible(l_layers_list[l_idx], visible_tab[l_idx]); if(gap_debug) printf("visibilty restore [%d] %d\n", (int)l_idx, (int)visible_tab[l_idx]); } p_gdisplays_update_full(image_id); } else { printf ("Error: Plugin %s has changed Nr. of layers from %d to %d\ncould not restore Layer visibilty.\n", plugin_name, (int)nlayers, (int)l_nlayers2); } g_free (l_layers_list); } /* ------------------------ * p_get_indexed_layerid * ------------------------ */ static gint32 p_get_indexed_layerid(gint32 image_id, gint *nlayers, gint32 idx, char *plugin_name) { gint32 *l_layers_list; gint32 l_layer_id; gint l_nlayers2; l_layers_list = gimp_image_get_layers(image_id, &l_nlayers2); if(l_layers_list == NULL) { printf ("Warning: cant get layers (maybe the image was closed)\n"); return -1; } if((l_nlayers2 != *nlayers) && (*nlayers > 0)) { printf ("Error: Plugin %s has changed Nr. of layers from %d to %d\nAnim Filter apply stopped.\n", plugin_name, (int)*nlayers, (int)l_nlayers2); return -1; } *nlayers = l_nlayers2; l_layer_id = l_layers_list[idx]; g_free (l_layers_list); return (l_layer_id); } /* ---------------------- * p_foreach_multilayer * ---------------------- * apply the given plugin to each layer of the image. * returns image_id of the new created multilayer image * (or -1 on error) */ static int p_foreach_multilayer(GimpRunMode run_mode, gint32 image_id, const char *plugin_name, GapFiltPdbApplyMode apply_mode) { char *canonical_plugin_name; int rc; canonical_plugin_name = gimp_canonicalize_identifier(plugin_name); rc = p_foreach_multilayer2(run_mode, image_id, canonical_plugin_name, apply_mode); g_free(canonical_plugin_name); return (rc); } /* ennd p_foreach_multilayer */ /* ---------------------- * p_foreach_multilayer2 * ---------------------- * apply the given plugin to each layer of the image. * returns image_id of the new created multilayer image * (or -1 on error) */ static int p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id, char *canonical_plugin_name, GapFiltPdbApplyMode apply_mode) { static char l_key_from[512]; static char l_key_to[512]; char *l_plugin_iterator; gint32 l_layer_id; gint32 l_top_layer; gint32 l_idx; gint l_nlayers; gdouble l_percentage, l_percentage_step; int l_rc; gint l_plugin_data_len; long l_child_pid; /* int l_status; */ int *l_visible_tab; char l_step_backup_file[120]; gint l_pit_rc; gint l_count; l_rc = 0; l_plugin_data_len = 0; l_nlayers = 0; l_visible_tab = NULL; l_step_backup_file[0] = '\0'; /* check for the Plugin */ l_rc = gap_filt_pdb_procedure_available(canonical_plugin_name, GAP_PTYP_CAN_OPERATE_ON_DRAWABLE); if(l_rc < 0) { printf("ERROR: Plugin not available or wrong type %s\n", canonical_plugin_name); return -1; } /* check for matching Iterator PluginProcedures */ l_plugin_iterator = gap_filt_pdb_get_iterator_proc(canonical_plugin_name, &l_count); l_percentage = 0.0; if(run_mode == GIMP_RUN_INTERACTIVE) { gimp_progress_init( _("Applying filter to all layers...")); } l_layer_id = p_get_indexed_layerid(image_id, &l_nlayers, 0, canonical_plugin_name); if(l_layer_id >= 0) { if(l_nlayers < 1) { printf("ERROR: need at least 1 Layers to apply plugin !\n"); } else { /* allocate a table to store the visibility attributes for each layer */ l_visible_tab = (gint*) g_malloc((l_nlayers +1) * sizeof (gint)); if(l_visible_tab == NULL) return -1; /* save the visibility of all layers */ for(l_idx = 0; l_idx < l_nlayers; l_idx++) { l_layer_id = p_get_indexed_layerid(image_id, &l_nlayers, l_idx, canonical_plugin_name); l_visible_tab[l_idx] = gimp_drawable_get_visible(l_layer_id); /* make the backround visible, all others invisible * (so the user can see the effect of the 1.st applied _FROM filter) */ gimp_drawable_set_visible(l_layer_id, (l_idx == l_nlayers - 1)); } p_gdisplays_update_full(image_id); l_percentage_step = 1.0 / l_nlayers; if((l_plugin_iterator != NULL) && (l_nlayers > 1) && (apply_mode == GAP_PAPP_VARYING_LINEAR )) { l_child_pid = 0; /* fork(); */ if(l_child_pid < 0) { printf("ERROR: fork failed !\n"); return -1; } /* if(l_child_pid != 0) */ { /* parent process: call plugin Interactive for background layer[n] */ /* if(gap_debug) printf("forked child process pid=%ld\n", l_child_pid); */ if(gap_debug) { printf("DEBUG start 1.st Interactive call (_FROM values)\n"); } l_idx = l_nlayers -1; l_layer_id = p_get_indexed_layerid(image_id, &l_nlayers, l_idx, canonical_plugin_name); if(l_layer_id < 0) { l_rc = -1; } else { if(gap_debug) printf("DEBUG: apllying %s on Layerstack %d id=%d\n", canonical_plugin_name, (int)l_idx, (int)l_layer_id); l_rc = gap_filt_pdb_call_plugin(canonical_plugin_name, image_id, l_layer_id, GIMP_RUN_INTERACTIVE); /* get values, then store with suffix "-ITER-FROM" */ l_plugin_data_len = gap_filt_pdb_get_data(canonical_plugin_name); if(l_plugin_data_len > 0) { g_snprintf(l_key_from, sizeof(l_key_from), "%s%s", canonical_plugin_name, GAP_ITER_FROM_SUFFIX); gap_filt_pdb_set_data(l_key_from, l_plugin_data_len); } else l_rc = -1; if(run_mode == GIMP_RUN_INTERACTIVE) { l_percentage += l_percentage_step; gimp_progress_update (l_percentage); } } } /* else */ if((l_rc >= 0) && (l_nlayers > 1)) { /* child process: call plugin Interactive for top layer [0] */ if(gap_debug) printf("DEBUG start 2.nd Interactive call (_TO values)\n"); /* optional dialog between both calls (to see the effect of 1.call) */ if(p_pitstop(run_mode, canonical_plugin_name, 0, l_step_backup_file, sizeof(l_step_backup_file), 0 ) < 0) { if(gap_debug) printf("TERMINATED: by pitstop dialog\n"); /* restore the visibility of all layers */ p_visibilty_restore(image_id, l_nlayers, l_visible_tab, canonical_plugin_name); g_free(l_visible_tab); return -1; } else { l_layer_id = p_get_indexed_layerid(image_id, &l_nlayers, 0, canonical_plugin_name); if(l_layer_id < 0) { l_rc = -1; } else { /* make _TO layer visible */ gimp_drawable_set_visible(l_layer_id, TRUE); p_gdisplays_update_full(image_id); if(gap_debug) printf("DEBUG: apllying %s on Layerstack 0 id=%d\n", canonical_plugin_name, (int)l_layer_id); l_rc = gap_filt_pdb_call_plugin(canonical_plugin_name, image_id, l_layer_id, GIMP_RUN_INTERACTIVE); /* get values, then store with suffix "-ITER-TO" */ l_plugin_data_len = gap_filt_pdb_get_data(canonical_plugin_name); if(l_plugin_data_len > 0) { g_snprintf(l_key_to, sizeof(l_key_to), "%s%s", canonical_plugin_name, GAP_ITER_TO_SUFFIX); gap_filt_pdb_set_data(l_key_to, l_plugin_data_len); } else l_rc = -1; if(run_mode == GIMP_RUN_INTERACTIVE) { l_percentage += l_percentage_step; gimp_progress_update (l_percentage); } /* if(gap_debug) printf("DEBUG child process exit %d\n", (int)l_rc); */ /* exit(l_rc); */ /* end of childprocess */ } } } l_top_layer = 1; /* wait until exit of childprocess */ /* waitpid(l_child_pid, &l_status, 0); */ } else { /* no iterator available, call plugin with constant values * for each layer */ /* call plugin only ONCE Interactive for background layer[n] */ l_layer_id = p_get_indexed_layerid(image_id, &l_nlayers, l_nlayers -1, canonical_plugin_name); if(l_layer_id < 0) { l_rc = -1; } else { if(gap_debug) printf("DEBUG: NO Varying, applying %s on Layer id=%d\n", canonical_plugin_name, (int)l_layer_id); l_rc = gap_filt_pdb_call_plugin(canonical_plugin_name, image_id, l_layer_id, GIMP_RUN_INTERACTIVE); l_top_layer = 0; if(run_mode == GIMP_RUN_INTERACTIVE) { l_percentage += l_percentage_step; gimp_progress_update (l_percentage); } } } if((l_rc >= 0) && (l_nlayers > 2)) { /* call plugin foreach layer inbetween * with runmode GIMP_RUN_WITH_LAST_VALS * and modify the last values */ l_pit_rc = 1; for(l_idx = l_nlayers - 2; l_idx >= l_top_layer; l_idx--) { if(l_rc < 0) break; if(l_pit_rc > 0) /* last pit_rc was a skip, so ask again for the next layer */ { l_pit_rc = p_pitstop(run_mode, canonical_plugin_name, 1, l_step_backup_file, sizeof(l_step_backup_file), l_idx ); } if(l_pit_rc < 0) { if(gap_debug) printf("TERMINATED: by pitstop dialog\n"); l_rc = -1; } l_layer_id = p_get_indexed_layerid(image_id, &l_nlayers, l_idx, canonical_plugin_name); if(l_layer_id < 0) { l_rc = -1; break; } if(gap_debug) { printf("DEBUG: applying %s on Layerstack %d id=%d total_steps:%d current_step:%d\n" , canonical_plugin_name , (int)l_idx , (int)l_layer_id , (int)l_nlayers -1 , (int)l_idx ); } if((l_plugin_iterator != NULL) && (apply_mode == GAP_PAPP_VARYING_LINEAR )) { /* call plugin-specific iterator (or the common iterator), to modify * the plugin's last_values */ if(!gap_filter_iterator_call(l_plugin_iterator , l_nlayers -1 /* total steps */ , (gdouble)l_idx /* current step */ , canonical_plugin_name , l_plugin_data_len )) { l_rc = -1; } } if(l_rc < 0) break; if(l_pit_rc == 0) /* 0 == continue without further dialogs */ { /* call the plugin itself with runmode RUN_WITH_LAST_VALUES */ l_rc = gap_filt_pdb_call_plugin(canonical_plugin_name, image_id, l_layer_id, GIMP_RUN_WITH_LAST_VALS); /* check if to save each step to backup file */ if((l_step_backup_file[0] != '\0') && (l_step_backup_file[0] != ' ')) { printf ("Saving image to backupfile:%s step = %d\n", l_step_backup_file, (int)l_idx); gap_filt_pdb_save_xcf(image_id, l_step_backup_file); } } if(run_mode == GIMP_RUN_INTERACTIVE) { l_percentage += l_percentage_step; gimp_progress_update (l_percentage); } } /* end for */ } /* restore the visibility of all layers */ p_visibilty_restore(image_id, l_nlayers, l_visible_tab, canonical_plugin_name); g_free(l_visible_tab); } } if(l_plugin_iterator != NULL) g_free(l_plugin_iterator); return l_rc; } /* end p_foreach_multilayer2 */ /* ------------------------ * gap_proc_anim_apply * ------------------------ */ gint gap_proc_anim_apply(GimpRunMode run_mode, gint32 image_id, char *plugin_name , GapFiltPdbApplyMode apply_mode) { GapDbBrowserResult l_browser_result; if(run_mode == GIMP_RUN_INTERACTIVE) { if(gap_db_browser_dialog( _("Select Filter for Animated Apply"), _("Apply Constant"), _("Apply Varying"), gap_filt_pdb_constraint_proc, gap_filt_pdb_constraint_proc_sel1, gap_filt_pdb_constraint_proc_sel2, &l_browser_result, image_id, GAP_DB_BROWSER_FILTERALL_HELP_ID) < 0) { if(gap_debug) printf("DEBUG: gap_db_browser_dialog cancelled\n"); return -1; } strcpy(plugin_name, l_browser_result.selected_proc_name); if(l_browser_result.button_nr == 1) apply_mode = GAP_PAPP_VARYING_LINEAR; if(gap_debug) printf("DEBUG: gap_db_browser_dialog SELECTED:%s\n", plugin_name); } return(p_foreach_multilayer(run_mode, image_id, plugin_name, apply_mode )); } gimp-gap-2.6.0+dfsg.orig/gap/gap_drawable_vref_parasite.h0000644000175000017500000000423111212030253023207 0ustar thibautthibaut/* 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 * * * 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 gimp-gap-2.6.0+dfsg.orig/gap/gap_player_dialog.h0000644000175000017500000000422411212030253021331 0ustar thibautthibaut/* gap_player_dialog.h * * This module handles GAP video playback * based on thumbnail files */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.25c; 2004/01/26 hof: support for storyboard level1 playback * version 1.3.14c; 2003/06/09 hof: created */ #ifndef _GAP_PLAYER_DIALOG_H #define _GAP_PLAYER_DIALOG_H #include "libgimp/gimp.h" #include "gap_player_main.h" void gap_player_dlg_create(GapPlayerMainGlobalParams *gpp); void gap_player_dlg_cleanup(GapPlayerMainGlobalParams *gpp); void gap_player_dlg_restart(GapPlayerMainGlobalParams *gpp , gboolean autostart , gint32 image_id , char *imagename , gint32 imagewidth , gint32 imageheight , GapStoryBoard *stb_ptr , gint32 begin_frame , gint32 end_frame , gboolean play_selection_only , gint32 seltrack , gdouble delace , const char *preferred_decoder , gboolean force_open_as_video , gint32 flip_request , gint32 flip_status , gint32 stb_in_track ); void gap_player_dlg_playback_dialog(GapPlayerMainGlobalParams *gpp); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_navigator_dialog.c0000644000175000017500000043014511212030253022027 0ustar thibautthibaut/* gap_navigator_dialog.c * by hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains the GAP Video Navigator dialog Window * that provides a VCR-GUI for the GAP basic navigation functions. * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 2.1.0a; 2005/03/12 hof: added radio buttons for active layer tracking * gimp 2.1.0a; 2004/11/04 hof: replaced deprecated option_menu by gimp_image_combo_box_new * gimp 2.1.0a; 2004/06/26 hof: #144649 use NULL for the default cursor as active_cursor * gimp 1.3.26a; 2004/01/30 hof: navi_pviews_reset: use the procedure gap_pview_drop_repaint_buffers rather than g_free the pixmap * gimp 1.3.25a; 2004/01/21 hof: gap_thumb_file_load_thumbnail now returns th_data with th_bpp == 4 * (the flatten capabilities were removed) * gimp 1.3.24a; 2004/01/17 hof: bugfix: call of plug_in_gap_range_to_multilayer needs regionselect_mode * use faster procedure gap_thumb_file_load_thumbnail to load thumbnaildata * gimp 1.3.23a; 2003/11/26 hof: follow API changes for gimp_dialog_new * gimp 1.3.20d; 2003/10/18 hof: sourcecode cleanup, remove close button * gimp 1.3.19a; 2003/09/06 hof: call plug_in_gap_videoframes_player with dummy audioparameters * gimp 1.3.18b; 2003/08/27 hof: fixed waiting cursor for long running ops * gimp 1.3.17a; 2003/07/29 hof: param types GimpPlugInInfo.run procedure * gimp 1.3.16c; 2003/07/12 hof: bugfixes (vscale slider reflects pagesize), del_button,dup_button sensitivity * gimp 1.3.16b; 2003/07/02 hof: selection highlight bugfix (using gtk_widget_modify_bg) * gimp 1.3.16a; 2003/06/29 hof: redesign: replaced scrolled_window by table that fits the visible window height * and a vertical scale to manage scrolling. * with this approach it is now possible to handle * all frames of an animation without a limit. * HIGHLIGHTING of the selected frame_widgets does not work yet. * * Overview about the GAP Navigator Redesign * * - use gap_pview_da (drawing_area based) render procedures (instead of deprecated gtk_preview) * - dyn_table is a gtk_table that has 1 column, and 1 upto MAX_DYN_ROWS. * - dyn_table shows only a subset of thumbnails beginning at dyn_topframenr * frame_widget_tab[0] is always attached to the 1.st dyn_table row. * if dyn_rows > 1 * then frame_widget_tab[1] is attached to 2.nd dyn_table row and so on... * * - with the adjustment (vscale) dyn_adj the user can set dyn_topframenr * to scroll the displayed framerange. * at changes of dyn_topframenr all visible thumbnails are updated as follows: * * * frame_widget_tab[0] is loaded with thumbnail [dyn_topframenr] * frame_widget_tab[1] is loaded with thumbnail [dyn_topframenr+1] * ... * * frame_widget_tab[dyn_rows-1] is loaded with thumbnail [dyn_topframenr + (dyn_rows - 1)] * * * - dyn_table grows and shrinks at user window resize operations * on significant height grow events: * additional rows are added to dyn_table (using gtk_table_resize) * and more elements from frame_widget_tab are attached to * the newly added row(s) * * on significant height shrink events: * rows are removed from dyn_table (using gtk_table_resize) * detach is done by destroying the attached frame_widgets * before the row is removed. * * - Selections are handled completely by this module in the SelectedRange List * this list is sorted ascending by "from" numbers (framenumber). * * gimp 1.3.15a; 2003/06/21 hof: gap_timeconv_framenr_to_timestr, use plug_in_gap_videoframes_player for playback * ops_button_pressed_callback must have returnvalue FALSE * (this enables other handlers -- ops_button_extended_callback -- to run afterwards * gimp 1.3.14b; 2003/06/03 hof: added gap_stock_init * ops_button_box_new: now using stock buttons instead of xpm pixmap data * gimp 1.3.14a; 2003/05/27 hof: replaced old workaround procedure readXVThumb by legal API gimp_file_load_thumbnail * replaced scale widgets by spinbuttons * gimp 1.3.12a; 2003/05/03 hof: merge into CVS-gimp-gap project * 6digit framenumbers, replace gimp_help_init by _gimp_help_init * gimp 1.3.5a; 2002/04/21 hof: handle changing image_id of the active_image (navi_reload_ainfo) * gimp 1.3.4; 2002/03/12 hof: STARTED port to gtk+2.0.0 * still needs GTK_DISABLE_DEPRECATED (bacause port is not complete) * version 1.1.29b; 2000.11.30 hof: new e-mail adress * version 1.1.20a; 2000.04.25 hof: copy/cut/paste menu * version 1.1.14a; 2000.01.08 hof: 1st release */ /* SYTEM (UNIX) includes */ #include #include #include #include #include #include #include #include /* GIMP includes */ #include #include "config.h" #include "gap-intl.h" #include #include #include "gap_libgapbase.h" #include "gap_stock.h" #include "gap_timeconv.h" #include "gap_navi_activtable.h" #include "gap_pview_da.h" #include "gap_arr_dialog.h" #include "gap_thumbnail.h" #include "gap_image.h" #define PLUGIN_NAME "plug_in_gap_navigator" #define PLUGIN_HELP_ID "plug-in-gap-navigator" #define NAVI_CHECK_SIZE 4 #define MAX_DYN_ROWS 400 #define KEY_NAVI_DIALOG_TO_FRONT "plug_in_gap_navigator_to_front" /* * OpsButton code was inspired by gimp-1.2 core code, * but was changed for gap_navigator_dialog use and ported to gtk+2.2 * switched from GtkSignalFunc to private OpsButtonFunc */ typedef void (*OpsButtonFunc) (GtkWidget *widget, gpointer data); #define OPS_BUTTON_FUNC(f) ((OpsButtonFunc) f) /* --------------------------------------- start copy of gimp-1.1.14/app/ops_buttons.h */ #ifndef __OPS_BUTTONS_H__ #define __OPS_BUTTONS_H__ typedef enum { OPS_BUTTON_MODIFIER_NONE, OPS_BUTTON_MODIFIER_SHIFT, OPS_BUTTON_MODIFIER_CTRL, OPS_BUTTON_MODIFIER_ALT, OPS_BUTTON_MODIFIER_SHIFT_CTRL, OPS_BUTTON_MODIFIER_LAST } OpsButtonModifier; typedef enum { OPS_BUTTON_NORMAL, OPS_BUTTON_RADIO } OpsButtonType; typedef struct _OpsButton OpsButton; struct _OpsButton { const char *stock_id; /* STOCK id for the stock button */ OpsButtonFunc callback; /* callback function */ OpsButtonFunc *ext_callbacks; /* callback functions when * modifiers are pressed */ gchar *tooltip; gchar *private_tip; GtkWidget *widget; /* the button widget */ gint modifier; }; /* Function declarations */ GtkWidget * ops_button_box_new (GtkWidget *parent, OpsButton *ops_button, OpsButtonType ops_type); #endif /* __OPS_BUTTONS_H__ */ /* --------------------------------------- end copy of gimp-1.1.14/app/ops_buttons.h */ /* GAP includes */ #include "gap_lib.h" #include "gap_pdb_calls.h" #include "gap_vin.h" /* some definitions used in all dialogs */ #define LIST_WIDTH 200 #define LIST_HEIGHT 150 #define PREVIEW_BPP 3 #define THUMBNAIL_BPP 3 #define MIX_CHANNEL(b, a, m) (((a * m) + (b * (255 - m))) / 255) #define PREVIEW_BG_GRAY1 80 #define PREVIEW_BG_GRAY2 180 #define NUPD_IMAGE_MENU 1 #define NUPD_THUMBFILE_TIMESTAMP 2 #define NUPD_FRAME_NR_CHANGED 4 #define NUPD_PREV_LIST 8 #define NUPD_PREV_LIST_ICONS 16 #define NUPD_ALL 0xffffffff; typedef struct _OpenFrameImages OpenFrameImages; typedef struct _SelectedRange SelectedRange; struct _OpenFrameImages{ gint32 image_id; gint32 frame_nr; OpenFrameImages *next; }; struct _SelectedRange { gint32 from; gint32 to; SelectedRange *next; SelectedRange *prev; }; typedef struct FrameWidget { GtkWidget *event_box; GtkWidget *vbox; GtkWidget *hbox; GtkWidget *number_label; /* for the 6-digit framenumber */ GtkWidget *time_label; GapPView *pv_ptr; /* for gap preview rendering based on drawing_area */ gint32 image_id; gint32 frame_nr; gint width; gint height; /* state information */ time_t frame_timestamp; char *frame_filename; } FrameWidget; typedef struct NaviDialog { FrameWidget frame_widget_tab[MAX_DYN_ROWS]; gint32 fw_tab_used_count; /* how much elements are initialized in frame_widget_tab */ GtkWidget *vbox; GtkWidget *hbox; GtkWidget *dyn_frame; /* table with */ GtkWidget *dyn_table; /* table with */ GtkObject *dyn_adj; gint32 dyn_topframenr; gint32 dyn_rows; gint32 prev_selected_framnr; SelectedRange *sel_range_list; gboolean in_dyn_table_sizeinit; gint tooltip_on; GtkWidget *shell; GtkWidget *preserve_trans; GtkWidget *framerate_box; GtkWidget *timezoom_box; GtkWidget *image_combo; GtkWidget *image_combo_hbox; GtkWidget *ops_menu; GtkWidget *copy_menu_item; GtkWidget *cut_menu_item; GtkWidget *pastea_menu_item; GtkWidget *pasteb_menu_item; GtkWidget *paster_menu_item; GtkWidget *clrpaste_menu_item; GtkWidget *sel_all_menu_item; GtkWidget *sel_none_menu_item; GtkAccelGroup *accel_group; GtkObject *framerate_adj; GtkObject *timezoom_adj; GtkWidget *framerange_number_label; GtkWidget *del_button; GtkWidget *dup_button; gint waiting_cursor; GdkCursor *cursor_wait; GdkCursor *cursor_acitve; gint32 paste_at_frame; /* -1: use current frame */ gdouble ratio; gdouble preview_size; gint image_width, image_height; gint gimage_width, gimage_height; /* state information */ gint32 active_imageid; gint32 any_imageid; GapAnimInfo *ainfo_ptr; GapVinVideoInfo *vin_ptr; int timer; int cycle_time; OpenFrameImages *OpenFrameImagesList; int OpenFrameImagesCount; gint32 item_height; GtkWidget *acl_trace_off_toggle; GtkWidget *acl_trace_by_name_toggle; GtkWidget *acl_trace_by_pos_toggle; } NaviDialog; /* ----------------------- * procedure declarations * ----------------------- */ static void p_set_data_to_front_request(gboolean dialog_to_front_request); static void p_check_dialog_to_front_request(void); int gap_navigator(gint32 image_id); static void navi_preview_extents (void); static void frames_dialog_flush (void); static void frames_dialog_update (gint32 image_id); static void frame_widget_preview_redraw (FrameWidget *); static void navi_vid_copy_and_cut(gint cut_flag); static gboolean navi_images_menu_constrain (gint32 image_id, gpointer data); static void navi_images_menu_callback (GtkWidget *widget, gpointer data); static void navi_update_after_goto(void); static void navi_ops_menu_set_sensitive(void); static void navi_ops_buttons_set_sensitive(void); static void navi_pviews_reset(void); static void navi_dialog_thumb_update_callback(GtkWidget *w, gpointer data); static void navi_dialog_thumb_updateall_callback(GtkWidget *w, gpointer data); static void navi_dialog_vcr_play_callback(GtkWidget *w, gpointer data); static void navi_dialog_vcr_play_layeranim_callback(GtkWidget *w, gpointer data); static void navi_dialog_frames_duplicate_frame_callback(GtkWidget *w, gpointer data); static void navi_dialog_frames_delete_frame_callback(GtkWidget *w, gpointer data); static void navi_dialog_vcr_goto_first_callback(GtkWidget *w, gpointer data); static void navi_dialog_vcr_goto_prev_callback(GtkWidget *w, gpointer data); static void navi_dialog_vcr_goto_prevblock_callback(GtkWidget *w, gpointer data); static void navi_dialog_vcr_goto_next_callback(GtkWidget *w, gpointer data); static void navi_dialog_vcr_goto_nextblock_callback(GtkWidget *w, gpointer data); static void navi_dialog_vcr_goto_last_callback(GtkWidget *w, gpointer data); static void navi_framerate_spinbutton_update(GtkAdjustment *w, gpointer data); static void navi_timezoom_spinbutton_update(GtkAdjustment *w, gpointer data); static gboolean frame_widget_preview_events (GtkWidget *, GdkEvent *, gpointer); static gint navi_dialog_poll(GtkWidget *w, gpointer data); static void navi_dialog_update(gint32 update_flag); static void navi_scroll_to_current_frame_nr(void); static gboolean navi_scroll_event_cb ( GtkWidget *widget , GdkEventScroll *sevent , NaviDialog *naviD ); static gint32 navi_get_preview_size(void); static void navi_frames_timing_update (void); static void navi_frame_widget_time_label_update(FrameWidget *fw); static void navi_dialog_tooltips(void); static void navi_set_waiting_cursor(void); static void navi_set_active_cursor(void); static SelectedRange * navi_get_last_range_list(SelectedRange *sel_range_list); static void navi_debug_print_sel_range(void); static void navi_drop_sel_range_list(void); static void navi_drop_sel_range_list2(void); static void navi_drop_sel_range_elem(SelectedRange *range_item); static SelectedRange * navi_findframe_in_sel_range(gint32 framenr); static void navi_add_sel_range_list(gint32 framenr_from, gint32 framenr_to); static void navi_sel_normal(gint32 framenr); static void navi_sel_ctrl(gint32 framenr); static void navi_sel_shift(gint32 framenr); static void navi_dyn_frame_size_allocate (GtkWidget *widget, GtkAllocation *allocation, gpointer user_data); static void navi_frame_widget_replace2(FrameWidget *fw); static void navi_frame_widget_replace(gint32 image_id, gint32 frame_nr, gint32 dyn_rowindex); static void navi_refresh_dyn_table(gint32 l_frame_nr); static void navi_dyn_adj_changed_callback(GtkWidget *wgt, gpointer data); static void navi_dyn_adj_set_pos(void); static void navi_dyn_adj_set_limits(void); static void navi_frame_widget_init_empty (FrameWidget *fw); static int navi_dyn_table_set_size(gint win_height); static void p_set_acl_tracking_radio_buttons(NaviDialog *naviD); static void p_set_acl_tracking_mode(NaviDialog *naviD, gint32 acl_tracking_mode); static void p_acl_tracking_off_callback(GtkWidget *widget, NaviDialog *naviD); static void p_acl_tracking_by_name_callback(GtkWidget *widget, NaviDialog *naviD); static void p_acl_tracking_by_pos_callback(GtkWidget *widget, NaviDialog *naviD); /* ----------------------- * Local data * ----------------------- */ static NaviDialog *naviD = NULL; static gint suspend_gimage_notify = 0; static gint32 global_old_active_imageid = -1; /* the ops buttons */ static OpsButtonFunc navi_dialog_update_ext_callbacks[] = { OPS_BUTTON_FUNC (navi_dialog_thumb_updateall_callback), NULL, NULL, NULL }; static OpsButtonFunc navi_dialog_vcr_play_ext_callbacks[] = { OPS_BUTTON_FUNC (navi_dialog_vcr_play_layeranim_callback), NULL, NULL, NULL }; static OpsButtonFunc navi_dialog_vcr_goto_prev_ext_callbacks[] = { OPS_BUTTON_FUNC (navi_dialog_vcr_goto_prevblock_callback), NULL, NULL, NULL }; static OpsButtonFunc navi_dialog_vcr_goto_next_ext_callbacks[] = { OPS_BUTTON_FUNC (navi_dialog_vcr_goto_nextblock_callback), NULL, NULL, NULL }; static OpsButton frames_ops_buttons[] = { { GAP_STOCK_PLAY, OPS_BUTTON_FUNC (navi_dialog_vcr_play_callback), navi_dialog_vcr_play_ext_callbacks, N_("Playback\n" "SHIFT converts the selected frames to temporary image, " "and does layeranimation playback on it."), "#playback", NULL, 0 }, { GAP_STOCK_UPDATE, OPS_BUTTON_FUNC (navi_dialog_thumb_update_callback), navi_dialog_update_ext_callbacks, N_("Smart update thumbnails\n" "SHIFT forces thumbnail update for all frames"), "#update", NULL, 0 }, { GIMP_STOCK_DUPLICATE, OPS_BUTTON_FUNC (navi_dialog_frames_duplicate_frame_callback), NULL, N_("Duplicate selected frames"), "#duplicate", NULL, 0 }, { GTK_STOCK_DELETE, OPS_BUTTON_FUNC (navi_dialog_frames_delete_frame_callback), NULL, N_("Delete selected frames"), "#delete", NULL, 0 }, { NULL, NULL, NULL, NULL, NULL, NULL, 0 } }; static OpsButton vcr_ops_buttons[] = { { GTK_STOCK_GOTO_FIRST, OPS_BUTTON_FUNC (navi_dialog_vcr_goto_first_callback), NULL, N_("Goto first frame"), "#goto_first", NULL, 0 }, { GTK_STOCK_GO_BACK, OPS_BUTTON_FUNC (navi_dialog_vcr_goto_prev_callback), navi_dialog_vcr_goto_prev_ext_callbacks, N_("Goto prev frame\n" "SHIFT use timezoom stepsize"), "#goto_previous", NULL, 0 }, { GTK_STOCK_GO_FORWARD, OPS_BUTTON_FUNC (navi_dialog_vcr_goto_next_callback), navi_dialog_vcr_goto_next_ext_callbacks, N_("Goto next frame\n" "SHIFT use timezoom stepsize"), "#goto_next", NULL, 0 }, { GTK_STOCK_GOTO_LAST, OPS_BUTTON_FUNC (navi_dialog_vcr_goto_last_callback), NULL, N_("Goto last frame"), "#goto_last", NULL, 0 }, { NULL, NULL, NULL, NULL, NULL, NULL, 0 } }; /* ------------------------ * gap DEBUG switch * ------------------------ */ /* int gap_debug = 1; */ /* print debug infos */ /* int gap_debug = 0; */ /* 0: dont print debug infos */ int gap_debug = 0; static void query(void); static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; /* ------------------------ * MAIN, query & run * ------------------------ */ MAIN () /* --------------------------------- * query * --------------------------------- */ static void query () { static GimpParamDef args_navigator[] = { {GIMP_PDB_INT32, "run_mode", "Interactive"}, {GIMP_PDB_IMAGE, "image", "(unused)"}, {GIMP_PDB_DRAWABLE, "drawable", "(unused)"}, }; static GimpParamDef *return_vals = NULL; static int nreturn_vals = 0; gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); gimp_install_procedure(PLUGIN_NAME, "GAP video navigator dialog", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("VCR Navigator..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, G_N_ELEMENTS (args_navigator), nreturn_vals, args_navigator, return_vals); // gimp_plugin_menu_branch_register("", "Video"); gimp_plugin_menu_register (PLUGIN_NAME, N_("/Video/")); } /* end query */ /* --------------------------------- * run * --------------------------------- */ static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals) { gint32 l_active_image; const gchar *l_env; static GimpParam values[2]; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; gint32 nr; pid_t l_navid_pid; gint32 l_rc; *nreturn_vals = 1; *return_vals = values; nr = 0; l_rc = 0; INIT_I18N(); l_env = g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } run_mode = param[0].data.d_int32; l_active_image = -1; if(gap_debug) printf("\n\ngap_navigator: debug name = %s\n", name); l_active_image = param[1].data.d_image; p_set_data_to_front_request(TRUE); /* check for other Video navigator Dialog Process */ if (sizeof(pid_t) == gimp_get_data_size(PLUGIN_NAME)) { gimp_get_data(PLUGIN_NAME, &l_navid_pid); /* note that the check gap_base_is_pid_alive implementation does not work on WINDOWS */ #ifndef G_OS_WIN32 if(l_navid_pid != 0) { if (gap_base_is_pid_alive(l_navid_pid)) { gap_arr_msg_win(GIMP_RUN_INTERACTIVE, _("Cant open two or more video navigator windows.")); l_rc = -1; } } #endif } if(l_rc == 0) { /* set pid data when navigator is running */ l_navid_pid = gap_base_getpid(); gimp_set_data(PLUGIN_NAME, &l_navid_pid, sizeof(pid_t)); if (strcmp (name, PLUGIN_NAME) == 0) { if (run_mode != GIMP_RUN_INTERACTIVE) { status = GIMP_PDB_CALLING_ERROR; } if (status == GIMP_PDB_SUCCESS) { l_rc = gap_navigator(l_active_image); } } /* set pid data to 0 when navigator stops */ l_navid_pid = 0; gimp_set_data(PLUGIN_NAME, &l_navid_pid, sizeof(pid_t)); } /* ---------- return handling --------- */ if(l_rc < 0) { status = GIMP_PDB_EXECUTION_ERROR; } values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; } /* end run */ /* -------------------------- * navi_delete_confirm_dialog * -------------------------- */ static gboolean navi_delete_confirm_dialog(gint32 del_cnt) { gchar *msg_txt; gboolean l_rc; msg_txt = g_strdup_printf(_("The selected %d frame(s) will be deleted.\n" "There will be no undo for this operation\n") ,(int)del_cnt ); l_rc = gap_arr_confirm_dialog(msg_txt , _("Confirm Frame Delete") /* title_txt */ , _("Confirm Frame Delete") /* frame_txt */ ); g_free(msg_txt); return (l_rc); } /* end navi_delete_confirm_dialog */ /* --------------------------------- * navi_constrain_dyn_topframenr * --------------------------------- */ static gint32 navi_constrain_dyn_topframenr(gint32 frame_nr) { gint32 l_frame_nr; l_frame_nr = (frame_nr - naviD->ainfo_ptr->first_frame_nr) / naviD->vin_ptr->timezoom; l_frame_nr = (l_frame_nr * naviD->vin_ptr->timezoom)+ naviD->ainfo_ptr->first_frame_nr; l_frame_nr = CLAMP(l_frame_nr , naviD->ainfo_ptr->first_frame_nr , MAX(naviD->ainfo_ptr->first_frame_nr , (1 + naviD->ainfo_ptr->last_frame_nr - naviD->dyn_rows)) ); return (l_frame_nr); } /* end navi_constrain_dyn_topframenr */ /* --------------------------------- * the navigator callback procedures * --------------------------------- */ static void edit_copy_callback (GtkWidget *w, gpointer client_data) { if(gap_debug) printf("edit_copy_callback\n"); navi_vid_copy_and_cut(FALSE /* cut_flag */); } static void edit_cut_callback (GtkWidget *w, gpointer client_data) { if(gap_debug) printf("edit_cut_callback\n"); navi_vid_copy_and_cut(TRUE /* cut_flag */); } /* --------------------------------- * p_set_data_to_front_request * --------------------------------- */ static void p_set_data_to_front_request(gboolean dialog_to_front_request) { gimp_set_data(KEY_NAVI_DIALOG_TO_FRONT, &dialog_to_front_request, sizeof (gboolean)); } /* end p_set_data_to_front_request */ /* --------------------------------- * p_check_dialog_to_front_request * --------------------------------- * check for request to present the (already open) naviagtor dialog * window (in front of screen) * typically used on attempt to start a 2nd instance (which is not allowed) */ static void p_check_dialog_to_front_request(void) { gint data_size; if (naviD == NULL) { return; } if (naviD->shell == NULL) { return; } if (GTK_WIDGET(naviD->shell)->window == NULL) { return; } data_size = gimp_get_data_size(KEY_NAVI_DIALOG_TO_FRONT); if (data_size == sizeof (gboolean)) { gboolean dialog_to_front_request; gimp_get_data(KEY_NAVI_DIALOG_TO_FRONT, &dialog_to_front_request); if(dialog_to_front_request == TRUE) { gtk_window_present(GTK_WINDOW(naviD->shell)); p_set_data_to_front_request(FALSE); } } } /* end p_check_dialog_to_front_request */ /* --------------------------------- * p_edit_paste_call * --------------------------------- */ static void p_edit_paste_call(gint32 paste_mode) { GimpParam *return_vals; int nreturn_vals; gint32 dummy_layer_id; if(naviD->paste_at_frame < 0) { return; /* invalid frame_nr do not paste here */ } if(gap_debug) { printf("p_edit_paste_call: paste_at_frame:%d active_image_id:%d\n" , (int)naviD->paste_at_frame , (int)naviD->active_imageid ); } /* goto the first selected frame */ dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_goto", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_INT32, naviD->paste_at_frame, GIMP_PDB_END); if (return_vals[0].data.d_status != GIMP_PDB_SUCCESS) { gimp_destroy_params(return_vals, nreturn_vals); gap_arr_msg_win(GIMP_RUN_INTERACTIVE ,_("Error while positioning to frame. Video paste operation failed") ); return; } naviD->active_imageid = return_vals[1].data.d_image; gimp_destroy_params(return_vals, nreturn_vals); dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_video_edit_paste", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_INT32, paste_mode, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { naviD->active_imageid = return_vals[1].data.d_image; } else { gap_arr_msg_win(GIMP_RUN_INTERACTIVE, _("Video paste operaton failed")); } gimp_destroy_params(return_vals, nreturn_vals); navi_update_after_goto(); } /* end p_edit_paste_call */ static void edit_pasteb_callback (GtkWidget *w, gpointer client_data) { p_edit_paste_call(GAP_VID_PASTE_INSERT_BEFORE); } static void edit_pastea_callback (GtkWidget *w, gpointer client_data) { p_edit_paste_call(GAP_VID_PASTE_INSERT_AFTER); } static void edit_paster_callback (GtkWidget *w, gpointer client_data) { p_edit_paste_call(GAP_VID_PASTE_REPLACE); } static void edit_clrpaste_callback (GtkWidget *w, gpointer client_data) { GimpParam *return_vals; int nreturn_vals; gint32 dummy_layer_id; if(gap_debug) printf("edit_clrpaste_callback\n"); dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_video_edit_clear", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_END); gimp_destroy_params(return_vals, nreturn_vals); } static void navi_sel_all_callback (GtkWidget *w, gpointer client_data) { navi_drop_sel_range_list(); navi_add_sel_range_list(naviD->ainfo_ptr->first_frame_nr ,naviD->ainfo_ptr->last_frame_nr); navi_debug_print_sel_range(); navi_ops_buttons_set_sensitive(); navi_frames_timing_update(); } static void navi_sel_none_callback (GtkWidget *w, gpointer client_data) { navi_drop_sel_range_list(); navi_debug_print_sel_range(); navi_ops_buttons_set_sensitive(); navi_frames_timing_update(); } /* --------------------------------- * navi_vid_copy_and_cut * --------------------------------- * perform copy (or cut) operations * and free the selection list */ void navi_vid_copy_and_cut(gint cut_flag) { SelectedRange *range_list; SelectedRange *range_list2; GimpParam *return_vals; int nreturn_vals; gboolean vid_copy_ok; gint32 dummy_layer_id; vid_copy_ok = TRUE; if(gap_debug) printf("navi_dialog_vid_copy_callback\n"); if(naviD->sel_range_list) { navi_set_waiting_cursor(); gap_vid_edit_clear(); range_list = naviD->sel_range_list; while(range_list) { /* Note: process the ranges from low frame_nummers * upto high frame_numbers. * (the sel_range_list is sorted by ascending from-framenumbers at creation * the lowest range the 1st list element in the list) */ if(gap_debug) printf("Copy Range from:%d to:%d\n" ,(int)range_list->from ,(int)range_list->to ); dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_video_edit_copy", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_INT32, range_list->from, GIMP_PDB_INT32, range_list->to, GIMP_PDB_END); if (return_vals[0].data.d_status != GIMP_PDB_SUCCESS) { vid_copy_ok = FALSE; } gimp_destroy_params(return_vals, nreturn_vals); if(!vid_copy_ok) { gap_arr_msg_win(GIMP_RUN_INTERACTIVE, _("Video copy (or cut) operation failed")); break; } range_list = range_list->next; } if((cut_flag) && (vid_copy_ok)) { range_list2 = navi_get_last_range_list(naviD->sel_range_list); while(range_list2) { /* for delete we process the ranges from high frame_nummers * downto low frame_numbers. * (the sel_range_list is sorted by ascending from-framenumbers at creation * therefore we step from the last range liste elem backto the 1st * using the prev pointers in the list) */ if(gap_debug) printf("Delete Range from:%d to:%d\n" ,(int)range_list2->from ,(int)range_list2->to ); dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_goto", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_INT32, range_list2->from, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { naviD->active_imageid = return_vals[1].data.d_image; gimp_destroy_params(return_vals, nreturn_vals); dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_del", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_INT32, 1 + (range_list2->to - range_list2->from), /* number of frames to delete */ GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { naviD->active_imageid = return_vals[1].data.d_image; } gimp_destroy_params(return_vals, nreturn_vals); } else { gimp_destroy_params(return_vals, nreturn_vals); gap_arr_msg_win(GIMP_RUN_INTERACTIVE, _("Video cut operation failed")); } range_list2 = range_list2->prev; } } /* selection is cleared after copy/cut operations */ navi_drop_sel_range_list(); navi_update_after_goto(); } } /* end navi_vid_copy_and_cut */ /* --------------------------------- * navi_get_preview_size * --------------------------------- */ static gint32 navi_get_preview_size(void) { char *value_string; gint32 preview_size; preview_size = 32; /* default preview size if nothing is configured */ value_string = gimp_gimprc_query("video-preview-size"); if(value_string == NULL) { value_string = gimp_gimprc_query("layer-preview-size"); } if(value_string) { if(gap_debug) printf("navi_get_preview_size value_str:%s:\n", value_string); if (strcmp (value_string, "none") == 0) preview_size = 0; else if (strcmp (value_string, "tiny") == 0) preview_size = 24; else if (strcmp (value_string, "small") == 0) preview_size = 32; else if (strcmp (value_string, "medium") == 0) preview_size = 48; else if (strcmp (value_string, "large") == 0) preview_size = 64; else if (strcmp (value_string, "extra-large") == 0) preview_size = 128; else if (strcmp (value_string, "huge") == 0) preview_size = 160; else if (strcmp (value_string, "enormous") == 0) preview_size = 192; else if (strcmp (value_string, "gigantic") == 0) preview_size = 256; else preview_size = atol(value_string); g_free(value_string); } else { if(gap_debug) printf("navi_get_preview_size value_str is NULL\n"); } return (preview_size); } /* navi_get_preview_size */ /* --------------------------------- * navi_check_exist_first_and_last * --------------------------------- */ static gint navi_check_exist_first_and_last(GapAnimInfo *ainfo_ptr) { char *l_fname; l_fname = gap_lib_alloc_fname(ainfo_ptr->basename, ainfo_ptr->last_frame_nr, ainfo_ptr->extension); if (!gap_lib_file_exists(l_fname)) { g_free(l_fname); return(FALSE); } g_free(l_fname); l_fname = gap_lib_alloc_fname(ainfo_ptr->basename, ainfo_ptr->first_frame_nr, ainfo_ptr->extension); if (!gap_lib_file_exists(l_fname)) { g_free(l_fname); return(FALSE); } g_free(l_fname); l_fname = gap_lib_alloc_fname(ainfo_ptr->basename, ainfo_ptr->last_frame_nr+1, ainfo_ptr->extension); if (gap_lib_file_exists(l_fname)) { g_free(l_fname); return(FALSE); } g_free(l_fname); l_fname = gap_lib_alloc_fname(ainfo_ptr->basename, ainfo_ptr->first_frame_nr-1, ainfo_ptr->extension); if (gap_lib_file_exists(l_fname)) { g_free(l_fname); return(FALSE); } g_free(l_fname); return(TRUE); } /* end navi_check_exist_first_and_last */ /* --------------------------------- * navi_get_ainfo * --------------------------------- */ static GapAnimInfo * navi_get_ainfo(gint32 image_id, GapAnimInfo *old_ainfo_ptr) { GapAnimInfo *ainfo_ptr; ainfo_ptr = gap_lib_alloc_ainfo(image_id, GIMP_RUN_NONINTERACTIVE); if(ainfo_ptr) { if(old_ainfo_ptr) { if((old_ainfo_ptr->image_id == image_id) && (strcmp(old_ainfo_ptr->basename, ainfo_ptr->basename) == 0)) { if(navi_check_exist_first_and_last(old_ainfo_ptr)) { /* - image_id and name have not changed, * - first and last frame still exist * and are still first and last frame * In that case we can reuse first and last frame_nr * without scanning the directory for frames */ ainfo_ptr->first_frame_nr = old_ainfo_ptr->first_frame_nr; ainfo_ptr->last_frame_nr = old_ainfo_ptr->last_frame_nr; ainfo_ptr->frame_cnt = old_ainfo_ptr->frame_cnt; return(ainfo_ptr); } } } gap_lib_dir_ainfo(ainfo_ptr); } navi_dyn_adj_set_limits(); return(ainfo_ptr); } /* navi_get_ainfo */ /* --------------------------------- * navi_reload_ainfo_force * --------------------------------- */ void navi_reload_ainfo_force(gint32 image_id) { GapAnimInfo *old_ainfo_ptr; char frame_nr_to_char[20]; gboolean is_alive; is_alive = gap_image_is_alive(image_id); if(gap_debug) { printf("navi_reload_ainfo_force image_id:%d is_alive:%d\n" , (int)image_id , (int)is_alive ); } if (is_alive != TRUE) { return; } old_ainfo_ptr = naviD->ainfo_ptr; naviD->active_imageid = image_id; naviD->ainfo_ptr = navi_get_ainfo(image_id, old_ainfo_ptr); if((strcmp(naviD->ainfo_ptr->extension, ".xcf") != 0) && (strcmp(naviD->ainfo_ptr->extension, ".xcfgz") != 0) && (global_old_active_imageid != image_id)) { /* for other frameformats than xcf * save the frame a 1st time (to set filetype specific save paramters) * this also is a workaround for a BUG that causes an X11 deadlock * when the save dialog pops up from the double-click callback in the frames listbox */ suspend_gimage_notify++; gap_lib_save_named_frame(image_id, naviD->ainfo_ptr->old_filename); suspend_gimage_notify--; } global_old_active_imageid = image_id; if(naviD->framerange_number_label) { g_snprintf(frame_nr_to_char, sizeof(frame_nr_to_char), "%06d - %06d" , (int)naviD->ainfo_ptr->first_frame_nr , (int)naviD->ainfo_ptr->last_frame_nr ); gtk_label_set_text (GTK_LABEL (naviD->framerange_number_label), frame_nr_to_char); } navi_dyn_adj_set_limits(); if(old_ainfo_ptr) gap_lib_free_ainfo(&old_ainfo_ptr); } /* end navi_reload_ainfo_force */ /* --------------------------------- * navi_reload_ainfo * --------------------------------- */ void navi_reload_ainfo(gint32 image_id) { if(gap_debug) printf("navi_reload_ainfo image_id:%d\n", (int)image_id); if(image_id < 0) { navi_reload_ainfo_force(naviD->any_imageid); } else { gint32 l_new_image_id; gint32 l_pid; /* check for changes in the active_image table * (this table is updated automatically by gap_goto and other gap procedures * to inform the navigator dialog about changes of the active image_id) */ l_pid = gap_base_getpid(); l_new_image_id = gap_navat_get_active_image(image_id, l_pid); if(l_new_image_id >= 0) { gap_navat_set_active_image(l_new_image_id, l_pid); image_id = l_new_image_id; global_old_active_imageid = l_new_image_id; } navi_reload_ainfo_force(image_id); } if(naviD->ainfo_ptr) { if(naviD->vin_ptr) g_free(naviD->vin_ptr); naviD->vin_ptr = gap_vin_get_all(naviD->ainfo_ptr->basename); if(naviD->framerate_adj != NULL) { gtk_adjustment_set_value(GTK_ADJUSTMENT(naviD->framerate_adj), (gfloat)naviD->vin_ptr->framerate); } if(naviD->timezoom_adj != NULL) { gtk_adjustment_set_value(GTK_ADJUSTMENT(naviD->timezoom_adj), (gfloat)naviD->vin_ptr->timezoom); } p_set_acl_tracking_radio_buttons(naviD); } } /* end navi_reload_ainfo */ /* --------------------------------- * navi_images_menu_constrain * --------------------------------- */ static gboolean navi_images_menu_constrain(gint32 image_id, gpointer data) { if(gap_debug) printf("navi_images_menu_constrain PROCEDURE imageID:%d\n", (int)image_id); if(gap_lib_get_frame_nr(image_id) < 0) { return(FALSE); /* reject images without frame number */ } if(naviD) { if(naviD->active_imageid < 0) { /* if there is no valid active_imageid * we nominate the first one that comes along */ naviD->any_imageid = image_id; } } return(TRUE); } /* end navi_images_menu_constrain */ /* --------------------------------- * navi_images_menu_callback * --------------------------------- */ static void navi_images_menu_callback (GtkWidget *widget, gpointer data) { gint32 image_id; gint value; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value); image_id = (gint32)value; if(gap_debug) printf("navi_images_menu_callback PROCEDURE imageID:%d\n", (int)image_id); if(naviD) { if(naviD->active_imageid != image_id) { navi_reload_ainfo(image_id); navi_dialog_update(NUPD_FRAME_NR_CHANGED | NUPD_PREV_LIST); navi_drop_sel_range_list(); navi_scroll_to_current_frame_nr(); } } } /* end navi_images_menu_callback */ /* --------------------------------- * navi_set_waiting_cursor * --------------------------------- */ static void navi_set_waiting_cursor(void) { if(naviD == NULL) return; if(GTK_WIDGET(naviD->shell)->window == NULL) return; naviD->waiting_cursor = TRUE; gdk_window_set_cursor(GTK_WIDGET(naviD->shell)->window, naviD->cursor_wait); gdk_flush(); /* g_main_context_iteration makes sure that waiting cursor is displayed */ while(g_main_context_iteration(NULL, FALSE)); gdk_flush(); } /* end navi_set_waiting_cursor */ /* --------------------------------- * navi_set_active_cursor * --------------------------------- */ static void navi_set_active_cursor(void) { if(naviD == NULL) return; if(GTK_WIDGET(naviD->shell)->window == NULL) return; naviD->waiting_cursor = FALSE; gdk_window_set_cursor(GTK_WIDGET(naviD->shell)->window, naviD->cursor_acitve); gdk_flush(); } /* end navi_set_active_cursor */ /* -------------------------------- * navi_scroll_to_current_frame_nr * -------------------------------- */ static void navi_scroll_to_current_frame_nr(void) { gint32 adj_intval; if(naviD == NULL) return; if(naviD->ainfo_ptr == NULL) return; if(naviD->vin_ptr == NULL) return; if(naviD->dyn_table == NULL) return; adj_intval = (gint32)(GTK_ADJUSTMENT(naviD->dyn_adj)->value + 0.5); if(gap_debug) { printf("navi_scroll_to_current_frame_nr: BEGIN timezoom:%d, item_height:%d\n" " curr_frame_nr: %d dyn_topframenr: %d dyn_rows:%d dyn_adj: %d\n" , (int)naviD->vin_ptr->timezoom , (int)naviD->item_height , (int)naviD->ainfo_ptr->curr_frame_nr , (int)naviD->dyn_topframenr , (int)naviD->dyn_rows , (int)adj_intval ); } if((naviD->ainfo_ptr->curr_frame_nr >= naviD->dyn_topframenr) && (naviD->ainfo_ptr->curr_frame_nr < naviD->dyn_topframenr + (naviD->dyn_rows * naviD->vin_ptr->timezoom)) ) { navi_dyn_adj_set_pos(); /* current frame is within in the currently displayed range */ return; } navi_dyn_adj_set_limits(); naviD->dyn_topframenr = navi_constrain_dyn_topframenr(naviD->ainfo_ptr->curr_frame_nr); /* fetch and render all thumbnail_previews in the dyn table */ navi_refresh_dyn_table(naviD->dyn_topframenr); navi_dyn_adj_set_pos(); } /* end navi_scroll_to_current_frame_nr */ /* ----------------------------------- * navi_scroll_event_cb * ----------------------------------- * handling of ctrl-c, ctrl-x, ctrl-v, ctrl-z keys * pressed when focus is somewhere in the tabw frame_with_name. */ static gboolean navi_scroll_event_cb ( GtkWidget *widget , GdkEventScroll *sevent , NaviDialog *naviD ) { gint32 value; if(naviD == NULL) { return FALSE;} value = (gint32)GTK_ADJUSTMENT(naviD->dyn_adj)->value; if((sevent->direction == GDK_SCROLL_UP) || (sevent->direction == GDK_SCROLL_RIGHT)) { value--; } else { value++; } /* set value in the rowpage spinbutton * (this fires another callback for update of tabw->rowpage;) */ gtk_adjustment_set_value(GTK_ADJUSTMENT(naviD->dyn_adj), (gdouble)value); return FALSE; } /* end navi_scroll_event_cb */ /* --------------------------------- * navi_dialog_tooltips * --------------------------------- */ static void navi_dialog_tooltips(void) { if(naviD == NULL) { return; } naviD->tooltip_on = gap_base_check_tooltips(&naviD->tooltip_on); } /* end navi_dialog_tooltips */ /* --------------------------------- * navi_find_OpenFrameList * --------------------------------- */ static gint navi_find_OpenFrameList(OpenFrameImages *search_item) { OpenFrameImages *item_list; item_list = naviD->OpenFrameImagesList; while(item_list) { if((item_list->image_id == search_item->image_id) && (item_list->frame_nr == search_item->frame_nr)) { return(TRUE); /* item found in the list */ } item_list = (OpenFrameImages *)item_list->next; } return(FALSE); } /* end navi_find_OpenFrameList */ /* --------------------------------- * navi_free_OpenFrameList * --------------------------------- */ static void navi_free_OpenFrameList(OpenFrameImages *list) { OpenFrameImages *item_list; OpenFrameImages *item_next; item_list = list; while(item_list) { item_next = (OpenFrameImages *)item_list->next; g_free(item_list); item_list = item_next; } } /* end navi_free_OpenFrameList */ /* --------------------------------- * navi_check_image_menu_changes * --------------------------------- */ static gint navi_check_image_menu_changes() { int nimages; gint32 *images; gint32 frame_nr; int i; gint l_rc; int item_count; OpenFrameImages *item_list; OpenFrameImages *new_item; l_rc = TRUE; if(naviD->OpenFrameImagesList == NULL) { l_rc = FALSE; } item_list = NULL; item_count = 0; images = gimp_image_list (&nimages); for (i = 0; i < nimages; i++) { frame_nr = gap_lib_get_frame_nr(images[i]); /* check for video frame */ if(frame_nr >= 0) { item_count++; new_item = g_new (OpenFrameImages, 1); new_item->image_id = images[i]; new_item->frame_nr = frame_nr; new_item->next = item_list; item_list = new_item; if(!navi_find_OpenFrameList(new_item)) { l_rc = FALSE; } } } g_free(images); if(item_count != naviD->OpenFrameImagesCount) { l_rc = FALSE; } if(l_rc == TRUE) { navi_free_OpenFrameList(item_list); } else { navi_free_OpenFrameList(naviD->OpenFrameImagesList); naviD->OpenFrameImagesCount = item_count; naviD->OpenFrameImagesList = item_list; } return(l_rc); } /* end navi_check_image_menu_changes */ /* --------------------------------- * navi_refresh_image_menu * --------------------------------- */ static gint navi_refresh_image_menu() { if(naviD) { if(!navi_check_image_menu_changes()) { GtkWidget *old_combo; if(gap_debug) printf("navi_refresh_image_menu ** BEGIN REFRESH\n"); if(naviD->OpenFrameImagesCount != 0) { gtk_widget_set_sensitive(naviD->vbox, TRUE); } old_combo = naviD->image_combo; naviD->image_combo = gimp_image_combo_box_new(navi_images_menu_constrain, naviD); if(old_combo) { /* drop the old combo box */ gtk_widget_destroy(old_combo); } gtk_box_pack_start (GTK_BOX (naviD->image_combo_hbox) , naviD->image_combo , TRUE, TRUE, 0); gtk_widget_show (naviD->image_combo); gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (naviD->image_combo), naviD->active_imageid, /* initial value */ G_CALLBACK (navi_images_menu_callback), naviD); if(naviD->OpenFrameImagesCount == 0) { gtk_widget_set_sensitive(naviD->vbox, FALSE); } return(TRUE); } } return(FALSE); } /* end navi_refresh_image_menu */ /* --------------------------------- * navi_update_after_goto * --------------------------------- */ void navi_update_after_goto(void) { if(naviD) { navi_dialog_update(NUPD_IMAGE_MENU | NUPD_FRAME_NR_CHANGED); navi_scroll_to_current_frame_nr(); } gimp_displays_flush(); navi_set_active_cursor(); } /* end navi_update_after_goto */ /* --------------------------------- * navi_ops_menu_set_sensitive * --------------------------------- */ static void navi_ops_menu_set_sensitive(void) { if(naviD == NULL) { return; } if(gap_vid_edit_framecount() > 0) { gtk_widget_set_sensitive(naviD->pastea_menu_item, TRUE); gtk_widget_set_sensitive(naviD->pasteb_menu_item, TRUE); gtk_widget_set_sensitive(naviD->paster_menu_item, TRUE); gtk_widget_set_sensitive(naviD->clrpaste_menu_item, TRUE); } else { gtk_widget_set_sensitive(naviD->pastea_menu_item, FALSE); gtk_widget_set_sensitive(naviD->pasteb_menu_item, FALSE); gtk_widget_set_sensitive(naviD->paster_menu_item, FALSE); gtk_widget_set_sensitive(naviD->clrpaste_menu_item, FALSE); } if(naviD->sel_range_list) { gtk_widget_set_sensitive(naviD->copy_menu_item, TRUE); gtk_widget_set_sensitive(naviD->cut_menu_item, TRUE); } else { gtk_widget_set_sensitive(naviD->copy_menu_item, FALSE); gtk_widget_set_sensitive(naviD->cut_menu_item, FALSE); } } /* end navi_ops_menu_set_sensitive */ /* --------------------------------- * navi_ops_buttons_set_sensitive * --------------------------------- */ static void navi_ops_buttons_set_sensitive(void) { if(naviD == NULL) { return; } if(naviD->sel_range_list) { if(naviD->del_button) gtk_widget_set_sensitive(naviD->del_button, TRUE); if(naviD->dup_button) gtk_widget_set_sensitive(naviD->dup_button, TRUE); } else { if(naviD->del_button) gtk_widget_set_sensitive(naviD->del_button, FALSE); if(naviD->dup_button) gtk_widget_set_sensitive(naviD->dup_button, FALSE); } } /* end navi_ops_buttons_set_sensitive */ /* --------------------------------- * navi_pviews_reset * --------------------------------- */ static void navi_pviews_reset(void) { gint l_row; for(l_row = 0; l_row < naviD->dyn_rows; l_row++) { FrameWidget *fw; fw = &naviD->frame_widget_tab[l_row]; fw->frame_timestamp = 0; gap_pview_drop_repaint_buffers(fw->pv_ptr); } } /* end navi_pviews_reset */ /* --------------------------------- * navi_thumb_update * --------------------------------- * update thumbnailfiles on disk * IN: update_all TRUE force update on all frames */ static void navi_thumb_update(gboolean update_all) { gint32 l_frame_nr; gint32 l_image_id; gint l_upd_flag; gint l_any_upd_flag; char *l_image_filename; static gboolean l_msg_win_alrady_open = FALSE; if(naviD == NULL) return; if(naviD->ainfo_ptr == NULL) return; if(l_msg_win_alrady_open) { return; } if(!gap_thumb_thumbnailsave_is_on()) { l_msg_win_alrady_open = TRUE; gap_arr_msg_win(GIMP_RUN_INTERACTIVE , _("For the thumbnail update you have to select\n" "a thumbnail filesize other than 'No Thumbnails'\n" "in the environment section of the preferences dialog") ); l_msg_win_alrady_open = FALSE; return; } navi_set_waiting_cursor(); l_any_upd_flag = FALSE; for(l_frame_nr = naviD->ainfo_ptr->first_frame_nr; l_frame_nr <= naviD->ainfo_ptr->last_frame_nr; l_frame_nr++) { l_upd_flag = TRUE; l_image_filename = gap_lib_alloc_fname(naviD->ainfo_ptr->basename, l_frame_nr, naviD->ainfo_ptr->extension); if(!update_all) { gint32 l_th_width; gint32 l_th_height; gint32 l_th_data_count; gint32 l_th_bpp; guchar *l_raw_thumb; /* init preferred width and height * (as hint for the thumbnail loader to decide * if thumbnail is to fetch from normal or large thumbnail directory * just for the case when both sizes are available) */ l_th_width = naviD->preview_size; l_th_height = naviD->preview_size; l_raw_thumb = NULL; if(TRUE == gap_thumb_file_load_thumbnail(l_image_filename , &l_th_width , &l_th_height , &l_th_data_count , &l_th_bpp , &l_raw_thumb )) { /* Thumbnail load failed, so an update is needed to create one */ l_upd_flag = FALSE; } else { /* Thumbnail load succeeded, update is not needed */ if(l_raw_thumb) { g_free(l_raw_thumb); } } } if(l_upd_flag) { l_any_upd_flag = TRUE; if(gap_debug) printf("navi_thumb_update frame_nr:%d\n", (int)l_frame_nr); l_image_id = gap_lib_load_image(l_image_filename); gap_pdb_gimp_file_save_thumbnail(l_image_id, l_image_filename); gimp_image_delete(l_image_id); } if(l_image_filename) g_free(l_image_filename); } if(l_any_upd_flag ) { /* forget about the previous chached thumbnials * (if we had no thumbnails before, the cache holds only the default icons * but now we generated real thumbnails without changing the timestamp * of the oroginal file) */ navi_pviews_reset(); /* fetch and render all thumbnail_previews in the dyn table */ navi_refresh_dyn_table(naviD->dyn_topframenr); } navi_set_active_cursor(); } /* end navi_thumb_update */ static void navi_dialog_thumb_update_callback(GtkWidget *w, gpointer data) { if(gap_debug) printf("navi_dialog_thumb_update_callback\n"); navi_thumb_update(FALSE); } static void navi_dialog_thumb_updateall_callback(GtkWidget *w, gpointer data) { if(gap_debug) printf("navi_dialog_thumb_updateall_callback\n"); navi_thumb_update(TRUE); } /* --------------------------------- * navi_playback * --------------------------------- */ static void navi_playback(gboolean use_gimp_layeranimplayer) { SelectedRange *range_list; gint32 l_from; gint32 l_to; gint32 l_new_image_id; GimpParam *return_vals; int nreturn_vals; char l_frame_name[50]; int l_frame_delay; gint32 dummy_layer_id; if(gap_debug) printf("navi_dialog_vcr_play_callback\n"); navi_set_waiting_cursor(); strcpy(l_frame_name, "frame_[######]"); if(naviD->vin_ptr) { if(naviD->vin_ptr->framerate > 0) { l_frame_delay = 1000 / naviD->vin_ptr->framerate; g_snprintf(l_frame_name, sizeof(l_frame_name), "frame_[######] (%dms)", (int)l_frame_delay); } } l_from = naviD->ainfo_ptr->first_frame_nr; l_to = naviD->ainfo_ptr->last_frame_nr; range_list = naviD->sel_range_list; if(range_list) { l_to = naviD->ainfo_ptr->first_frame_nr; l_from = naviD->ainfo_ptr->last_frame_nr; while(range_list) { l_from = MIN(l_from, range_list->from); l_to = MAX(l_to, range_list->to); range_list = range_list->next; } } if(!use_gimp_layeranimplayer) { /* Start GAP video frame Playback Module via PDB * note: the player always rund INTERACTIVE * but accepts calling parameters only when called in * GIMP_RUN_NONINTERACTIVE runmode */ dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_videoframes_player", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_INT32, l_from, GIMP_PDB_INT32, l_to, GIMP_PDB_INT32, TRUE, /* autostart */ GIMP_PDB_INT32, TRUE, /* use_thumbnails (playback using thumbnails where available) */ GIMP_PDB_INT32, TRUE, /* exact_timing */ GIMP_PDB_INT32, TRUE, /* play_selection_only */ GIMP_PDB_INT32, TRUE, /* play_loop */ GIMP_PDB_INT32, FALSE, /* play_pingpong */ GIMP_PDB_FLOAT, -1.0, /* speed is original framerate */ GIMP_PDB_INT32, -1, /* use default width */ GIMP_PDB_INT32, -1, /* use default height */ GIMP_PDB_INT32, FALSE, /* audio_enable (DISABLED) */ GIMP_PDB_STRING, "\0", /* audio_filename */ GIMP_PDB_INT32, 0, /* audio_frame_offset */ GIMP_PDB_FLOAT, 1.0, /* audio_volume */ GIMP_PDB_END); gimp_destroy_params(return_vals, nreturn_vals); navi_set_active_cursor(); return; } dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_range_to_multilayer", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_INT32, l_from, GIMP_PDB_INT32, l_to, GIMP_PDB_INT32, 3, /* flatten image */ GIMP_PDB_INT32, 1, /* BG_VISIBLE */ GIMP_PDB_INT32, (gint32)naviD->vin_ptr->framerate, GIMP_PDB_STRING, l_frame_name, GIMP_PDB_INT32, 6, /* use all visible layers */ GIMP_PDB_INT32, 0, /* ignore case */ GIMP_PDB_INT32, 0, /* normal selection (no invert) */ GIMP_PDB_STRING, "0", /* select string (ignored) */ GIMP_PDB_INT32, 0, /* use full layersize, ignore selection */ GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { l_new_image_id = return_vals[1].data.d_image; gimp_destroy_params(return_vals, nreturn_vals); /* TODO: here we should start a thread for the playback, * so the navigator is not blocked until playback exits */ dummy_layer_id = gap_image_get_any_layer(l_new_image_id); return_vals = gimp_run_procedure ("plug_in_animationplay", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, l_new_image_id, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_END); gimp_destroy_params(return_vals, nreturn_vals); } else { gimp_destroy_params(return_vals, nreturn_vals); } navi_set_active_cursor(); } /* end navi_playback */ static void navi_dialog_vcr_play_callback(GtkWidget *w, gpointer data) { if(gap_debug) printf("navi_dialog_vcr_play_callback\n"); navi_playback(FALSE /* dont use_gimp_layeranimplayer */); } static void navi_dialog_vcr_play_layeranim_callback(GtkWidget *w, gpointer data) { if(gap_debug) printf("navi_dialog_vcr_play_layeranim_callback\n"); navi_playback(TRUE /* use_gimp_layeranimplayer */); } /* ------------------------------------------- * navi_dialog_frames_duplicate_frame_callback * ------------------------------------------- */ static void navi_dialog_frames_duplicate_frame_callback(GtkWidget *w, gpointer data) { SelectedRange *range_list; GimpParam *return_vals; int nreturn_vals; gint32 dummy_layer_id; if(gap_debug) printf("navi_dialog_frames_duplicate_frame_callback\n"); if(naviD->sel_range_list) { navi_set_waiting_cursor(); range_list = navi_get_last_range_list(naviD->sel_range_list); while(range_list) { /* Note: process the ranges from high frame_nummers * downto low frame_numbers. * (the sel_range_list is sorted by ascending from framenumbers * therefore we step from the last element back to the 1st) */ if(gap_debug) printf("Duplicate Range from:%d to:%d\n" ,(int)range_list->from ,(int)range_list->to ); dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_goto", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_INT32, range_list->from, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { naviD->active_imageid = return_vals[1].data.d_image; gimp_destroy_params(return_vals, nreturn_vals); dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_dup", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_INT32, 1, /* copy block 1 times */ GIMP_PDB_INT32, range_list->from, GIMP_PDB_INT32, range_list->to, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { naviD->active_imageid = return_vals[1].data.d_image; } } gimp_destroy_params(return_vals, nreturn_vals); range_list = range_list->prev; } navi_drop_sel_range_list(); navi_update_after_goto(); } } /* end navi_dialog_frames_duplicate_frame_callback */ /* ---------------------------------------- * navi_dialog_frames_delete_frame_callback * ---------------------------------------- */ static void navi_dialog_frames_delete_frame_callback(GtkWidget *w, gpointer data) { SelectedRange *range_list; GimpParam *return_vals; int nreturn_vals; gint32 dummy_layer_id; if(gap_debug) printf("navi_dialog_frames_delete_frame_callback\n"); if(naviD->sel_range_list) { gint32 del_cnt; del_cnt = 0; range_list = navi_get_last_range_list(naviD->sel_range_list); while(range_list) { del_cnt += (1 + (range_list->to - range_list->from)); range_list = range_list->prev; } if(!navi_delete_confirm_dialog(del_cnt)) { return; } navi_set_waiting_cursor(); range_list = navi_get_last_range_list(naviD->sel_range_list); while(range_list) { /* Note: process the ranges from high frame_nummers * downto low frame_numbers. * (the sel_range_list is sorted by ascending from framenumbers * therefore we step from the last element back to the 1st) */ if(gap_debug) printf("Delete Range from:%d to:%d\n" ,(int)range_list->from ,(int)range_list->to ); dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_goto", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, /* dummy */ GIMP_PDB_INT32, range_list->from, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { naviD->active_imageid = return_vals[1].data.d_image; gimp_destroy_params(return_vals, nreturn_vals); dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_del", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_INT32, 1 + (range_list->to - range_list->from), /* number of frames to delete */ GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { naviD->active_imageid = return_vals[1].data.d_image; } } gimp_destroy_params(return_vals, nreturn_vals); range_list = range_list->prev; } navi_drop_sel_range_list(); navi_update_after_goto(); } } /* end navi_dialog_frames_delete_frame_callback */ /* --------------------------------- * navi_dialog_goto_callback * --------------------------------- */ static void navi_dialog_goto_callback(gint32 dst_framenr) { GimpParam *return_vals; int nreturn_vals; gint32 dummy_layer_id; if(gap_debug) printf("navi_dialog_goto_callback\n"); navi_set_waiting_cursor(); dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_goto", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, /* dummy */ GIMP_PDB_INT32, dst_framenr, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { naviD->active_imageid = return_vals[1].data.d_image; } gimp_destroy_params(return_vals, nreturn_vals); navi_update_after_goto(); } /* end navi_dialog_goto_callback */ /* ----------------------------------- * navi_dialog_vcr_goto_first_callback * ----------------------------------- */ static void navi_dialog_vcr_goto_first_callback(GtkWidget *w, gpointer data) { GimpParam *return_vals; int nreturn_vals; gint32 dummy_layer_id; if(gap_debug) printf("navi_dialog_vcr_goto_first_callback\n"); navi_set_waiting_cursor(); dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_first", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { naviD->active_imageid = return_vals[1].data.d_image; } gimp_destroy_params(return_vals, nreturn_vals); navi_update_after_goto(); } /* end navi_dialog_vcr_goto_first_callback */ /* --------------------------------- * navi_dialog_vcr_goto_prev_callback * --------------------------------- */ static void navi_dialog_vcr_goto_prev_callback(GtkWidget *w, gpointer data) { GimpParam *return_vals; int nreturn_vals; gint32 dummy_layer_id; if(gap_debug) printf("navi_dialog_vcr_goto_prev_callback\n"); navi_set_waiting_cursor(); dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_prev", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { naviD->active_imageid = return_vals[1].data.d_image; } gimp_destroy_params(return_vals, nreturn_vals); navi_update_after_goto(); } /* end navi_dialog_vcr_goto_prev_callback */ /* --------------------------------- * navi_dialog_goto_callback * --------------------------------- */ static void navi_dialog_vcr_goto_prevblock_callback(GtkWidget *w, gpointer data) { gint32 dst_framenr; if(gap_debug) printf("navi_dialog_vcr_goto_prevblock_callback\n"); if(naviD->ainfo_ptr == NULL) navi_reload_ainfo(naviD->active_imageid); if(naviD->ainfo_ptr == NULL) return; if(naviD->vin_ptr == NULL) return; dst_framenr = MAX(naviD->ainfo_ptr->curr_frame_nr - naviD->vin_ptr->timezoom, naviD->ainfo_ptr->first_frame_nr); navi_dialog_goto_callback(dst_framenr); } /* end navi_dialog_goto_callback */ /* ---------------------------------- * navi_dialog_vcr_goto_next_callback * ---------------------------------- */ static void navi_dialog_vcr_goto_next_callback(GtkWidget *w, gpointer data) { GimpParam *return_vals; int nreturn_vals; gint32 dummy_layer_id; if(gap_debug) printf("navi_dialog_vcr_goto_next_callback\n"); navi_set_waiting_cursor(); dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_next", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_END); gimp_destroy_params(return_vals, nreturn_vals); navi_update_after_goto(); } /* end navi_dialog_vcr_goto_next_callback */ /* --------------------------------------- * navi_dialog_vcr_goto_nextblock_callback * --------------------------------------- */ static void navi_dialog_vcr_goto_nextblock_callback(GtkWidget *w, gpointer data) { gint32 dst_framenr; if(gap_debug) printf("navi_dialog_vcr_goto_nextblock_callback\n"); if(naviD->ainfo_ptr == NULL) navi_reload_ainfo(naviD->active_imageid); if(naviD->ainfo_ptr == NULL) return; if(naviD->vin_ptr == NULL) return; dst_framenr = MIN(naviD->ainfo_ptr->curr_frame_nr + naviD->vin_ptr->timezoom, naviD->ainfo_ptr->last_frame_nr); navi_dialog_goto_callback(dst_framenr); } /* end navi_dialog_vcr_goto_nextblock_callback */ /* --------------------------------- * navi_dialog_vcr_goto_last_callback * --------------------------------- */ static void navi_dialog_vcr_goto_last_callback(GtkWidget *w, gpointer data) { GimpParam *return_vals; int nreturn_vals; gint32 dummy_layer_id; if(gap_debug) printf("navi_dialog_vcr_goto_last_callback\n"); navi_set_waiting_cursor(); dummy_layer_id = gap_image_get_any_layer(naviD->active_imageid); return_vals = gimp_run_procedure ("plug_in_gap_last", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, naviD->active_imageid, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_END); gimp_destroy_params(return_vals, nreturn_vals); navi_update_after_goto(); } /* end navi_dialog_vcr_goto_last_callback */ /* --------------------------------- * navi_frames_timing_update * --------------------------------- */ static void navi_frames_timing_update (void) { gint32 l_frame_nr; gint32 l_frame_nr_prev; gint32 l_count; l_frame_nr = naviD->dyn_topframenr; l_frame_nr_prev = -1; for(l_count = 0; l_count < naviD->dyn_rows; l_count++) { FrameWidget *fw; fw = &naviD->frame_widget_tab[l_count]; l_frame_nr = CLAMP(l_frame_nr , naviD->ainfo_ptr->first_frame_nr , naviD->ainfo_ptr->last_frame_nr ); if(l_frame_nr == l_frame_nr_prev) { /* make sure that dummy element has no -1 (dummy frame_nr) * (will display a blank label) */ fw->frame_nr = -1; } navi_frame_widget_time_label_update(fw); l_frame_nr_prev = l_frame_nr; l_frame_nr += naviD->vin_ptr->timezoom; } } /* end navi_frames_timing_update */ /* --------------------------------- * navi_framerate_spinbutton_update * --------------------------------- */ void navi_framerate_spinbutton_update(GtkAdjustment *adjustment, gpointer data) { gdouble framerate; if(naviD == NULL) return; if(naviD->vin_ptr == NULL) return; framerate = (gdouble) (adjustment->value); if(framerate != naviD->vin_ptr->framerate) { naviD->vin_ptr->framerate = framerate; if(naviD->ainfo_ptr) { /* write new framerate to video info file */ gap_vin_set_common(naviD->vin_ptr, naviD->ainfo_ptr->basename); } navi_frames_timing_update(); } if(gap_debug) printf("navi_framerate_spinbutton_update :%d\n", (int)naviD->vin_ptr->framerate); } /* end navi_framerate_spinbutton_update */ /* --------------------------------- * navi_timezoom_spinbutton_update * --------------------------------- */ void navi_timezoom_spinbutton_update(GtkAdjustment *adjustment, gpointer data) { gint timezoom; if(naviD == NULL) return; if(naviD->vin_ptr == NULL) return; timezoom = (int) (adjustment->value); if(timezoom != naviD->vin_ptr->timezoom) { naviD->vin_ptr->timezoom = timezoom; if(naviD->ainfo_ptr) { /* write new timezoom to video info file */ gap_vin_set_common(naviD->vin_ptr, naviD->ainfo_ptr->basename); } frames_dialog_flush(); navi_dyn_adj_set_limits(); navi_dyn_adj_set_pos(); } if(gap_debug) printf("navi_timezoom_spinbutton_update :%d\n", (int)naviD->vin_ptr->timezoom); } /* end navi_timezoom_spinbutton_update */ /* ------------------------ * frames_dialog_flush * ------------------------ */ static void frames_dialog_flush (void) { if(gap_debug) printf("frames_dialog_flush\n"); if(naviD) { frames_dialog_update(naviD->active_imageid); } } /* end frames_dialog_flush */ /* ------------------------ * frames_dialog_update * ------------------------ */ void frames_dialog_update (gint32 image_id) { gint l_waiting_cursor; if(gap_debug) printf("frames_dialog_update image_id:%d\n", (int)image_id); if (! naviD) /* || (naviD->active_imageid == image_id) */ { return; } l_waiting_cursor = naviD->waiting_cursor; if(!naviD->waiting_cursor) navi_set_waiting_cursor(); navi_reload_ainfo(image_id); /* Make sure the gimage is not notified of this change */ suspend_gimage_notify++; /* Find the preview extents */ navi_preview_extents (); /* Refresh all elements in dyn_table */ navi_refresh_dyn_table (naviD->dyn_topframenr); suspend_gimage_notify--; if(!l_waiting_cursor) navi_set_active_cursor(); } /* end frames_dialog_update */ /* --------------------------------- * navi_render_preview * --------------------------------- */ static void navi_render_preview (FrameWidget *fw) { gint32 l_th_width; gint32 l_th_height; gint32 l_th_data_count; gint32 l_th_bpp; guchar *l_th_data; gint32 l_thumbdata_count; if(gap_debug) printf("navi_render_preview START\n"); l_th_data = NULL; l_th_bpp = 3; /* l_th_bpp always 3 for thumbnail_file data, but can be 4 for the actual image */ if(naviD == NULL) { return; } if(fw == NULL) { return; } if(fw->pv_ptr == NULL) { return; } if(naviD->ainfo_ptr == NULL) { return; } if(!gap_image_is_alive(naviD->active_imageid)) {return; } if((fw->pv_ptr->pv_width != naviD->image_width) || (fw->pv_ptr->pv_height != naviD->image_height)) { gap_pview_set_size(fw->pv_ptr, naviD->image_width, naviD->image_height, NAVI_CHECK_SIZE); } if(naviD->ainfo_ptr->curr_frame_nr == fw->frame_nr) { /* if this is the currently open image * we must get the thumbnail from memory (gimp composite view) * rather than reading from thumbnail file * to get an actual version. */ if(gap_debug) printf("navi_render_preview ACTUAL image BEFORE gap_pdb_gimp_image_thumbnail w:%d h:%d,\n" ,(int)fw->pv_ptr->pv_width, (int)fw->pv_ptr->pv_height); gap_pdb_gimp_image_thumbnail(naviD->active_imageid , fw->pv_ptr->pv_width , fw->pv_ptr->pv_height , &l_th_width , &l_th_height , &l_th_bpp , &l_thumbdata_count , &l_th_data ); if(gap_debug) printf("navi_render_preview AFTER gap_pdb_gimp_image_thumbnail th_w:%d th_h:%d, th_bpp:%d, count:%d\n" ,(int)l_th_width, (int)l_th_height, (int)l_th_bpp, (int)l_thumbdata_count); } else { struct stat l_stat; gchar *l_frame_filename; gboolean l_can_use_cached_thumbnail; l_can_use_cached_thumbnail = FALSE; l_frame_filename = gap_lib_alloc_fname(naviD->ainfo_ptr->basename, fw->frame_nr, naviD->ainfo_ptr->extension); if(l_frame_filename) { if (0 == g_stat(l_frame_filename, &l_stat)) { if(fw->frame_filename) { if(gap_debug) { printf(" CHECK SIZE old pv_area_data: %d pv_w: %d pv_h:%d filename:%s timestamp:%d\n" , (int)fw->pv_ptr->pv_area_data , (int)fw->pv_ptr->pv_width , (int)fw->pv_ptr->pv_height , fw->frame_filename , (int)fw->frame_timestamp ); printf(" CHECK SIZE new w: %d h:%d filename:%s timestamp:%d\n" , (int)naviD->image_width , (int)naviD->image_height , l_frame_filename , (int)l_stat.st_mtime ); } if((strcmp(l_frame_filename,fw->frame_filename) == 0) && (fw->frame_timestamp == l_stat.st_mtime) && (fw->pv_ptr->pv_area_data) && (fw->pv_ptr->pv_width == naviD->image_width) && (fw->pv_ptr->pv_height == naviD->image_height) ) { /* there was no change of the frame file since * we cached the thumbnail data * and the cached data does match in size * (fw->pv_ptr->pv_area_data is the pointer to the cached thumbnaildata) */ l_can_use_cached_thumbnail = TRUE; } else { /* free the old filename */ g_free(fw->frame_filename); /* store te new name and mtime */ fw->frame_filename = l_frame_filename; fw->frame_timestamp = l_stat.st_mtime; } } else { /* we are going to read thumbnaildata of this frame for the 1.st time * store its name and mtime for next usage */ fw->frame_filename = l_frame_filename; fw->frame_timestamp = l_stat.st_mtime; } } } if(l_can_use_cached_thumbnail) { if(gap_debug) printf("navi_render_preview: USING CACHED THUMBNAIL\n"); gap_pview_repaint(fw->pv_ptr); return; } else { /* fetch l_th_data from thumbnail_file */ if(gap_debug) printf("navi_render_preview: fetching THUMBNAILFILE for: %s\n", l_frame_filename); if(l_frame_filename) { /* init preferred width and height * (as hint for the thumbnail loader to decide * if thumbnail is to fetch from normal or large thumbnail directory * just for the case when both sizes are available) */ l_th_width = naviD->preview_size; l_th_height = naviD->preview_size; gap_thumb_file_load_thumbnail(l_frame_filename , &l_th_width , &l_th_height , &l_th_data_count , &l_th_bpp , &l_th_data ); } } } if(l_th_data) { gboolean l_th_data_was_grabbed; /* fetch was successful, we can call the render procedure */ l_th_data_was_grabbed = gap_pview_render_from_buf (fw->pv_ptr , l_th_data , l_th_width , l_th_height , l_th_bpp , TRUE /* allow_grab_src_data */ ); if(l_th_data_was_grabbed) { l_th_data = NULL; } } else { /* fetch failed, render a default icon */ if(gap_debug) printf("navi_render_preview: fetch failed, using DEFAULT_ICON\n"); gap_pview_render_default_icon(fw->pv_ptr); } if(l_th_data) { g_free(l_th_data); } } /* end navi_render_preview */ /* --------------------------------- * frame_widget_preview_redraw * --------------------------------- */ static void frame_widget_preview_redraw (FrameWidget *fw) { if(fw == NULL) { return;} if(fw->pv_ptr == NULL) { return;} gap_pview_repaint(fw->pv_ptr); /* make sure the image has been transfered completely to the pixmap before * we use it again... */ gdk_flush (); } /* end frame_widget_preview_redraw */ /* --------------------------------- * frame_widget_preview_events * --------------------------------- * handles events for all frame_widgets (in the dyn_table) * - Expose of pview drawing_area * - Doubleclick (goto) * - Selections (Singleclick, and key-modifiers) */ static gboolean frame_widget_preview_events (GtkWidget *widget, GdkEvent *event, gpointer user_data) { GdkEventExpose *eevent; GdkEventButton *bevent; FrameWidget *fw; /* int sx, sy, dx, dy, w, h; */ fw = (FrameWidget *) user_data; if(fw == NULL) { fw = (FrameWidget *) g_object_get_data (G_OBJECT (widget), "frame_widget"); if(fw == NULL) { return FALSE; } } if (fw->frame_nr < 0) { /* the frame_widget is not initialized or it is just a dummy, no action needed */ return FALSE; } switch (event->type) { case GDK_2BUTTON_PRESS: if(gap_debug) printf("frame_widget_preview_events GDK_2BUTTON_PRESS (doubleclick)\n"); navi_dialog_goto_callback(fw->frame_nr); return TRUE; case GDK_BUTTON_PRESS: bevent = (GdkEventButton *) event; if(gap_debug) printf("frame_widget_preview_events GDK_BUTTON_PRESS button:%d frame_nr:%d widget:%d da_wgt:%d\n" , (int)bevent->button , (int)fw->frame_nr , (int)widget , (int)fw->pv_ptr->da_widget ); if(fw->frame_nr < 0) { /* perform no actions on dummy entries in the dyn_table */ return TRUE; } if (bevent->button == 3) { /* right mousebutton (3) shows the PopUp Menu */ navi_ops_menu_set_sensitive(); naviD->paste_at_frame = fw->frame_nr; gtk_menu_popup (GTK_MENU (naviD->ops_menu), NULL, NULL, NULL, NULL, 3, bevent->time); return TRUE; } /* handle selctions, according to modifier keys */ if (event->button.state & GDK_CONTROL_MASK) { if(gap_debug) printf("frame_widget_preview_events SELECTION GDK_CONTROL_MASK (ctrl modifier)\n"); navi_sel_ctrl(fw->frame_nr); navi_debug_print_sel_range(); } else if (event->button.state & GDK_SHIFT_MASK) { if(gap_debug) printf("frame_widget_preview_events SELECTION GDK_SHIFT_MASK (shift modifier)\n"); navi_sel_shift(fw->frame_nr); navi_debug_print_sel_range(); } else if (event->button.state & GDK_MOD1_MASK) { if(gap_debug) printf("frame_widget_preview_events SELECTION GDK_MOD1_MASK (alt modifier)\n"); navi_sel_ctrl(fw->frame_nr); /* alt does same as ctrl */ navi_debug_print_sel_range(); } else { if(gap_debug) printf("frame_widget_preview_events SELECTION (no modifier)\n"); navi_sel_normal(fw->frame_nr); navi_debug_print_sel_range(); } navi_ops_buttons_set_sensitive(); navi_frames_timing_update(); /* this is also for refresh of the selection state */ break; case GDK_EXPOSE: if(gap_debug) printf("frame_widget_preview_events GDK_EXPOSE frame_nr:%d widget:%d da_wgt:%d\n" , (int)fw->frame_nr , (int)widget , (int)fw->pv_ptr->da_widget ); eevent = (GdkEventExpose *) event; if(widget == fw->pv_ptr->da_widget) { navi_preview_extents(); navi_frame_widget_time_label_update(fw); frame_widget_preview_redraw (fw); } break; default: break; } return FALSE; } /* end frame_widget_preview_events */ /* --------------------------------- * navi_dialog_poll * --------------------------------- */ static gint navi_dialog_poll(GtkWidget *w, gpointer data) { gint32 frame_nr; gint32 update_flag; gint32 video_preview_size; if(gap_debug) printf("navi_dialog_poll TIMER POLL\n"); if(naviD) { if(suspend_gimage_notify == 0) { update_flag = NUPD_IMAGE_MENU; video_preview_size = navi_get_preview_size(); if(naviD->preview_size != video_preview_size) { naviD->preview_size = video_preview_size; update_flag = NUPD_ALL; } /* check and enable/disable tooltips */ navi_dialog_tooltips (); /* check request to present dialog window */ p_check_dialog_to_front_request(); /* check if active image is still valid and is a frame image */ if(gap_image_is_alive(naviD->active_imageid)) { frame_nr = gap_lib_get_frame_nr(naviD->active_imageid); } else { frame_nr = -1; } if(frame_nr < 0 ) { if(gap_debug) { printf("TIMER POLL active_imageid:%d is now invalid\n" ,(int)naviD->active_imageid ); } /* no valid frame number, maybe frame was closed */ naviD->active_imageid = -1; update_flag = NUPD_ALL; } else { if(naviD->ainfo_ptr) { update_flag = NUPD_IMAGE_MENU | NUPD_FRAME_NR_CHANGED; } else { update_flag = NUPD_ALL; } } navi_dialog_update(update_flag); } /* restart timer */ if(naviD->timer >= 0) { g_source_remove(naviD->timer); } naviD->timer = g_timeout_add(naviD->cycle_time, (GtkFunction)navi_dialog_poll, NULL); } return FALSE; } /* end navi_dialog_poll */ /* --------------------------------- * navi_dialog_update * --------------------------------- */ static void navi_dialog_update(gint32 update_flag) { gint32 l_first, l_last; gint l_image_menu_was_changed; l_image_menu_was_changed = FALSE; if(update_flag & NUPD_IMAGE_MENU) { l_image_menu_was_changed = navi_refresh_image_menu(); } if(update_flag & NUPD_FRAME_NR_CHANGED) { l_first = -1; l_last = -1; if(naviD->ainfo_ptr) { l_first = naviD->ainfo_ptr->first_frame_nr; l_last = naviD->ainfo_ptr->last_frame_nr; } navi_reload_ainfo(naviD->active_imageid); navi_preview_extents(); /* we must force a rebuild of the dyn_table of frame_widgets * if any frames were deleteted or are created * (outside of the navigator) */ if(naviD->ainfo_ptr) { if((l_first != naviD->ainfo_ptr->first_frame_nr) || (l_last != naviD->ainfo_ptr->last_frame_nr)) { update_flag |= NUPD_PREV_LIST; navi_drop_sel_range_list(); } } } if(update_flag & NUPD_PREV_LIST) { frames_dialog_flush(); } else { /* SIMPLY refresh all frame_widgets in the dn_table. * (could limit refresh to those frame_widgets * where the thumbnail file timestamp changed since last access * and always refresh the preview of the active image.) */ navi_refresh_dyn_table (naviD->dyn_topframenr); } } /* end navi_dialog_update */ /* ------------------------ * navi_preview_extents * ------------------------ */ static void navi_preview_extents (void) { gint32 width, height; if (!naviD) { return; } if (!gap_image_is_alive(naviD->active_imageid)) { return; } naviD->gimage_width = gimp_image_width(naviD->active_imageid); naviD->gimage_height = gimp_image_height(naviD->active_imageid); /* Get the image width and height variables, based on the gimage */ if (naviD->gimage_width > naviD->gimage_height) { naviD->ratio = (double) naviD->preview_size / (double) naviD->gimage_width; } else { naviD->ratio = (double) naviD->preview_size / (double) naviD->gimage_height; } if (naviD->preview_size > 0) { width = (int) (naviD->ratio * naviD->gimage_width); height = (int) (naviD->ratio * naviD->gimage_height); if (width < 1) width = 1; if (height < 1) height = 1; } else { /* defaults for the case that gimprc preferences says: use no layer previews at all */ width = 16; height = 10; } if((naviD->image_width != width) || (naviD->image_height != height)) { gint ii; naviD->image_width = width; naviD->image_height = height; /* set new size for all (used) frame_wiget_tab element preview drawing_areas */ for(ii=0; ii < naviD->fw_tab_used_count; ii++) { FrameWidget *fw; fw = &naviD->frame_widget_tab[ii]; if(fw->pv_ptr) { if(gap_debug) printf("navi_preview_extents pv_w: %d pv_h:%d\n", (int)fw->pv_ptr->pv_width, (int)fw->pv_ptr->pv_height); gap_pview_set_size(fw->pv_ptr , naviD->image_width , naviD->image_height , NAVI_CHECK_SIZE ); } } } naviD->item_height = 4 + naviD->image_height; if(gap_debug) printf("navi_preview_extents w: %d h:%d\n", (int)naviD->image_width, (int)naviD->image_height); } /* end navi_preview_extents */ /* --------------------------------- * navi_calc_frametiming * --------------------------------- */ static void navi_calc_frametiming(gint32 frame_nr, char *buf, gint32 sizeof_buf) { gint32 first; gdouble framerate; first = frame_nr; if(naviD->ainfo_ptr) { first = naviD->ainfo_ptr->first_frame_nr; } framerate = 24.0; if(naviD->vin_ptr) { framerate = naviD->vin_ptr->framerate; } gap_timeconv_framenr_to_timestr( (frame_nr - first) , framerate , buf , sizeof_buf ); } /* end navi_calc_frametiming */ /* --------------------------------- * navi_frame_widget_time_label_update * --------------------------------- */ static void navi_frame_widget_time_label_update(FrameWidget *fw) { char frame_nr_to_time[20]; GdkColor *bg_color; GdkColor *fg_color; bg_color = &naviD->shell->style->bg[GTK_STATE_NORMAL]; fg_color = &naviD->shell->style->fg[GTK_STATE_NORMAL]; if(fw->frame_nr >= 0) { navi_calc_frametiming(fw->frame_nr, frame_nr_to_time, sizeof(frame_nr_to_time)); if(navi_findframe_in_sel_range(fw->frame_nr)) { bg_color = &naviD->shell->style->bg[GTK_STATE_SELECTED]; fg_color = &naviD->shell->style->fg[GTK_STATE_SELECTED]; } } else { frame_nr_to_time[0] = ' '; frame_nr_to_time[1] = '\0'; } if(gap_debug) printf("navi_frame_widget_time_label_update: GTK_STYLE_SET_BACKGROUND bg_color: %d\n", (int)bg_color); /* Note: Gtk does not know about selcted items, since selections are handled * external by gap_navigator_dialog code. * using SELECTED or NORMAL color from the shell window to paint this private selection * (must use always the NORMAL state here, because for Gtk the event_box is never selected) */ gtk_widget_modify_bg(fw->event_box, GTK_STATE_NORMAL, bg_color); gtk_widget_modify_fg(fw->number_label, GTK_STATE_NORMAL, fg_color); gtk_widget_modify_fg(fw->time_label, GTK_STATE_NORMAL, fg_color); gtk_label_set_text (GTK_LABEL (fw->time_label), frame_nr_to_time); } /* end navi_frame_widget_time_label_update */ /* ######### SelctionRange Procedures ########## */ /* ----------------------------------------- * navi_debug_print_sel_range * ----------------------------------------- */ static void navi_debug_print_sel_range(void) { SelectedRange *range_item; if(gap_debug) { printf("\n SEL_RANGE ------------------------- START\n"); range_item = naviD->sel_range_list; while(range_item) { printf(" SEL_RANGE from: %06d to: %06d\n" , (int)range_item->from , (int)range_item->to ); range_item = range_item->next; } printf(" SEL_RANGE ------------------------- END\n\n"); } } /* end navi_debug_print_sel_range */ /* --------------------------------- * navi_drop_sel_range_list (2) * --------------------------------- */ static void navi_drop_sel_range_list2(void) { SelectedRange *range_list; SelectedRange *range_item; range_list = naviD->sel_range_list; while(range_list) { range_item = range_list; range_list = range_list->next; g_free(range_item); } naviD->sel_range_list = NULL; navi_ops_buttons_set_sensitive(); } /* end navi_drop_sel_range_list2 */ static void navi_drop_sel_range_list(void) { navi_drop_sel_range_list2(); naviD->prev_selected_framnr = -1; } /* end navi_drop_sel_range_list */ /* --------------------------------- * navi_drop_sel_range_elem * --------------------------------- */ static void navi_drop_sel_range_elem(SelectedRange *range_item) { SelectedRange *range_next; SelectedRange *range_prev; range_prev = range_item->prev; range_next = range_item->next; if(range_prev) { range_prev->next = range_next; } if(range_next) { range_next->prev = range_prev; } if(range_item == naviD->sel_range_list) { naviD->sel_range_list = range_next; } g_free(range_item); } /* end navi_drop_sel_range_elem */ /* ----------------------------------------- * navi_findframe_in_sel_range * ----------------------------------------- * return the SelectedRange that contains the framenr * return NULL if framenr is not found in the selected ranges */ static SelectedRange * navi_findframe_in_sel_range(gint32 framenr) { SelectedRange *range_item; range_item = naviD->sel_range_list; while(range_item) { if((framenr >= range_item->from) && (framenr <= range_item->to)) { return (range_item); } range_item = range_item->next; } return (NULL); } /* end navi_findframe_in_sel_range */ /* ----------------------------------------- * navi_add_sel_range_list * ----------------------------------------- * add a new element to the naviD->sel_range_list * the element is added at its place following ascending sort order * by framenr_from. */ static void navi_add_sel_range_list(gint32 framenr_from, gint32 framenr_to) { SelectedRange *range_list; SelectedRange *range_item; SelectedRange *range_prev; SelectedRange *range_next; range_prev = NULL; range_next = naviD->sel_range_list; range_list = naviD->sel_range_list; while(range_list) { if(framenr_from < range_list->from) { break; } range_prev = range_list; range_list = range_list->next; range_next = range_list; } range_item = g_new(SelectedRange, 1); range_item->from = framenr_from; range_item->to = framenr_to; if(range_prev == NULL) { /* add new element as 1.st element in the list */ range_item->next = naviD->sel_range_list; range_item->prev = NULL; naviD->sel_range_list = range_item; } else { range_prev->next = range_item; range_item->next = range_next; range_item->prev = range_prev; } if(range_next) { range_next->prev = range_item; } } /* end navi_add_sel_range_list */ /* ----------------------------------------- * navi_sel_normal * ----------------------------------------- */ static void navi_sel_normal(gint32 framenr) { navi_drop_sel_range_list(); navi_add_sel_range_list(framenr, framenr); naviD->prev_selected_framnr = framenr; } /* end navi_sel_normal */ /* ----------------------------------------- * navi_sel_ctrl * ----------------------------------------- */ static void navi_sel_ctrl(gint32 framenr) { SelectedRange *range_item; range_item = navi_findframe_in_sel_range(framenr); if(range_item) { /* framenr was already selected, DESELECT now */ if((range_item->from == framenr) && (range_item->to == framenr)) { /* completely remove the range_item */ navi_drop_sel_range_elem(range_item); } else if (range_item->from == framenr) { /* take out the first frame from the range */ range_item->from++; } else if (range_item->to == framenr) { /* take out the last frame from the range */ range_item->to--; } else { gint32 old_framenr_to; if(gap_debug) printf(" ** SPLIT from:%d to:%d framenr:%d\n", (int)range_item->from, (int)range_item->to, (int)framenr); /* have to split the range (take out framenr) */ old_framenr_to = range_item->to; range_item->to = framenr - 1; navi_add_sel_range_list(framenr +1, old_framenr_to); } } else { /* framenr was not SELECTED, select now */ navi_add_sel_range_list(framenr, framenr); } naviD->prev_selected_framnr = framenr; } /* end navi_sel_ctrl */ /* ----------------------------------------- * navi_sel_shift * ----------------------------------------- */ static void navi_sel_shift(gint32 framenr) { navi_drop_sel_range_list2(); /* use the variant without resetting naviD->prev_selected_framnr */ /* if there was no previous selection * then we use the first_frame_nr as starting point */ naviD->prev_selected_framnr = MAX(naviD->prev_selected_framnr ,naviD->ainfo_ptr->first_frame_nr); navi_add_sel_range_list(MIN(framenr, naviD->prev_selected_framnr) ,MAX(framenr, naviD->prev_selected_framnr)); } /* end navi_sel_shift */ /* ################################################# */ /* --------------------------------- * navi_dyn_frame_size_allocate * --------------------------------- */ static void navi_dyn_frame_size_allocate (GtkWidget *widget, GtkAllocation *allocation, gpointer user_data) { if(naviD == NULL) { return; } if(gap_debug) printf("\n# on_vid_preview_size_allocate: START new: w:%d h:%d \n" , (int)allocation->width , (int)allocation->height ); if(!naviD->in_dyn_table_sizeinit) { gint resize_flag; resize_flag = navi_dyn_table_set_size((gint)allocation->height); if(resize_flag > 0) { /* need refresh if new ros were added */ navi_refresh_dyn_table(naviD->dyn_topframenr); } } } /* end navi_dyn_frame_size_allocate */ /* --------------------------------- * navi_get_last_range_list * --------------------------------- * */ static SelectedRange * navi_get_last_range_list(SelectedRange *sel_range_list) { SelectedRange *range_list; SelectedRange *range_item; /* generate prev linkpointers in the range list */ range_item = NULL; range_list = sel_range_list; while(range_list) { range_list->prev = range_item; range_item = range_list; if(range_list->next == NULL) { break; /* now range_list points to the last element in the list */ } range_list = range_list->next; } return (range_list); } /* end navi_get_last_range_list */ /* -------------------------- * navi_frame_widget_replace2 * -------------------------- * in frame_nr (create empty dummy widgets for illegal frame_nr -1) */ static void navi_frame_widget_replace2(FrameWidget *fw) { if(gap_debug) printf("navi_frame_widget_replace2 START\n"); if(naviD == NULL) { return; } if(fw->pv_ptr == NULL) { fw->pv_ptr = gap_pview_new( naviD->image_width /* width */ , naviD->image_height /* height */ , NAVI_CHECK_SIZE , NULL /* preview without aspect_frame */ ); } else { if((naviD->image_width != fw->pv_ptr->pv_width) || (naviD->image_height != fw->pv_ptr->pv_height)) { gap_pview_set_size(fw->pv_ptr , naviD->image_width , naviD->image_height , NAVI_CHECK_SIZE ); } } fw->width = naviD->image_width; fw->height = naviD->image_height; if(fw->frame_nr < 0) { gtk_label_set_text (GTK_LABEL (fw->number_label), " "); gtk_label_set_text (GTK_LABEL (fw->time_label), " "); gtk_widget_hide(fw->pv_ptr->da_widget); return; gap_pview_render_from_buf (fw->pv_ptr , NULL /* render black frame */ , naviD->image_width , naviD->image_height , 3 /* bpp */ , FALSE /* DONT allow_grab_src_data */ ); } else { char frame_nr_to_char[20]; gtk_widget_show(fw->pv_ptr->da_widget); if(naviD->preview_size <= 0) { gap_pview_render_default_icon(fw->pv_ptr); } else { navi_render_preview(fw); } /* update the labeltexts */ navi_frame_widget_time_label_update(fw); g_snprintf(frame_nr_to_char, sizeof(frame_nr_to_char), "%06d", (int)fw->frame_nr); gtk_label_set_text (GTK_LABEL (fw->number_label), frame_nr_to_char); } } /* end navi_frame_widget_replace2 */ /* --------------------------------- * navi_frame_widget_replace * --------------------------------- */ static void navi_frame_widget_replace(gint32 image_id, gint32 frame_nr, gint32 dyn_rowindex) { FrameWidget *fw; time_t new_timestamp; if((dyn_rowindex < 0) || (dyn_rowindex >= MAX_DYN_ROWS) || (naviD == NULL) ) { return; } fw = &naviD->frame_widget_tab[dyn_rowindex]; new_timestamp = 0; if(fw->frame_filename) { gchar *l_frame_filename; l_frame_filename = NULL; if(frame_nr >= 0) { l_frame_filename = gap_lib_alloc_fname(naviD->ainfo_ptr->basename, frame_nr, naviD->ainfo_ptr->extension); if(l_frame_filename) { if(strcmp(l_frame_filename, fw->frame_filename) == 0) { /* filename has not changed, keep the current timestamp in that case */ new_timestamp = fw->frame_timestamp; } } } g_free(fw->frame_filename); fw->frame_filename = l_frame_filename; } fw->frame_timestamp = new_timestamp; fw->image_id = image_id; fw->frame_nr = frame_nr; navi_frame_widget_replace2(fw); } /* end navi_frame_widget_replace */ /* --------------------------------- * navi_refresh_dyn_table * --------------------------------- * the refresh does read pixmap data for all items in the dyn_table * (from thumbnail_file or gimp_image_thumbnail) * the labels are refreshed too. */ static void navi_refresh_dyn_table(gint32 frame_nr) { gint32 l_frame_nr; gint32 l_frame_nr_prev; gint32 l_count; if(gap_debug) printf("navi_refresh_dyn_table: START frame_nr:%d\n", (int)frame_nr); naviD->dyn_topframenr = navi_constrain_dyn_topframenr(frame_nr); l_frame_nr = naviD->dyn_topframenr; l_frame_nr_prev = -1; for(l_count = 0; l_count < naviD->dyn_rows; l_count++) { l_frame_nr = CLAMP(l_frame_nr , naviD->ainfo_ptr->first_frame_nr , naviD->ainfo_ptr->last_frame_nr ); if(gap_debug) printf("navi_refresh_dyn_table: l_frame_nr:%d\n", (int)l_frame_nr); if(l_frame_nr == l_frame_nr_prev) { /* dont repeat display of the last frame again (use -1 instead) */ navi_frame_widget_replace (-1, -1, l_count); } else { navi_frame_widget_replace (naviD->active_imageid, l_frame_nr, l_count); } l_frame_nr_prev = l_frame_nr; l_frame_nr += naviD->vin_ptr->timezoom; } } /* end navi_refresh_dyn_table */ /* --------------------------------- * navi_dyn_adj_set_pos * --------------------------------- */ static void navi_dyn_adj_set_pos(void) { gint32 adj_intval; gint32 topval; if(naviD == NULL) { return; } adj_intval = GTK_ADJUSTMENT(naviD->dyn_adj)->value; topval = (naviD->dyn_topframenr - naviD->ainfo_ptr->first_frame_nr) / naviD->vin_ptr->timezoom; topval++; if(gap_debug) { printf("navi_dyn_adj_set_pos: adj_intval:%d topval:%d\n" , (int)adj_intval , (int)topval ); } if(adj_intval != topval) { gtk_adjustment_set_value(GTK_ADJUSTMENT(naviD->dyn_adj), (gdouble)topval); } } /* end navi_dyn_adj_set_pos */ /* --------------------------------- * navi_dyn_adj_changed_callback * --------------------------------- */ static void navi_dyn_adj_changed_callback(GtkWidget *wgt, gpointer data) { gint32 adj_intval; gint32 dyn_topframenr; if(naviD == NULL) { return; } adj_intval = (gint32)(GTK_ADJUSTMENT(naviD->dyn_adj)->value + 0.5); if(gap_debug) printf("navi_dyn_adj_changed_callback: adj_intval:%d dyn_topframenr:%d\n", (int)adj_intval, (int)naviD->dyn_topframenr); GTK_ADJUSTMENT(naviD->dyn_adj)->value = adj_intval; dyn_topframenr = ((adj_intval -1) * naviD->vin_ptr->timezoom) + naviD->ainfo_ptr->first_frame_nr; dyn_topframenr = navi_constrain_dyn_topframenr(dyn_topframenr); if(naviD->dyn_topframenr != dyn_topframenr) { naviD->dyn_topframenr = dyn_topframenr; navi_refresh_dyn_table(dyn_topframenr); } } /* end navi_dyn_adj_changed_callback */ /* --------------------------------- * navi_dyn_adj_set_limits * --------------------------------- */ static void navi_dyn_adj_set_limits(void) { gdouble upper_limit; gdouble lower_limit; gdouble page_increment; gdouble page_size; gdouble value; gint32 frame_cnt_zoomed; if(naviD == NULL) { return; } if(naviD->dyn_adj == NULL) { return; } frame_cnt_zoomed = naviD->ainfo_ptr->frame_cnt / naviD->vin_ptr->timezoom; if(naviD->vin_ptr->timezoom > 1) { /* if there is a rest add 1 to make the last frame, * (that should never be filtered out by timezoom) reachable */ frame_cnt_zoomed++; } lower_limit = 1.0; upper_limit = lower_limit + frame_cnt_zoomed; page_size = (gdouble)naviD->dyn_rows; page_increment = (gdouble)((gint32)page_size); value = GTK_ADJUSTMENT(naviD->dyn_adj)->value; if(gap_debug) { printf("\n cnt_zoomed : %d dyn_rows:%d\n", (int)frame_cnt_zoomed ,(int)naviD->dyn_rows); printf("lower_limit %f\n", (float)lower_limit ); printf("upper_limit %f\n", (float)upper_limit ); printf("page_size %f\n", (float) page_size); printf("page_increment %f\n", (float)page_increment ); printf("value %f\n", (float)value ); } GTK_ADJUSTMENT(naviD->dyn_adj)->lower = lower_limit; GTK_ADJUSTMENT(naviD->dyn_adj)->upper = upper_limit; GTK_ADJUSTMENT(naviD->dyn_adj)->page_increment = page_increment; GTK_ADJUSTMENT(naviD->dyn_adj)->value = MIN(value, upper_limit); GTK_ADJUSTMENT(naviD->dyn_adj)->page_size = page_size; } /* end navi_dyn_adj_set_limits */ /* --------------------------------- * navi_frame_widget_init_empty * --------------------------------- * this procedure does initialize * the passed frame_widget, by creating all * the gtk_widget stuff to build up the frame_widget */ static void navi_frame_widget_init_empty (FrameWidget *fw) { GtkWidget *alignment; if(gap_debug) printf("navi_frame_widget_init_empty START\n"); /* create all sub-widgets for the given frame widget */ fw->image_id = -1; fw->frame_nr = -1; fw->pv_ptr = NULL; fw->width = -1; fw->height = -1; fw->frame_timestamp = 0; fw->frame_filename = NULL; fw->vbox = gtk_vbox_new (FALSE, 1); /* the hbox */ fw->hbox = gtk_hbox_new (FALSE, 1); /* Create an EventBox (container for labels and the preview drawing_area) * used to handle selection events */ fw->event_box = gtk_event_box_new (); gtk_container_add (GTK_CONTAINER (fw->event_box), fw->hbox); gtk_widget_set_events (fw->event_box, GDK_BUTTON_PRESS_MASK); g_signal_connect (G_OBJECT (fw->event_box), "button_press_event", G_CALLBACK (frame_widget_preview_events), fw); gtk_box_pack_start (GTK_BOX (fw->vbox), fw->event_box, FALSE, FALSE, 1); /* the frame number label */ fw->number_label = gtk_label_new ("######"); gtk_box_pack_start (GTK_BOX (fw->hbox), fw->number_label, FALSE, FALSE, 2); gtk_widget_show (fw->number_label); /* The frame preview */ alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); gtk_box_pack_start (GTK_BOX (fw->hbox), alignment, FALSE, FALSE, 2); gtk_widget_show (alignment); fw->pv_ptr = gap_pview_new( naviD->image_width + 4 , naviD->image_height + 4 , NAVI_CHECK_SIZE , NULL /* no aspect_frame is used */ ); gtk_widget_set_events (fw->pv_ptr->da_widget, GDK_EXPOSURE_MASK); gtk_container_add (GTK_CONTAINER (alignment), fw->pv_ptr->da_widget); gtk_widget_show (fw->pv_ptr->da_widget); g_signal_connect (G_OBJECT (fw->pv_ptr->da_widget), "event", G_CALLBACK (frame_widget_preview_events), fw); /* the frame timing label */ fw->time_label = gtk_label_new ("##:##:###"); gtk_box_pack_start (GTK_BOX (fw->hbox), fw->time_label, FALSE, FALSE, 2); gtk_widget_show (fw->time_label); gtk_widget_show (fw->hbox); gtk_widget_show (fw->event_box); gtk_widget_show (fw->vbox); if(gap_debug) printf("navi_frame_widget_init_empty END\n"); } /* end navi_frame_widget_init_empty */ /* --------------------------------- * navi_dyn_table_set_size * --------------------------------- * init and attach frame_widgets from naviD->frame_widget_tab * to dyn_tab * return 0 if number of rows was not changed, * -n if shrinked by n rows * +n if expanded by n rows */ static gint navi_dyn_table_set_size(gint win_height) { gint l_row; gint l_new_rows; gint l_resize_flag; l_new_rows = MIN((win_height / MAX(naviD->item_height,10)), MAX_DYN_ROWS); if(gap_debug) printf("navi_dyn_table_set_size: START (old)fw_tab_used_count:%d (old)dyn_rows:%d (new)l_new_rows:%d\n" , (int)naviD->fw_tab_used_count , (int)naviD->dyn_rows , (int)l_new_rows ); l_resize_flag = l_new_rows - naviD->dyn_rows; if(l_resize_flag < 0) { /* gtk_table_resize does not work if we want less rows * and the rows already have widgets attached. * we first have to destroy the attached widgets. */ for(l_row = l_new_rows; l_row < naviD->dyn_rows; l_row++) { FrameWidget *fw; if(gap_debug) printf("navi_dyn_table_set_size: destroy row:%d\n", (int)l_row); fw = &naviD->frame_widget_tab[l_row]; gap_pview_reset(fw->pv_ptr); if(fw->frame_filename) g_free(fw->frame_filename); gtk_widget_destroy(fw->vbox); navi_frame_widget_init_empty(fw); } naviD->fw_tab_used_count = MIN(l_new_rows, naviD->fw_tab_used_count); } if(l_new_rows != naviD->dyn_rows) { gtk_table_resize(GTK_TABLE(naviD->dyn_table), l_new_rows, 1); } /* initialize as much frame_widgets as needed * NOTE: frame_widgets in the frame_widget_tab are initialzed * only once, and are kept even if dyn_table shrinks down * to less rows. * (they can be reused later if dyn_table expands again) */ for(l_row = naviD->fw_tab_used_count; l_row < l_new_rows; l_row++) { if(gap_debug) printf("navi_dyn_table_set_size: init row:%d\n", (int)l_row); navi_frame_widget_init_empty(&naviD->frame_widget_tab[l_row]); } naviD->fw_tab_used_count = l_row; /* attach frame_widgets as needed */ for(l_row = naviD->dyn_rows; l_row < l_new_rows; l_row++) { if(gap_debug) printf("navi_dyn_table_set_size: attach row:%d\n", (int)l_row); gtk_table_attach (GTK_TABLE (naviD->dyn_table) , naviD->frame_widget_tab[l_row].vbox , 0, 1 , l_row, l_row+1 , (GtkAttachOptions) (GTK_FILL | GTK_EXPAND) , (GtkAttachOptions) (GTK_FILL | GTK_EXPAND) , 0, 0); } naviD->dyn_rows = l_new_rows; navi_dyn_adj_set_limits(); if(gap_debug) printf("navi_dyn_table_set_size: END (result)fw_tab_used_count:%d (res)dyn_rows:%d flag:%d\n" , (int)naviD->fw_tab_used_count , (int)naviD->dyn_rows , (int)l_resize_flag ); return (l_resize_flag); } /* end navi_dyn_table_set_size */ /* --------------------------------- * p_set_acl_tracking_radio_buttons * --------------------------------- */ static void p_set_acl_tracking_radio_buttons(NaviDialog *naviD) { GtkWidget *radio_button; radio_button = naviD->acl_trace_off_toggle; if(naviD->vin_ptr) { switch(naviD->vin_ptr->active_layer_tracking) { case GAP_ACTIVE_LAYER_TRACKING_BY_NAME: radio_button = naviD->acl_trace_by_name_toggle; break; case GAP_ACTIVE_LAYER_TRACKING_BY_STACKPOS: radio_button = naviD->acl_trace_by_pos_toggle; break; default: radio_button = naviD->acl_trace_off_toggle; break; } } if(radio_button) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), TRUE); } } /* end p_set_acl_tracking_radio_buttons */ /* --------------------------------- * p_set_acl_tracking_mode * --------------------------------- */ static void p_set_acl_tracking_mode(NaviDialog *naviD, gint32 acl_tracking_mode) { if(acl_tracking_mode != naviD->vin_ptr->active_layer_tracking) { naviD->vin_ptr->active_layer_tracking = acl_tracking_mode; if(naviD->ainfo_ptr) { /* write new framerate to video info file */ gap_vin_set_common(naviD->vin_ptr, naviD->ainfo_ptr->basename); } } } /* end p_set_acl_tracking_mode */ /* --------------------------------- * p_acl_tracking_off_callback * --------------------------------- */ static void p_acl_tracking_off_callback(GtkWidget *widget, NaviDialog *naviD) { if((naviD) && (GTK_TOGGLE_BUTTON (widget)->active)) { p_set_acl_tracking_mode(naviD, GAP_ACTIVE_LAYER_TRACKING_OFF); } } /* end p_acl_tracking_off_callback */ /* --------------------------------- * p_acl_tracking_by_name_callback * --------------------------------- */ static void p_acl_tracking_by_name_callback(GtkWidget *widget, NaviDialog *naviD) { if((naviD) && (GTK_TOGGLE_BUTTON (widget)->active)) { p_set_acl_tracking_mode(naviD, GAP_ACTIVE_LAYER_TRACKING_BY_NAME); } } /* end p_acl_tracking_by_name_callback */ /* --------------------------------- * p_acl_tracking_by_pos_callback * --------------------------------- */ static void p_acl_tracking_by_pos_callback(GtkWidget *widget, NaviDialog *naviD) { if((naviD) && (GTK_TOGGLE_BUTTON (widget)->active)) { p_set_acl_tracking_mode(naviD, GAP_ACTIVE_LAYER_TRACKING_BY_STACKPOS); } } /* end p_acl_tracking_by_pos_callback */ /* --------------------------------- * p_create_acl_tracking_widgets * --------------------------------- */ GtkWidget * p_create_acl_tracking_widgets(NaviDialog *naviD) { GtkWidget *label; GtkWidget *util_box; GtkWidget *radio_table; GtkWidget *radio_button; GSList *radio_group = NULL; gint l_idx; gboolean l_radio_pressed; util_box = gtk_hbox_new (FALSE, 1); /* the active layer tracking label */ label = gtk_label_new (_("AL-Tracking:")); gtk_box_pack_start (GTK_BOX (util_box), label, FALSE, FALSE, 2); gtk_widget_show (label); /* radio_table */ radio_table = gtk_table_new (1, 3, FALSE); l_idx = 0; /* radio button active layer tracking OFF */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("OFF") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach ( GTK_TABLE (radio_table), radio_button, l_idx, l_idx+1 , 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0); naviD->acl_trace_off_toggle = radio_button; l_radio_pressed = TRUE; if(naviD->vin_ptr) { l_radio_pressed = (naviD->vin_ptr->active_layer_tracking == GAP_ACTIVE_LAYER_TRACKING_OFF); } gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button, _("Disable active layer tracking"), NULL); gtk_widget_show (radio_button); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (p_acl_tracking_off_callback), naviD); l_idx = 1; /* radio button thres_mode HSV */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Name") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach ( GTK_TABLE (radio_table), radio_button, l_idx, l_idx+1, 0, 1 , GTK_FILL | GTK_EXPAND, 0, 0, 0); naviD->acl_trace_by_name_toggle = radio_button; l_radio_pressed = FALSE; if(naviD->vin_ptr) { l_radio_pressed = (naviD->vin_ptr->active_layer_tracking == GAP_ACTIVE_LAYER_TRACKING_BY_NAME); } gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button, _("Enable tracking of the active layer by name at framechanges"), NULL); gtk_widget_show (radio_button); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (p_acl_tracking_by_name_callback), naviD); l_idx = 2; /* radio button thres_mode VAL */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Pos") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach ( GTK_TABLE (radio_table), radio_button, l_idx, l_idx+1, 0, 1 , GTK_FILL | GTK_EXPAND, 0, 0, 0); naviD->acl_trace_by_pos_toggle = radio_button; l_radio_pressed = FALSE; if(naviD->vin_ptr) { l_radio_pressed = (naviD->vin_ptr->active_layer_tracking == GAP_ACTIVE_LAYER_TRACKING_BY_STACKPOS); } gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button, _("Enable tracking of the active layer by stack position at framechanges"), NULL); gtk_widget_show (radio_button); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (p_acl_tracking_by_pos_callback), naviD); gtk_box_pack_start (GTK_BOX (util_box), radio_table, FALSE, FALSE, 2); gtk_widget_show (radio_table); return(util_box); } /* end p_create_acl_tracking_widgets */ /* ------------------------ * navi_dialog_create * ------------------------ */ GtkWidget * navi_dialog_create (GtkWidget* shell, gint32 image_id) { GtkWidget *vbox; GtkWidget *vbox2; GtkWidget *vscale; GtkWidget *util_box; GtkWidget *button_box; GtkWidget *label; GtkWidget *spinbutton; GtkWidget *menu_item; GtkObject *adj; char *l_basename; char frame_nr_to_char[20]; if(gap_debug) printf("navi_dialog_create\n"); if (naviD) { return naviD->vbox; } l_basename = NULL; g_snprintf(frame_nr_to_char, sizeof(frame_nr_to_char), "0000 - 0000"); naviD = g_new (NaviDialog, 1); /* init the global naviD structure */ naviD->del_button = NULL; naviD->dup_button = NULL; naviD->framerate_adj = NULL; naviD->timezoom_adj = NULL; naviD->acl_trace_off_toggle = NULL; naviD->acl_trace_by_name_toggle = NULL; naviD->acl_trace_by_pos_toggle = NULL; naviD->dyn_adj = NULL; /* disable procedure navi_dyn_adj_set_limits before this widget is created */ naviD->sel_range_list = NULL; /* startup without selection */ naviD->prev_selected_framnr = -1; naviD->fw_tab_used_count = 0; /* nothing used/initialized in the frame_widget table */ naviD->dyn_rows = 0; /* no rows in the dyn table (are added later at 1st resize while creation) */ naviD->waiting_cursor = FALSE; naviD->cursor_wait = gdk_cursor_new (GDK_WATCH); naviD->cursor_acitve = NULL; /* NULL: use the default cursor */ naviD->shell = shell; naviD->OpenFrameImagesList = NULL; naviD->OpenFrameImagesCount = 0; naviD->any_imageid = -1; naviD->cycle_time = 1000; /* polling cylcle of 1 sec */ naviD->timer = -1; naviD->active_imageid = image_id; /* naviD->ainfo_ptr = navi_get_ainfo(naviD->active_imageid, NULL); */ naviD->ainfo_ptr = NULL; naviD->framerange_number_label = NULL; navi_reload_ainfo_force(image_id); if(naviD->ainfo_ptr != NULL) { g_snprintf(frame_nr_to_char, sizeof(frame_nr_to_char), "%06d - %06d" , (int)naviD->ainfo_ptr->first_frame_nr , (int)naviD->ainfo_ptr->last_frame_nr); l_basename = naviD->ainfo_ptr->basename; } naviD->vin_ptr = gap_vin_get_all(l_basename); naviD->image_width = 0; naviD->image_height = 0; naviD->preview_size = navi_get_preview_size(); if (naviD->preview_size > 0) { navi_preview_extents (); } /* The main vbox */ naviD->vbox = gtk_event_box_new (); vbox = gtk_vbox_new (FALSE, 1); gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); gtk_container_add (GTK_CONTAINER (naviD->vbox), vbox); /* The image menu */ util_box = gtk_hbox_new (FALSE, 1); gtk_box_pack_start (GTK_BOX (vbox), util_box, FALSE, FALSE, 0); /* The image combobox (is replaced at navi_refresh_image_menu) */ naviD->image_combo = NULL; naviD->image_combo_hbox = util_box; navi_refresh_image_menu(); gtk_widget_show (util_box); /* The popup menu (copy/cut/paste) */ naviD->ops_menu = gtk_menu_new (); /* menu_item copy */ menu_item = gtk_menu_item_new_with_label (_("Copy")); gtk_container_add (GTK_CONTAINER (naviD->ops_menu), menu_item); gtk_widget_show (menu_item); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (edit_copy_callback), naviD); naviD->copy_menu_item = menu_item; /* menu_item cut */ menu_item = gtk_menu_item_new_with_label (_("Cut")); gtk_container_add (GTK_CONTAINER (naviD->ops_menu), menu_item); gtk_widget_show (menu_item); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (edit_cut_callback), naviD); naviD->cut_menu_item = menu_item; /* menu_item paste before */ menu_item = gtk_menu_item_new_with_label (_("Paste Before")); gtk_container_add (GTK_CONTAINER (naviD->ops_menu), menu_item); gtk_widget_show (menu_item); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (edit_pasteb_callback), naviD); naviD->pasteb_menu_item = menu_item; /* menu_item copy */ menu_item = gtk_menu_item_new_with_label (_("Paste After")); gtk_container_add (GTK_CONTAINER (naviD->ops_menu), menu_item); gtk_widget_show (menu_item); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (edit_pastea_callback), naviD); naviD->pastea_menu_item = menu_item; /* menu_item copy */ menu_item = gtk_menu_item_new_with_label (_("Paste Replace")); gtk_container_add (GTK_CONTAINER (naviD->ops_menu), menu_item); gtk_widget_show (menu_item); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (edit_paster_callback), naviD); naviD->paster_menu_item = menu_item; /* menu_item copy */ menu_item = gtk_menu_item_new_with_label (_("Clear Video Buffer")); gtk_container_add (GTK_CONTAINER (naviD->ops_menu), menu_item); gtk_widget_show (menu_item); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (edit_clrpaste_callback), naviD); naviD->clrpaste_menu_item = menu_item; /* menu_item Select All */ menu_item = gtk_menu_item_new_with_label (_("Select All")); gtk_container_add (GTK_CONTAINER (naviD->ops_menu), menu_item); gtk_widget_show (menu_item); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (navi_sel_all_callback), naviD); naviD->sel_all_menu_item = menu_item; /* menu_item Select None */ menu_item = gtk_menu_item_new_with_label (_("Select None")); gtk_container_add (GTK_CONTAINER (naviD->ops_menu), menu_item); gtk_widget_show (menu_item); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (navi_sel_none_callback), naviD); naviD->sel_none_menu_item = menu_item; gtk_widget_show (naviD->ops_menu); /* radio button box for active layer tracking */ util_box = p_create_acl_tracking_widgets(naviD); gtk_box_pack_start (GTK_BOX (vbox), util_box, FALSE, FALSE, 0); gtk_widget_show (util_box); /* the Framerange label */ util_box = gtk_hbox_new (FALSE, 1); gtk_box_pack_start (GTK_BOX (vbox), util_box, FALSE, FALSE, 0); label = gtk_label_new (_("Videoframes:")); gtk_box_pack_start (GTK_BOX (util_box), label, FALSE, FALSE, 2); gtk_widget_show (label); /* the max frame number label */ naviD->framerange_number_label = gtk_label_new (frame_nr_to_char); gtk_box_pack_start (GTK_BOX (util_box), naviD->framerange_number_label, FALSE, FALSE, 2); gtk_widget_show (naviD->framerange_number_label); gtk_widget_show (util_box); /* framerate spinbutton */ naviD->framerate_box = util_box = gtk_hbox_new (FALSE, 1); gtk_box_pack_start (GTK_BOX (vbox), util_box, FALSE, FALSE, 0); label = gtk_label_new (_("Framerate:")); gtk_box_pack_start (GTK_BOX (util_box), label, FALSE, FALSE, 2); gtk_widget_show (label); spinbutton = gimp_spin_button_new (&adj, /* return value (the adjustment) */ naviD->vin_ptr->framerate, /* initial_val */ 1.0, /* umin */ 100.0, /* umax */ 1.0, /* sstep */ 10.0, /* pagestep */ 0.0, /* page_size */ 1.0, /* climb_rate */ 4 /* digits */ ); naviD->framerate_adj = adj; gtk_box_pack_start (GTK_BOX (util_box), spinbutton, TRUE, TRUE, 0); g_signal_connect (G_OBJECT (naviD->framerate_adj), "value_changed", G_CALLBACK (navi_framerate_spinbutton_update), naviD); gtk_widget_show (spinbutton); gimp_help_set_help_data (spinbutton, _("Set framerate in frames/sec"), NULL); gtk_widget_show (util_box); /* timezoom spinbutton */ naviD->timezoom_box = util_box = gtk_hbox_new (FALSE, 1); gtk_box_pack_start (GTK_BOX (vbox), util_box, FALSE, FALSE, 0); label = gtk_label_new (_("Timezoom:")); gtk_box_pack_start (GTK_BOX (util_box), label, FALSE, FALSE, 2); gtk_widget_show (label); spinbutton = gimp_spin_button_new (&adj, /* return value (the adjustment) */ naviD->vin_ptr->framerate, /* initial_val */ 1.0, /* umin */ 500.0, /* umax */ 1.0, /* sstep */ 10.0, /* pagestep */ 0.0, /* page_size */ 1.0, /* climb_rate */ 0 /* digits */ ); naviD->timezoom_adj = adj; gtk_box_pack_start (GTK_BOX (util_box), spinbutton, TRUE, TRUE, 0); g_signal_connect (G_OBJECT (naviD->timezoom_adj), "value_changed", G_CALLBACK (navi_timezoom_spinbutton_update), naviD); gtk_widget_show (spinbutton); gimp_help_set_help_data (spinbutton, _("Show only every Nth frame"), NULL); gtk_widget_show (util_box); /* The frame (that will contain the dyn_table) */ naviD->dyn_frame = gimp_frame_new (NULL); naviD->in_dyn_table_sizeinit = TRUE; g_signal_connect (G_OBJECT (naviD->dyn_frame), "size_allocate", G_CALLBACK (navi_dyn_frame_size_allocate), NULL); gtk_widget_set_size_request (naviD->dyn_frame , -1 /* LIST_WIDTH */ , LIST_HEIGHT /* LIST_HEIGHT */ ); gtk_box_pack_start (GTK_BOX (vbox), naviD->dyn_frame, TRUE, TRUE, 2); gtk_widget_show (naviD->dyn_frame); /* hbox for dyn_table and vscale */ naviD->hbox = gtk_hbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (naviD->dyn_frame), naviD->hbox); gtk_widget_show (naviD->hbox); /* dyn_table has 1 upto MAX_DYN_ROWS and always just 1 column */ naviD->dyn_table = gtk_table_new (1, 1, TRUE); navi_dyn_table_set_size(LIST_HEIGHT); gtk_widget_show (naviD->dyn_table); gtk_box_pack_start (GTK_BOX (naviD->hbox), naviD->dyn_table, TRUE, TRUE, 2); /* The vbox for vscale with arrow buttons */ vbox2 = gtk_vbox_new (FALSE, 1); gtk_widget_show (vbox2); gtk_box_pack_start (GTK_BOX (naviD->hbox), vbox2, FALSE, FALSE, 2); { gdouble upper_max; gdouble initial_val; upper_max = naviD->ainfo_ptr->frame_cnt; initial_val = 1 + ((naviD->ainfo_ptr->curr_frame_nr - naviD->ainfo_ptr->first_frame_nr) / naviD->vin_ptr->timezoom); naviD->dyn_adj = gtk_adjustment_new (initial_val , 1 , upper_max , 1.0, 1.0, 0.0 ); /* vscale = gtk_vscale_new (GTK_ADJUSTMENT(naviD->dyn_adj)); */ vscale = gtk_vscrollbar_new (GTK_ADJUSTMENT(naviD->dyn_adj)); gtk_range_set_update_policy (GTK_RANGE (vscale), GTK_UPDATE_DELAYED); /* GTK_UPDATE_CONTINUOUS */ gtk_box_pack_start (GTK_BOX (vbox2), vscale, TRUE, TRUE, 0); g_signal_connect (naviD->dyn_adj, "value_changed", G_CALLBACK (navi_dyn_adj_changed_callback), naviD); gtk_widget_show (vscale); } /* The ops buttons */ button_box = ops_button_box_new (naviD->shell, frames_ops_buttons, OPS_BUTTON_NORMAL); gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 2); gtk_widget_show (button_box); /* The VCR ops buttons */ button_box = ops_button_box_new (naviD->shell, vcr_ops_buttons, OPS_BUTTON_NORMAL); gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 2); gtk_widget_show (button_box); /* the GimpProgressBar */ { GtkWidget *progressbar; progressbar = gimp_progress_bar_new(); gtk_widget_set_size_request (progressbar, 100, -1); gtk_widget_show (progressbar); gtk_box_pack_start (GTK_BOX (vbox), progressbar, FALSE, FALSE, 2); } g_signal_connect (G_OBJECT ( naviD->dyn_frame), "scroll_event", G_CALLBACK (navi_scroll_event_cb), naviD); gtk_widget_show (vbox); gtk_widget_show (naviD->vbox); if(gap_debug) printf("navi_dialog_create END\n"); return naviD->vbox; } /* end navi_dialog_create */ /* --------------------------------- * the navigator MAIN dialog * --------------------------------- */ int gap_navigator(gint32 image_id) { GtkWidget *shell; GtkWidget *subshell; if(gap_debug) fprintf(stderr, "\nSTARTing gap_navigator_dialog\n"); gimp_ui_init ("gap_navigator", FALSE); gap_stock_init(); /* The main shell */ shell = gimp_dialog_new (_("Video Navigator"), "gap_navigator", NULL, 0, gimp_standard_help_func, PLUGIN_HELP_ID, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL /* end marker for va_args */ ); /* The subshell (toplevel vbox) */ subshell = gtk_vbox_new (FALSE, 1); gtk_container_add (GTK_CONTAINER (GTK_DIALOG (shell)->vbox), subshell); if(gap_debug) printf("BEFORE navi_dialog_create\n"); /* The naviD dialog structure */ navi_dialog_create (shell, image_id); if(gap_debug) printf("AFTER navi_dialog_create\n"); gtk_box_pack_start (GTK_BOX (subshell), naviD->vbox, TRUE, TRUE, 0); gtk_widget_show (subshell); gtk_widget_show (shell); frames_dialog_flush(); navi_scroll_to_current_frame_nr(); naviD->timer = g_timeout_add (naviD->cycle_time, (GtkFunction)navi_dialog_poll, NULL); naviD->in_dyn_table_sizeinit = FALSE; if(gap_debug) printf("BEFORE gimp_dialog_run\n"); gimp_dialog_run (GIMP_DIALOG (shell)); if (naviD->timer >= 0) { g_source_remove(naviD->timer); naviD->timer = -1; } navi_pviews_reset(); gtk_widget_destroy (shell); if(gap_debug) printf("END gap_navigator_dialog\n"); return 0; } /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX * Some Code Parts copied from gimp-1.2/app directory * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ /* --------------------------------------- start copy of gimp-1.1.14/app/ops_buttons.c */ /* -- 2003.06.03 hof: changed code by using stock buttons instead of xpm pixmap data */ static gboolean ops_button_pressed_callback (GtkWidget*, GdkEventButton*, gpointer); static void ops_button_extended_callback (GtkWidget*, gpointer); GtkWidget * ops_button_box_new (GtkWidget *parent, OpsButton *ops_button, OpsButtonType ops_type) { GtkWidget *button; GtkWidget *image; GtkWidget *button_box; GSList *group = NULL; gtk_widget_realize (parent); button_box = gtk_hbox_new (TRUE, 1); while (ops_button->stock_id) { switch (ops_type) { case OPS_BUTTON_NORMAL : button = gtk_button_new (); image = gtk_image_new_from_stock (ops_button->stock_id, GTK_ICON_SIZE_BUTTON); gtk_container_add (GTK_CONTAINER (button), image); gtk_widget_show (image); /* need to know del_button and dup_button * for setting sensitive when selection was made */ if(ops_button->callback == OPS_BUTTON_FUNC(navi_dialog_frames_delete_frame_callback)) { gtk_widget_set_sensitive(button, FALSE); naviD->del_button = button; } if(ops_button->callback == OPS_BUTTON_FUNC(navi_dialog_frames_duplicate_frame_callback)) { gtk_widget_set_sensitive(button, FALSE); naviD->dup_button = button; } break; case OPS_BUTTON_RADIO : button = gtk_radio_button_new (group); group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button)); gtk_container_set_border_width (GTK_CONTAINER (button), 0); gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE); break; default : button = NULL; /*stop compiler complaints */ g_error ("ops_button_box_new: unknown type %d\n", ops_type); break; } if (ops_button->ext_callbacks == NULL) { g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK (ops_button->callback), NULL); } else { gtk_widget_set_events(button, GDK_BUTTON_PRESS_MASK); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (ops_button_pressed_callback), ops_button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (ops_button_extended_callback), ops_button); } gimp_help_set_help_data (button, gettext (ops_button->tooltip), ops_button->private_tip); gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0); gtk_widget_show (button); ops_button->widget = button; ops_button->modifier = OPS_BUTTON_MODIFIER_NONE; ops_button++; } return (button_box); } static gboolean ops_button_pressed_callback (GtkWidget *widget, GdkEventButton *bevent, gpointer client_data) { OpsButton *ops_button; if (client_data == NULL) { return FALSE; } ops_button = (OpsButton*)client_data; if (bevent->state & GDK_SHIFT_MASK) { if (bevent->state & GDK_CONTROL_MASK) ops_button->modifier = OPS_BUTTON_MODIFIER_SHIFT_CTRL; else ops_button->modifier = OPS_BUTTON_MODIFIER_SHIFT; } else if (bevent->state & GDK_CONTROL_MASK) ops_button->modifier = OPS_BUTTON_MODIFIER_CTRL; else if (bevent->state & GDK_MOD1_MASK) ops_button->modifier = OPS_BUTTON_MODIFIER_ALT; else ops_button->modifier = OPS_BUTTON_MODIFIER_NONE; return FALSE; } static void ops_button_extended_callback (GtkWidget *widget, gpointer client_data) { OpsButton *ops_button; g_return_if_fail (client_data != NULL); ops_button = (OpsButton*)client_data; if (ops_button->modifier > OPS_BUTTON_MODIFIER_NONE && ops_button->modifier < OPS_BUTTON_MODIFIER_LAST) { if (ops_button->ext_callbacks[ops_button->modifier - 1] != NULL) (ops_button->ext_callbacks[ops_button->modifier - 1]) (widget, NULL); else (ops_button->callback) (widget, NULL); } else (ops_button->callback) (widget, NULL); ops_button->modifier = OPS_BUTTON_MODIFIER_NONE; } /* --------------------------------------- end copy of gimp-1.1.14/app/ops_buttons.c */ gimp-gap-2.6.0+dfsg.orig/gap/gap_story_render_lossless.c0000755000175000017500000012753011212030253023170 0ustar thibautthibaut/* gap_story_render_lossless.c * * * GAP storyboard pseudo rendering for lossless video cut. * (includes checks if frames in the referenced video source * can be provided 1:1 as raw data chunks to the calling encoder * and performs the raw data chunk fetch where possible * and requested by the calling encoder) * * Copyright (C) 2008 Wolfgang Hofer * * * 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.06.11 hof - created (moved stuff from the former gap_gve_story_render_processor to this new module) */ #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* ---------------------------------------------------- * p_debug_print_vcodec_missmatch * ---------------------------------------------------- */ static void p_debug_print_vcodec_missmatch(const char *videofile ,GapCodecNameElem *vcodec_list ,const char *vcodec_name_chunk ) { printf("chunk_fetch not possible, video codec missmatch. "); printf("videofile:"); if(videofile) { printf("%s", videofile); } else { printf("NULL"); } printf(", vcodec_list:"); if(vcodec_list) { GapCodecNameElem *codec_elem; for(codec_elem = vcodec_list; codec_elem != NULL; codec_elem = (GapCodecNameElem *) codec_elem->next) { if(codec_elem->codec_name) { printf("%s ", codec_elem->codec_name); } } } else { printf("NULL"); } printf(", vcodec_name_chunk:"); if(vcodec_name_chunk) { printf("%s", vcodec_name_chunk); } else { printf("NULL"); } printf("\n"); } /* end p_debug_print_vcodec_missmatch */ /* ---------------------------------------------------- * p_check_vcodec_name * ---------------------------------------------------- * return TRUE if vcodec_name_chunk is found in the * specified list of compatible codecs names * (The vcodec_list is provided by the calling encoder * and includes a list of compatible codec names for lossles video cut purpose) * FALSE if vcodec check condition failed. * * Note: vcodec_name_chunk NULL (unknown) is never compatible, * an empty list (vcodec_list == NULL) matches to * all codec names (but not to unknown codec) */ static gboolean p_check_vcodec_name(gint32 check_flags , GapCodecNameElem *vcodec_list, const char *vcodec_name_chunk) { if (check_flags & GAP_VID_CHCHK_FLAG_VCODEC_NAME) { if(vcodec_name_chunk == NULL) { return (FALSE); } if(vcodec_list == NULL) { return (TRUE); } else { GapCodecNameElem *codec_elem; for(codec_elem = vcodec_list; codec_elem != NULL; codec_elem = (GapCodecNameElem *) codec_elem->next) { if(codec_elem->codec_name) { if(strcmp(codec_elem->codec_name, vcodec_name_chunk) == 0) { return (TRUE); } } } } return (FALSE); } return (TRUE); } /* end p_check_vcodec_name */ /* ---------------------------------------------------- * p_check_flags_for_matching_vcodec * ---------------------------------------------------- * return TRUE if vcodec names fit to the specified check_flags conditions, * FALSE if vcodec check condition failed. * * Note: vcodec_name_encoder value * (or NULL pointer) matches always. */ static void p_check_flags_for_matching_vcodec(gint32 check_flags, gint32 *check_flags_result , const char *videofile, GapCodecNameElem *vcodec_list, const char *vcodec_name_chunk) { if (TRUE == p_check_vcodec_name(check_flags ,vcodec_list ,vcodec_name_chunk)) { *check_flags_result |= (check_flags & GAP_VID_CHCHK_FLAG_VCODEC_NAME); } else { if(gap_debug) { p_debug_print_vcodec_missmatch(videofile, vcodec_list, vcodec_name_chunk); } } } /* end p_check_flags_for_matching_vcodec */ /* ---------------------------------------------------- * p_chunk_fetch_from_single_image * ---------------------------------------------------- * This procedure fetches frame images from disc * * if possible and if the check conditions according to specified check_flags * are fulfilled. * * TODO: GAP_VID_CHCHK_FLAG_SIZE * (need to parsing image or load as image and let gimp do the parsing * such a check can significantly reduce performance) * * return FALSE if fetch not possible or failed. */ static gboolean p_chunk_fetch_from_single_image(const char *videofile , unsigned char *video_frame_chunk_data // IN/OUT , gint32 video_frame_chunk_maxsize // IN , gint32 *video_frame_chunk_hdr_size // OUT , gint32 *video_frame_chunk_size // OUT , GapCodecNameElem *vcodec_list // IN , gint32 check_flags // IN ) { const char *vcodec_name_chunk; gint32 fileSize; gint32 bytesRead; *video_frame_chunk_size = 0; *video_frame_chunk_hdr_size = 0; vcodec_name_chunk = NULL; /* no need to check GAP_VID_CHCHK_FLAG_FULL_FRAME * (single image fetch is always a full frame) */ if (check_flags & GAP_VID_CHCHK_FLAG_MPEG_INTEGRITY) { if(gap_debug) { printf("p_chunk_fetch_from_single_image: single image never fits MPEG_INTEGRITY (file:%s)\n" ,videofile ); } return (FALSE); } fileSize = gap_file_get_filesize(videofile); if (fileSize > video_frame_chunk_maxsize) { if(gap_debug) { printf("p_chunk_fetch_from_single_image: fileSize:%d biiger than max chunk buffer:%d (file:%s)\n" ,(int)fileSize ,(int)video_frame_chunk_maxsize ,videofile ); } return (FALSE); } if (check_flags & GAP_VID_CHCHK_FLAG_JPG) { bytesRead = gap_file_load_file_segment(videofile ,video_frame_chunk_data ,0 /* seek_index, start byte of datasegment in file */ ,16 /* segment size in byets (must be a multiple of 4) */ ); if(TRUE != GVA_util_check_jpg_picture( video_frame_chunk_data , 32 /* video_frame_chunk_size */ , 0 /* max_check_size */ , video_frame_chunk_hdr_size)) { if(gap_debug) { printf("p_chunk_fetch_from_single_image: not a JPEG file (file:%s)\n" ,videofile ); } return (FALSE); } vcodec_name_chunk = "JPEG"; } if (check_flags & GAP_VID_CHCHK_FLAG_PNG) { bytesRead = gap_file_load_file_segment(videofile ,video_frame_chunk_data ,0 /* seek_index, start byte of datasegment in file */ ,16 /* segment size in byets (must be a multiple of 4) */ ); if(TRUE != GVA_util_check_png_picture( video_frame_chunk_data , 32 /* video_frame_chunk_size */ , 0 /* max_check_size */ , video_frame_chunk_hdr_size)) { if(gap_debug) { printf("p_chunk_fetch_from_single_image: not a PNG file (file:%s)\n" ,videofile ); } return (FALSE); } vcodec_name_chunk = "PNG "; } if (vcodec_name_chunk == NULL) { if (check_flags & GAP_VID_CHCHK_FLAG_VCODEC_NAME) { vcodec_name_chunk = NULL; // TODO p_get_vcodec_name_by_magic_number .... } } if (TRUE != p_check_vcodec_name(check_flags ,vcodec_list ,vcodec_name_chunk)) { if(gap_debug) { p_debug_print_vcodec_missmatch(videofile, vcodec_list, vcodec_name_chunk); } return (FALSE); } bytesRead = gap_file_load_file_segment(videofile ,video_frame_chunk_data ,0 /* seek_index, start byte of datasegment in file */ ,fileSize /* segment size in byets (must be a multiple of 4) */ ); if (bytesRead != fileSize) { printf("p_chunk_fetch_from_single_image: ERROR failed reading %d bytes from file. (bytesRead:%d) (file:%s)\n" ,(int)fileSize ,(int)bytesRead ,videofile ); return (FALSE); } *video_frame_chunk_size = bytesRead; return (TRUE); } /* end p_chunk_fetch_from_single_image */ /* ---------------------------------------------------- * p_check_chunk_fetch_possible * ---------------------------------------------------- * This procedure checks the preconditions for a possible * fetch of already compresses frame chunk. * (a frame chunk can be one raw frame chunk fetched from a videofile * or a single image frame file that shall be loaded 1:1 into memory) * - there is only 1 videoinput track at this master_frame_nr * - the videoframe must match 1:1 in size * - there are no transformations (opacity, offsets ....) * * return the name of the input videofile if preconditions are OK, * or NULL if not. */ static char * p_check_chunk_fetch_possible(GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr /* starts at 1 */ , gint32 vid_width /* desired Video Width in pixels */ , gint32 vid_height /* desired Video Height in pixels */ , gint32 *video_frame_nr /* OUT: corresponding frame number in the input video */ , GapStoryRenderFrameRangeElem **frn_elem /* OUT: pointer to relevant frame range element */ ) { gint l_track; gint32 l_track_min; gint32 l_track_max; gchar *l_framename; gchar *l_videofile; gdouble l_opacity; gdouble l_scale_x; gdouble l_scale_y; gdouble l_move_x; gdouble l_move_y; GapStoryRenderFrameRangeElem *l_frn_elem_2; gint32 l_localframe_index; gint32 l_local_stepcount; gdouble l_localframe_tween_rest; gboolean l_keep_proportions; gboolean l_fit_width; gboolean l_fit_height; GapStoryRenderFrameType l_frn_type; char *l_trak_filtermacro_file; gdouble l_red_f; gdouble l_green_f; gdouble l_blue_f; gdouble l_alpha_f; gint l_cnt_active_tracks; *video_frame_nr = -1; *frn_elem = NULL; l_videofile = NULL; l_cnt_active_tracks = 0; p_find_min_max_vid_tracknumbers(vidhand->frn_list, &l_track_min, &l_track_max); /* findout if there is just one input track from type videofile * (that possibly could be fetched as comressed videoframe_chunk * and passed 1:1 to the calling encoder) */ for(l_track = MIN(GAP_STB_MAX_VID_INTERNAL_TRACKS, l_track_max); l_track >= MAX(0, l_track_min); l_track--) { l_framename = p_fetch_framename(vidhand->frn_list , master_frame_nr /* starts at 1 */ , l_track , &l_frn_type , &l_trak_filtermacro_file , &l_localframe_index /* used for ANIMIMAGE and Videoframe Number, -1 for all other types */ , &l_local_stepcount , &l_localframe_tween_rest , &l_keep_proportions , &l_fit_width , &l_fit_height , &l_red_f , &l_green_f , &l_blue_f , &l_alpha_f , &l_opacity /* output opacity 0.0 upto 1.0 */ , &l_scale_x /* output 0.0 upto 10.0 where 1.0 is 1:1 */ , &l_scale_y /* output 0.0 upto 10.0 where 1.0 is 1:1 */ , &l_move_x /* output -1.0 upto 1.0 where 0.0 is centered */ , &l_move_y /* output -1.0 upto 1.0 where 0.0 is centered */ , &l_frn_elem_2 /* output selected to the relevant framerange element */ ); if(gap_debug) { printf("l_track:%d l_frn_type:%d\n", (int)l_track, (int)l_frn_type); } if(l_frn_type != GAP_FRN_SILENCE) { l_cnt_active_tracks++; } if((l_framename) || (l_frn_type == GAP_FRN_COLOR)) { if(l_framename) { if((l_frn_type == GAP_FRN_MOVIE) || (l_frn_type == GAP_FRN_IMAGE) || (l_frn_type == GAP_FRN_FRAMES)) { if(l_cnt_active_tracks == 1) { /* check for transformations */ if((l_opacity == 1.0) && (l_scale_x == 1.0) && (l_scale_y == 1.0) && (l_move_x == 0.0) && (l_move_y == 0.0) && (l_fit_width) && (l_fit_height) && (!l_keep_proportions) && (l_frn_elem_2->flip_request == GAP_STB_FLIP_NONE) && (l_frn_elem_2->mask_name == NULL) && (l_trak_filtermacro_file == NULL)) { if(gap_debug) { printf("gap_story_render_fetch_composite_image_or_chunk: video:%s\n", l_framename); } l_videofile = g_strdup(l_framename); *video_frame_nr = l_localframe_index; *frn_elem = l_frn_elem_2; } else { if(gap_debug) { printf("gap_story_render_fetch_composite_image_or_chunk: there are transformations\n"); } /* there are transformations, cant use compressed frame */ l_videofile = NULL; break; } } else { if(gap_debug) { printf("gap_story_render_fetch_composite_image_or_chunk: 2 or more videotracks found\n"); } l_videofile = NULL; break; } } else { l_videofile = NULL; break; } g_free(l_framename); } else { l_videofile = NULL; break; } } /* else: (vid track not used) continue */ } /* end for loop over all video tracks */ return(l_videofile); } /* end p_check_chunk_fetch_possible */ /* ---------------------------------------------------- * p_check_basic_chunk_fetch_conditions * ---------------------------------------------------- * check some basic conditions for raw frame chunk fetching. * return FALSE if fetch not possible. */ static gboolean p_check_basic_chunk_fetch_conditions(gint32 check_flags , gint32 vid_width , gint32 vid_height , GapStoryRenderFrameRangeElem *frn_elem) { if(GVA_has_video_chunk_proc(frn_elem->gvahand) != TRUE) { if(gap_debug) { printf("p_check_basic_chunk_fetch_conditions: Decoder does not support raw chunk fetching\n"); } /* chunk fetch not possible because the used decoder implementation * does not provide the required support. */ return (FALSE); } if((check_flags & GAP_VID_CHCHK_FLAG_SIZE) != 0) { if((frn_elem->gvahand->width != vid_width) || (frn_elem->gvahand->height != vid_height) ) { if(gap_debug) { printf("p_check_basic_chunk_fetch_conditions: size (%d x %d) does not match required size (%d x %d)\n" , (int)frn_elem->gvahand->width , (int)frn_elem->gvahand->height , (int)vid_width , (int)vid_height ); } return (FALSE); } } return (TRUE); } /* end p_check_basic_chunk_fetch_conditions */ /* ---------------------------------------------------- * p_check_and_open_video_handle * ---------------------------------------------------- * */ static void p_check_and_open_video_handle(GapStoryRenderFrameRangeElem *frn_elem , GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr , const gchar *videofile ) { if(frn_elem->gvahand == NULL) { /* before we open a new GVA videohandle, lets check * if another element has already opened this videofile, * and reuse the already open gvahand handle if possible */ frn_elem->gvahand = p_try_to_steal_gvahand(vidhand , master_frame_nr , frn_elem->basename , frn_elem->exact_seek ); if(frn_elem->gvahand == NULL) { if(vidhand->preferred_decoder) { frn_elem->gvahand = GVA_open_read_pref(videofile , frn_elem->seltrack , 1 /* aud_track */ , vidhand->preferred_decoder , FALSE /* use MMX if available (disable_mmx == FALSE) */ ); } else { frn_elem->gvahand = GVA_open_read(videofile ,frn_elem->seltrack ,1 /* aud_track */ ); } if(frn_elem->gvahand) { GVA_set_fcache_size(frn_elem->gvahand, GAP_STB_RENDER_GVA_FRAMES_TO_KEEP_CACHED); frn_elem->gvahand->do_gimp_progress = vidhand->do_gimp_progress; if(frn_elem->exact_seek == 1) { /* configure the GVA Procedures for exact (but slow) seek emulaion */ frn_elem->gvahand->emulate_seek = TRUE; } } } } } /* end p_check_and_open_video_handle */ /* ---------------------------------------------------- * p_debug_dump_chunk_to_file * ---------------------------------------------------- * */ static void p_debug_dump_chunk_to_file(const unsigned char *video_frame_chunk_data , gint32 video_frame_chunk_size , gint32 video_frame_nr , gint32 master_frame_nr ) { FILE *fp; char *fname; const char *l_env; gint32 l_dump_chunk_frames; l_dump_chunk_frames = 0; l_env = g_getenv("GAP_DUMP_FRAME_CHUNKS"); if(l_env) { l_dump_chunk_frames = atol(l_env); } if (master_frame_nr > l_dump_chunk_frames) { return; } fname = g_strdup_printf("zz_chunk_data_%06d.dmp", (int)video_frame_nr); printf("DEBUG: SAVING fetched raw chunk to file:%s\n", fname); fp = g_fopen(fname, "wb"); if(fp) { fwrite(video_frame_chunk_data, video_frame_chunk_size, 1, fp); fclose(fp); } g_free(fname); } /* end p_debug_dump_chunk_to_file */ /* ---------------------------------------------------- * p_story_attempt_fetch_chunk * ---------------------------------------------------- * fetch the frame as uncompressed chunk into the buffer * that is provide by the caller * (via parameter video_frame_chunk_data at size video_frame_chunk_maxsize) * if not possible return NULL. * else return the name of the referenced videofile. */ static gchar* p_story_attempt_fetch_chunk(GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr /* starts at 1 */ , gint32 vid_width /* desired Video Width in pixels */ , gint32 vid_height /* desired Video Height in pixels */ , GapCodecNameElem *vcodec_list /* IN: list of video_codec names that are compatible to the calling encoder program */ , unsigned char *video_frame_chunk_data /* OUT: */ , gint32 *video_frame_chunk_size /* OUT: total size of frame (may include a videoformat specific frameheader)*/ , gint32 video_frame_chunk_maxsize /* IN: sizelimit (larger chunks are not fetched) */ , gdouble master_framerate , gint32 max_master_frame_nr /* the number of frames that will be encode in total */ , gint32 *video_frame_chunk_hdr_size /* OUT: size of videoformat specific frameheader (0 if has no hdr) */ , gint32 check_flags /* IN: combination of GAP_VID_CHCHK_FLAG_* flag values */ , gboolean *last_fetch_was_compressed_chunk , const char *last_videofile ) { #define GAP_MPEG_ASSUMED_REFERENCE_DISTANCE 3 static gint32 last_video_frame_nr = -1; gchar *l_framename; gchar *l_videofile; GapStoryRenderFrameRangeElem *l_frn_elem; GapStoryRenderFrameRangeElem *l_frn_elem_2; GapStoryRenderFrameType l_curr_frn_type; gint32 l_video_frame_nr; l_frn_elem = NULL; *video_frame_chunk_size = 0; *video_frame_chunk_hdr_size = 0; /* assume chunk contains no frame header */ l_videofile = NULL; /* NULL: also used as flag for "MUST fetch regular uncompressed frame" */ l_framename = NULL; l_video_frame_nr = 1; l_curr_frn_type = GAP_FRN_SILENCE; l_videofile = p_check_chunk_fetch_possible(vidhand , master_frame_nr , vid_width , vid_height , &l_video_frame_nr , &l_frn_elem ); if((l_videofile) && (l_frn_elem) ) { l_curr_frn_type = l_frn_elem->frn_type; if (l_curr_frn_type != GAP_FRN_MOVIE) { gboolean l_singleFetchOk; if(gap_debug) { printf("p_story_attempt_fetch_chunk: MASTER_FRAME_NR: %d refers to imagefile :%s \n" , (int)master_frame_nr , l_videofile ); } last_video_frame_nr = -1; l_singleFetchOk = p_chunk_fetch_from_single_image(l_videofile , video_frame_chunk_data , video_frame_chunk_maxsize , video_frame_chunk_hdr_size , video_frame_chunk_size , vcodec_list , check_flags ); if (l_singleFetchOk == TRUE) { /* passed all requested checks */ return(l_videofile); } g_free(l_videofile); l_videofile = NULL; return (NULL); } } if(l_curr_frn_type == GAP_FRN_MOVIE) { if(gap_debug) { printf("p_story_attempt_fetch_chunk: MASTER_FRAME_NR: %d refers to videofile :%s \n" , (int)master_frame_nr , l_videofile ); } p_check_and_open_video_handle(l_frn_elem, vidhand, master_frame_nr, l_videofile); if(l_frn_elem->gvahand) { /* check if framesize matches 1:1 to output video size * and if the videodecoder does support a read procedure for compressed vodeo chunks * TODO: should also check for compatible vcodec_name * (cannot check that, because libmpeg3 does not deliver vcodec_name information * and there is no implementation to fetch uncompressed chunks in other decoders) */ if (p_check_basic_chunk_fetch_conditions(check_flags, vid_width, vid_height, l_frn_elem) != TRUE) { if(gap_debug) { printf("p_story_attempt_fetch_chunk: MASTER_FRAME_NR: %d basic conditions NOT OK (no chunk fetch possible)\n" ,(int)master_frame_nr ); } } else { t_GVA_RetCode l_fcr; if(gap_debug) { printf("p_story_attempt_fetch_chunk: MASTER_FRAME_NR: %d video_frame_nr:%d performing CHUNK fetch\n" ,(int)master_frame_nr ,(int)l_video_frame_nr ); } /* FETCH compressed video chunk * (on successful fetch the chunk contains (at least) one frame, and may start with * MPEG typical sequence header and/or GOP header, Picture Header */ l_fcr = GVA_get_video_chunk(l_frn_elem->gvahand , l_video_frame_nr , video_frame_chunk_data , video_frame_chunk_size , video_frame_chunk_maxsize ); if(gap_debug) { printf("p_story_attempt_fetch_chunk: AFTER CHUNK fetch max:%d chunk_data:%d chunk_size:%d\n" ,(int)video_frame_chunk_maxsize ,(int)video_frame_chunk_data ,(int)*video_frame_chunk_size ); } if(l_fcr == GVA_RET_OK) { gint l_frame_type; gint32 check_flags_result; gint32 check_flags_mask; gboolean is_mpeg_integrity_check_done; char *vcodec_name_chunk; vcodec_name_chunk = GVA_get_codec_name(l_frn_elem->gvahand ,GVA_VIDEO_CODEC ,l_frn_elem->seltrack ); is_mpeg_integrity_check_done = FALSE; check_flags_result = check_flags & GAP_VID_CHCHK_FLAG_SIZE; p_check_flags_for_matching_vcodec(check_flags, &check_flags_result , l_videofile , vcodec_list , vcodec_name_chunk ); if(vcodec_name_chunk) { g_free(vcodec_name_chunk); vcodec_name_chunk = NULL; } l_frame_type = GVA_util_check_mpg_frame_type(video_frame_chunk_data ,*video_frame_chunk_size ); if(gap_debug) { printf("\nfetched CHUNK with l_frame_type %d(1=I,2=P,3=B)\n", (int)l_frame_type); } /* debug code: dump first video chunks to file(s) */ p_debug_dump_chunk_to_file(video_frame_chunk_data , *video_frame_chunk_size , l_video_frame_nr , master_frame_nr ); if (l_frame_type != GVA_MPGFRAME_UNKNOWN) { /* known MPEG specific framehaedr information is present * (typical when chunk was read via libmpeg3) * in this case try to fix timecode information in the header. */ GVA_util_fix_mpg_timecode(video_frame_chunk_data ,*video_frame_chunk_size ,master_framerate ,master_frame_nr ); *video_frame_chunk_hdr_size = GVA_util_calculate_mpeg_frameheader_size(video_frame_chunk_data , *video_frame_chunk_size ); } check_flags_mask = check_flags & (GAP_VID_CHCHK_FLAG_MPEG_INTEGRITY | GAP_VID_CHCHK_FLAG_FULL_FRAME); if ((l_frame_type == GVA_MPGFRAME_I_TYPE) && (check_flags_mask)) { is_mpeg_integrity_check_done = TRUE; /* intra frame has no dependencies to other frames * can use that frame type at any place in an MPEG stream * (or save it as JPEG) */ *last_fetch_was_compressed_chunk = TRUE; if(gap_debug) { printf("\nReuse I-FRAME at %06d,", (int)master_frame_nr); } check_flags_result |= check_flags_mask; } check_flags_mask = check_flags & (GAP_VID_CHCHK_FLAG_JPG | GAP_VID_CHCHK_FLAG_FULL_FRAME | GAP_VID_CHCHK_FLAG_MPEG_INTEGRITY); if (check_flags_mask) { if(TRUE == GVA_util_check_jpg_picture( video_frame_chunk_data , *video_frame_chunk_size , 32 /* max_check_size */ , video_frame_chunk_hdr_size)) { check_flags_result |= check_flags_mask; } } check_flags_mask = check_flags & (GAP_VID_CHCHK_FLAG_PNG | GAP_VID_CHCHK_FLAG_FULL_FRAME); if (check_flags_mask) { if(TRUE == GVA_util_check_png_picture( video_frame_chunk_data , *video_frame_chunk_size , 32 /* max_check_size */ , video_frame_chunk_hdr_size)) { check_flags_result |= check_flags_mask; } } check_flags_mask = check_flags & GAP_VID_CHCHK_FLAG_MPEG_INTEGRITY; if ((l_frame_type == GVA_MPGFRAME_P_TYPE) && (check_flags_mask)) { is_mpeg_integrity_check_done = TRUE; /* predicted frame has dependencies to the previous intra frame * can use that frame if fetch sequence contains previous i frame */ if(last_videofile) { /* check if frame is the next in sequence in the same videofile */ if((strcmp(l_videofile, last_videofile) == 0) && (l_video_frame_nr == last_video_frame_nr +1)) { *last_fetch_was_compressed_chunk = TRUE; if(gap_debug) { printf("P,"); // printf(" Reuse P-FRAME Chunk at %06d\n", (int)master_frame_nr); } check_flags_result |= check_flags_mask; } } } check_flags_mask = check_flags & GAP_VID_CHCHK_FLAG_MPEG_INTEGRITY; if (((l_frame_type == GVA_MPGFRAME_B_TYPE) || (l_frame_type == GVA_MPGFRAME_P_TYPE)) && (is_mpeg_integrity_check_done != TRUE) && (check_flags_mask)) { is_mpeg_integrity_check_done = TRUE; /* bi-directional predicted frame has dependencies both to * the previous intra frame or p-frame and to the following i or p-frame. * * can use that frame if fetch sequence contains previous i frame * and fetch will continue until the next i or p frame. * * we do a simplified check if the next few (say 3) frames in storyboard sequence * will fetch the next (3) frames in videofile sequence from the same videofile. * this is just a guess, but maybe sufficient in most cases. */ if(last_videofile) { gboolean l_bframe_ok; l_bframe_ok = FALSE; /* check if frame is the next in sequence in the same videofile */ if((strcmp(l_videofile, last_videofile) == 0) && (l_video_frame_nr == last_video_frame_nr +1)) { /* B-frame are not reused at the last few frames in the output video. * (unresolved references to following p or i frames of the * input video could be the result) */ if(master_frame_nr + GAP_MPEG_ASSUMED_REFERENCE_DISTANCE <= max_master_frame_nr) { gint ii; gint32 l_next_video_frame_nr; char *l_next_videofile; l_bframe_ok = TRUE; /* now assume that B-frame may be used */ /* look ahead if the next few fetches in storyboard sequence * will deliver the next frames from the same inputvideo * in ascending input_video sequence at stepsize 1 * (it is assumed that the referenced P or I frame * will be fetched in later calls then) */ for(ii=1; ii <= GAP_MPEG_ASSUMED_REFERENCE_DISTANCE; ii++) { gboolean is_next_video_the_same; is_next_video_the_same = FALSE; l_next_videofile = p_check_chunk_fetch_possible(vidhand , (master_frame_nr + ii) , vid_width , vid_height , &l_next_video_frame_nr , &l_frn_elem_2 ); if(l_next_videofile) { if (strcmp(l_next_videofile, l_videofile) == 0) { is_next_video_the_same = TRUE; } g_free(l_next_videofile); } if((is_next_video_the_same == TRUE) && (l_frn_elem_2)) { if((l_next_video_frame_nr != l_video_frame_nr +ii) || (l_frn_elem_2->frn_type != GAP_FRN_MOVIE)) { l_bframe_ok = FALSE; } } else { l_bframe_ok = FALSE; } if(!l_bframe_ok) { break; } } /* end for loop (look ahed next few frames in storyboard sequence) */ } if(gap_debug) { if(l_bframe_ok) printf("Look Ahead B-FRAME OK to copy\n"); else printf("Look Ahead B-FRAME dont USE\n"); } if(l_bframe_ok) { *last_fetch_was_compressed_chunk = TRUE; if(gap_debug) { if (l_frame_type == GVA_MPGFRAME_B_TYPE) { printf("B,"); } else { printf("p,"); } printf(" Reuse B-FRAME Chunk at %06d\n", (int)master_frame_nr); } check_flags_result |= check_flags_mask; } } } } last_video_frame_nr = l_video_frame_nr; if(check_flags_result == check_flags) { if(gap_debug) { printf("oo OK, Reuse of fetched CHUNK type: %d (1=I/2=P/3=B) masterFrameNr:%d frame_nr:%d (last_frame_nr:%d) \n" " check_flags_result:%d (requested check_flags:%d)\n" ,(int)l_frame_type ,(int)master_frame_nr ,(int)l_video_frame_nr ,(int)last_video_frame_nr ,(int)check_flags_result ,(int)check_flags ); } /* passed all requested checks */ return(l_videofile); } if(gap_debug) { printf("** sorry, no reuse of fetched CHUNK type: %d (1=I/2=P/3=B) masterFrameNr:%d frame_nr:%d (last_frame_nr:%d) \n" " check_flags_result:%d (requeste) check_flags:%d\n" ,(int)l_frame_type ,(int)master_frame_nr ,(int)l_video_frame_nr ,(int)last_video_frame_nr ,(int)check_flags_result ,(int)check_flags ); } } else { last_video_frame_nr = -1; if(gap_debug) { printf("**# sorry, no reuse fetch failed frame_nr:%d (last_frame_nr:%d)\n" ,(int)l_video_frame_nr ,(int)last_video_frame_nr ); } } } } } *last_fetch_was_compressed_chunk = FALSE; *video_frame_chunk_size = 0; if (l_videofile != NULL) { g_free(l_videofile); l_videofile = NULL; } return (NULL); /* Chunk fetch Not possible */ } /* end p_story_attempt_fetch_chunk */ #endif /* ---------------------------------------------------- * gap_story_render_fetch_composite_image_or_chunk * ---------------------------------------------------- * * fetch composite VIDEO Image at a given master_frame_nr * within a storyboard framerange list * * if desired (and possible) try directly fetch the (already compressed) Frame chunk from * an input videofile for the master_frame_nr. * * This procedure is typically used in encoders that support lossless video cut. * * the compressed fetch depends on following conditions: * - dont_recode_flag == TRUE * - there is only 1 videoinput track at this master_frame_nr * - the videodecoder must support a read_video_chunk procedure * (libmpeg3 has this support, for the libavformat the support is available vie the gap video api) * TODO: for future releases should also check for the same vcodec_name) * - the videoframe must match 1:1 in size * - there are no transformations (opacity, offsets ....) * - there are no filtermacros to perform on the fetched frame * * check_flags: * force checks if corresponding bit value is set. Supportet Bit values are: * GAP_VID_CHCHK_FLAG_SIZE check if width and height are equal * GAP_VID_CHCHK_FLAG_MPEG_INTEGRITY checks for MPEG P an B frames if the sequence of fetched frames * also includes the refered I frame (before or after the current * handled frame) * GAP_VID_CHCHK_FLAG_JPG check if fetched cunk is a jpeg encoded frame. * (typical for MPEG I frames) * GAP_VID_CHCHK_FLAG_VCODEC_NAME check for a compatible vcodec_name * + * RETURN TRUE on success, FALSE on ERRORS * if an already compressed video_frame_chunk was fetched then return the size of the chunk * in the *video_frame_chunk_size OUT Parameter. * (both *image_id an *layer_id will deliver -1 in that case) * if a composite image was fetched deliver its id in the *image_id OUT parameter * and the id of the only layer in the *layer_id OUT Parameter * the *force_keyframe OUT parameter tells the calling encoder to write an I-Frame * (*video_frame_chunk_size will deliver 0 in that case) */ gboolean gap_story_render_fetch_composite_image_or_chunk(GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr /* starts at 1 */ , gint32 vid_width /* desired Video Width in pixels */ , gint32 vid_height /* desired Video Height in pixels */ , char *filtermacro_file /* NULL if no filtermacro is used */ , gint32 *layer_id /* output: Id of the only layer in the composite image */ , gint32 *image_id /* output: Id of the only layer in the composite image */ , gboolean dont_recode_flag /* IN: TRUE try to fetch comressed chunk if possible */ , GapCodecNameElem *vcodec_list /* IN: list of video_codec names that are compatible to the calling encoder program */ , gboolean *force_keyframe /* OUT: the calling encoder should encode an I-Frame */ , unsigned char *video_frame_chunk_data /* OUT: */ , gint32 *video_frame_chunk_size /* OUT: total size of frame (may include a videoformat specific frameheader)*/ , gint32 video_frame_chunk_maxsize /* IN: sizelimit (larger chunks are not fetched) */ , gdouble master_framerate , gint32 max_master_frame_nr /* the number of frames that will be encode in total */ , gint32 *video_frame_chunk_hdr_size /* OUT: size of videoformat specific frameheader (0 if has no hdr) */ , gint32 check_flags /* IN: combination of GAP_VID_CHCHK_FLAG_* flag values */ ) { #define GAP_MPEG_ASSUMED_REFERENCE_DISTANCE 3 static char *last_videofile = NULL; static gboolean last_fetch_was_compressed_chunk = FALSE; gchar *l_videofile; GapStoryRenderFrameRangeElem *l_frn_elem; gboolean l_enable_chunk_fetch; *image_id = -1; *layer_id = -1; *force_keyframe = FALSE; l_frn_elem = NULL; *video_frame_chunk_size = 0; *video_frame_chunk_hdr_size = 0; /* assume chunk contains no frame header */ l_enable_chunk_fetch = dont_recode_flag; if(gap_debug) { printf("gap_story_render_fetch_composite_image_or_chunk START master_frame_nr:%d %dx%d dont_recode:%d\n" , (int)master_frame_nr , (int)vid_width , (int)vid_height , (int)dont_recode_flag ); } l_videofile = NULL; /* NULL: also used as flag for "MUST fetch regular uncompressed frame" */ #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if(filtermacro_file) { if(*filtermacro_file != '\0') { if(gap_debug) { printf("chunk fetch disabled due to filtermacro procesing\n"); } /* if a filtermacro_file is force disable chunk fetching */ l_enable_chunk_fetch = FALSE; } } if (l_enable_chunk_fetch) { if(gap_debug) { printf("start check if chunk fetch is possible\n"); } l_videofile = p_story_attempt_fetch_chunk(vidhand , master_frame_nr , vid_width , vid_height , vcodec_list , video_frame_chunk_data , video_frame_chunk_size , video_frame_chunk_maxsize , master_framerate , max_master_frame_nr , video_frame_chunk_hdr_size , check_flags , &last_fetch_was_compressed_chunk , last_videofile ); } if(last_fetch_was_compressed_chunk) { *force_keyframe = TRUE; } /* keep the videofile name for the next call * (for MPEG INTEGRITY checks that require continous sequence * in the same referenced source video */ if(last_videofile) { g_free(last_videofile); } last_videofile = l_videofile; #endif if(l_videofile != NULL) { /* chunk fetch was successful */ if(gap_debug) { printf("gap_story_render_fetch_composite_image_or_chunk: CHUNK fetch succsessful\n"); } return(TRUE); } else { last_fetch_was_compressed_chunk = FALSE; if(last_videofile) { g_free(last_videofile); } last_videofile = l_videofile; if(gap_debug) { printf("gap_story_render_fetch_composite_image_or_chunk: CHUNK fetch not possible (doing frame fetch instead)\n"); } *video_frame_chunk_size = 0; *image_id = gap_story_render_fetch_composite_image(vidhand , master_frame_nr /* starts at 1 */ , vid_width /* desired Video Width in pixels */ , vid_height /* desired Video Height in pixels */ , filtermacro_file /* NULL if no filtermacro is used */ , layer_id /* output: Id of the only layer in the composite image */ ); if(*image_id >= 0) { return(TRUE); } } return(FALSE); } /* end gap_story_render_fetch_composite_image_or_chunk */ gimp-gap-2.6.0+dfsg.orig/gap/gap_story_sox.c0000644000175000017500000000423011212030253020557 0ustar thibautthibaut/* gap_story_sox.c * Audio resampling Modules based on calls to UNIX Utility Program sox */ /* * Copyright * * 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 #include #include "gap_story_sox.h" #include "gap_audio_wav.h" #include "gap-intl.h" extern int gap_debug; /* 1 == print debug infos , 0 dont print debug infos */ /* -------------------------------- * gap_story_sox_exec_resample * -------------------------------- */ void gap_story_sox_exec_resample(char *in_audiofile ,char *out_audiofile ,gint32 samplerate ,char *util_sox /* the resample program (default: sox) */ ,char *util_sox_options ) { gchar *l_cmd; if(util_sox == NULL) { util_sox = GAP_STORY_SOX_DEFAULT_UTIL_SOX; } if(util_sox_options == NULL) { util_sox_options = GAP_STORY_SOX_DEFAULT_UTIL_SOX_OPTIONS; } /* the calling style requres UNIX Shell for Environment Variables * IN, OUT, RATE that are used for Parameter substitution */ l_cmd = g_strdup_printf("IN='%s';OUT='%s';RATE=%d;%s %s\n" , in_audiofile /* input audio file */ , out_audiofile /* output audio file (tmp 16-bit wav file) */ , (int)samplerate , util_sox , util_sox_options ); if(gap_debug) { printf("Execute resample CMD:%s\n", l_cmd); } system(l_cmd); g_free(l_cmd); } /* end gap_story_sox_exec_resample */ gimp-gap-2.6.0+dfsg.orig/gap/gap_vex_dialog.h0000644000175000017500000000277411212030253020647 0ustar thibautthibaut/* * gap_vex_dialog.h * Video Extract GUI procedures */ /* * Changelog: * 2003/02/11 v1.2.1a: hof created */ /* * Copyright * * 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_VEX_DIALOG #define GAP_VEX_DIALOG #include "config.h" /* SYTEM (UNIX) includes */ #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" #include "gap_vex_main.h" void gap_vex_dlg_init_gpp (GapVexMainGlobalParams *gpp); gint gap_vex_dlg_overwrite_dialog(GapVexMainGlobalParams *gpp , gchar *filename , gint overwrite_mode ); GtkWidget* gap_vex_dlg_create_mw__main_window (GapVexMainGlobalParams *gpp); void gap_vex_dlg_main_dialog (GapVexMainGlobalParams *gpp); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_arr_dialog.h0000644000175000017500000001704111212030253020622 0ustar thibautthibaut/* gap_arr_dialog.h * 1998.May.23 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins (Standard array dialog) * * - gap_arr_ok_cancel_dialog Dialog Window with one or more rows * each row can contain one of the following GAP widgets: * - float pair widget * (horizontal slidebar combined with a float input field) * - int pair widget * (horizontal slidebar combined with a int input field) * - Toggle Button widget * - Textentry widget * - Float entry widget * - Int entry widget * - gap_arr_slider_dialog * simplified call of p_pair_array_dialog, * using an array with one GAP_ARR_WGT_INT_PAIR. * - gap_arr_buttons_dialog * * * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 2.1.0a; 2004/09/25 hof: gap_arr_create_vindex_permission * gimp 1.3.20a; 2003/09/29 hof: gap_arr_overwrite_file_dialog * gimp 1.3.16b; 2003/07/04 hof: new gap_arr_confirm_dialog * gimp 1.3.14a; 2003/05/15 hof: new GAP_ARR_WGT_FONTSEL * gimp 1.3.12a; 2003/05/01 hof: merge into CVS-gimp-gap project * gimp 1.3.11a; 2003/01/18 hof: merged in changes of the gap_vid_enc project * - added GAP_ARR_WGT_OPT_ENTRY (entry comined with Optionmenu) and GAP_ARR_WGT_DEFAULT_BUTTON * gimp 1.3.4a; 2002/03/12 hof: ported to gtk+-2.0.0 * gimp 1.1.17b; 2000/01/26 hof: * version 0.96.03; 1998/08/15 hof: p_arr_gtk_init * version 0.96.00; 1998/07/09 hof: 1.st release * (re-implementation of gap_sld_dialog.c) */ #ifndef _ARR_DIALOG_H #define _ARR_DIALOG_H /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" #include "libgimp/gimpui.h" typedef enum { GAP_ARR_WGT_LABEL ,GAP_ARR_WGT_TEXT ,GAP_ARR_WGT_INT ,GAP_ARR_WGT_FLT ,GAP_ARR_WGT_TOGGLE ,GAP_ARR_WGT_RADIO ,GAP_ARR_WGT_OPTIONMENU ,GAP_ARR_WGT_FLT_PAIR ,GAP_ARR_WGT_INT_PAIR ,GAP_ARR_WGT_ACT_BUTTON ,GAP_ARR_WGT_FILESEL ,GAP_ARR_WGT_LABEL_LEFT ,GAP_ARR_WGT_LABEL_RIGHT ,GAP_ARR_WGT_OPT_ENTRY ,GAP_ARR_WGT_DEFAULT_BUTTON ,GAP_ARR_WGT_FONTSEL ,GAP_ARR_WGT_HELP_BUTTON } GapArrWidget; typedef int (*t_action_func) ( gpointer action_data); /* * - If one of the Args has set 'has_default' to TRUE * the action Area will contain an additional Button 'Default' * */ typedef struct { GapArrWidget widget_type; /* common fields for all widget types */ const char *label_txt; const char *help_txt; /* help for tooltips */ const char *help_id; /* help_id for the help page that should be displayed via help button */ GimpHelpFunc help_func; gint entry_width; /* for all Widgets with an entry */ gint scale_width; /* for the Widgets with a scale */ gint constraint; /* TRUE: check for min/max values */ gint has_default; /* TRUE: default value available */ /* flt_ fileds are used for GAP_ARR_WGT_FLT and GAP_ARR_WGT_FLT_PAIR */ gint flt_digits; /* digits behind comma */ gdouble flt_min; gdouble flt_max; gdouble flt_step; gdouble flt_default; gdouble flt_ret; /* int_ fileds are used for GAP_ARR_WGT_INT and GAP_ARR_WGT_INT_PAIR GAP_ARR_WGT_TOGGLE */ gint int_min; gint int_max; gint int_step; gint int_default; gint int_ret; gint int_ret_lim; /* for private (arr_dialog.c) use only */ /* unconstraint lower /upper limit for GAP_ARR_WGT_FLT_PAIR and GAP_ARR_WGT_INT_PAIR */ gfloat umin; gfloat umax; gfloat pagestep; /* togg_ field are used for GAP_ARR_WGT_TOGGLE */ char *togg_label; /* extra label attached right to toggle button */ /* radio_ fileds are used for GAP_ARR_WGT_RADIO and GAP_ARR_WGT_OPTIONMENU */ gint radio_argc; gint radio_default; gint radio_ret; char **radio_argv; char **radio_help_argv; /* text_ fileds are used for GAP_ARR_WGT_TEXT */ gint text_buf_len; /* common length for init, default and ret text_buffers */ char *text_buf_default; char *text_buf_ret; const gchar *text_fontsel; /* for private (arr_dialog.c) use only */ GtkWidget *text_filesel; /* for private (arr_dialog.c) use only */ GtkWidget *text_entry; /* for private (arr_dialog.c) use only */ GtkWidget *check_button; /* for private (arr_dialog.c) use only */ GtkWidget *combo; /* for private (arr_dialog.c) use only */ GtkObject *adjustment; /* for private (arr_dialog.c) use only */ gpointer radiogroup; /* for private (arr_dialog.c) use only */ /* action_ fileds are used for GAP_ARR_WGT_ACT_BUTTON */ t_action_func action_functon; gpointer action_data; /* flag is FALSE while the dialog is built * and goes to TRUE if all widgets are there and ready for user interaction * (used in some callbacks to prevent too to early fire) */ gboolean widget_locked; } GapArrArg; typedef struct { char *but_txt; gint but_val; } GapArrButtonArg; void gap_arr_arg_init (GapArrArg *arr_ptr, gint widget_type); gint gap_arr_ok_cancel_dialog (const char *title_txt, const char *frame_txt, int argc, GapArrArg argv[]); long gap_arr_slider_dialog(const char *title_txt, const char *frame_txt, const char *label_txt, const char *tooltip_txt, long min, long max, long curr, long constraint, const char *help_id); gint gap_arr_buttons_dialog (const char *title_txt, const char *frame_txt, int b_argc, GapArrButtonArg b_argv[], gint b_def_val); gint gap_arr_std_dialog (const char *title_txt, const char *frame_txt, int argc, GapArrArg argv[], int b_argc, GapArrButtonArg b_argv[], gint b_def_val); gboolean gap_arr_confirm_dialog(const char *msg_txt, const char *title_txt, const char *frame_txt); gboolean gap_arr_overwrite_file_dialog(const char *filename); void gap_arr_msg_win(GimpRunMode run_mode, const char *msg); void gap_arr_msg_popup(GimpRunMode run_mode, const char *msg); gboolean gap_arr_create_vindex_permission(const char *videofile , const char *vindex_file , gint32 seek_status ); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_navi_activtable.h0000644000175000017500000000252111212030253021647 0ustar thibautthibaut/* gap_navi_activtable.h * 2002.04.21 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 1.3.5a; 2002/04/21 hof: created (Handle Event: active_image changed id) */ #ifndef _GAP_NAVI_ACTIVTABLE_H #define _GAP_NAVI_ACTIVTABLE_H #include "libgimp/gimp.h" void gap_navat_update_active_image(gint32 old_image_id, gint32 new_image_id); void gap_navat_set_active_image(gint32 image_id, gint32 pid); gint32 gap_navat_get_active_image(gint32 image_id, gint32 pid); #endif gimp-gap-2.6.0+dfsg.orig/gap/Makefile.am0000644000175000017500000003436711212030253017565 0ustar thibautthibaut## Process this file with automake to produce Makefile.in libexecdir = $(GIMP_PLUGIN_DIR)/plug-ins scriptdatadir = $(GIMP_DATA_DIR)/scripts scriptdata_DATA = sel-to-anim-img.scm gap-dup-continue.scm if GAP_UNIX_FRONTENDS GAP_FRONTENDS = gap_frontends endif GAP_DECODE_MPLAYER_FRONTEND = gap_decode_mplayer if GAP_AUDIO_SUPPORT WAVPLAYCLIENT = $(top_builddir)/libwavplayclient/libwavplayclient.a endif if GAP_VIDEOAPI_SUPPORT GAPVIDEOAPI = $(top_builddir)/libgapvidapi/libgapvidapi.a $(GAPVIDEOAPI_EXTLIBS) INC_GAPVIDEOAPI = -I$(top_srcdir)/libgapvidapi $(GAPVIDEOAPI_EXTINCS) GAP_VIDEO_EXTRACT = gap_video_extract GAP_VIDEO_INDEX = gap_video_index endif LIBGAPBASE = $(top_builddir)/libgapbase/libgapbase.a INC_LIBGAPBASE = -I$(top_srcdir)/libgapbase LIBGIMPGAP = libgimpgap.a LIBGAPSTORY = libgapstory.a noinst_LIBRARIES = $(LIBGIMPGAP) $(LIBGAPSTORY) BASE_SOURCES = \ gap-intl.h \ gap_arr_dialog.c \ gap_arr_dialog.h \ gap_audio_util.c \ gap_audio_util.h \ gap_audio_wav.c \ gap_audio_wav.h \ gap_image.c \ gap_image.h \ gap_layer_copy.c \ gap_layer_copy.h \ gap_lib.c \ gap_lib.h \ gap_lib_common_defs.h \ gap_lock.c \ gap_lock.h \ gap_navi_activtable.c \ gap_navi_activtable.h \ gap_match.c \ gap_match.h \ gap_onion_base.c \ gap_onion_base.h \ gap_pdb_calls.c \ gap_pdb_calls.h \ gap_pview_da.c \ gap_pview_da.h \ gap_thumbnail.c \ gap_thumbnail.h \ gap_timeconv.c \ gap_timeconv.h \ gap_stock.c \ gap_stock.h \ gap_vin.c \ gap_vin.h libgimpgap_a_SOURCES = $(BASE_SOURCES) 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 \ gap_story_render_processor.h \ gap_story_render_processor.c \ gap_story_render_audio.h \ gap_story_render_audio.c \ gap_story_sox.h \ gap_story_sox.c \ gap_story_syntax.h \ gap_story_syntax.c libexec_PROGRAMS = \ gap_bluebox \ gap_plugins \ gap_filter \ gap_fmac \ gap_fmac_varying \ $(GAP_FRONTENDS) \ $(GAP_DECODE_MPLAYER_FRONTEND) \ gap_morph \ gap_name2layer \ gap_navigator_dialog \ gap_player \ gap_onion \ gap_storyboard \ $(GAP_VIDEO_EXTRACT) \ $(GAP_VIDEO_INDEX) \ gap_wr_color_curve \ gap_wr_color_levels \ gap_wr_color_huesat \ gap_wr_trans \ gap_wr_resynth \ gap_wr_opacity gap_bluebox_SOURCES = \ gap_lastvaldesc.c \ gap_lastvaldesc.h \ gap_bluebox_main.c \ gap_bluebox.c \ gap_bluebox.h \ gap_libgimpgap.h gap_plugins_SOURCES = \ gap_base_ops.c \ gap_base_ops.h \ gap_bluebox.c \ gap_bluebox.h \ gap_dbbrowser_utils.c \ gap_dbbrowser_utils.h \ gap_filter_codegen.c \ gap_filter_pdb.c \ gap_filter_pdb.h \ gap_lastvaldesc.c \ gap_lastvaldesc.h \ gap_main.c \ gap_mod_layer.c \ gap_mod_layer.h \ gap_mod_layer_dialog.c \ gap_mod_layer_dialog.h \ gap_mov_dialog.c \ gap_mov_dialog.h \ gap_mov_exec.c \ gap_mov_exec.h \ gap_mov_render.c \ gap_mov_render.h \ gap_navi_activtable.c \ gap_navi_activtable.h \ gap_range_ops.c \ gap_range_ops.h \ gap_resi_dialog.c \ gap_resi_dialog.h \ gap_split.c \ gap_split.h \ gap_libgimpgap.h gap_filter_SOURCES = \ gap_dbbrowser_utils.c \ gap_dbbrowser_utils.h \ gap_filter.h \ gap_filter_codegen.c \ gap_filter_foreach.c \ gap_filter_iterators.c \ gap_filter_iterators.h \ 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 gap_fmac_SOURCES = \ gap_dbbrowser_utils.c \ gap_dbbrowser_utils.h \ gap_filter.h \ gap_filter_codegen.c \ 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 \ gap_lastvaldesc.h \ gap_libgimpgap.h gap_fmac_varying_SOURCES = \ 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 \ gap_lastvaldesc.h \ gap_libgimpgap.h gap_frontends_SOURCES = \ gap_decode_xanim.c \ gap_decode_xanim.h \ gap_frontends_main.c \ gap_mpege.c \ gap_mpege.h \ gap_libgimpgap.h gap_decode_mplayer_SOURCES = \ gap_decode_mplayer_main.c \ gap_decode_mplayer.c \ gap_decode_mplayer.h \ gap_libgimpgap.h # gap_morph_SOURCES: gap_mov_exec.h should be removed when finished coding gap_morph_SOURCES = \ gap_morph_main.c \ gap_morph_main.h \ gap_morph_exec.c \ gap_morph_exec.h \ gap_morph_dialog.c \ gap_morph_dialog.h \ gap_morph_tween_dialog.c \ gap_morph_tween_dialog.h \ gap_mov_dialog.h \ gap_mov_exec.h \ gap_libgimpgap.h gap_name2layer_SOURCES = \ gap_lastvaldesc.c \ gap_lastvaldesc.h \ gap_name2layer_main.c \ gap_libgimpgap.h gap_navigator_dialog_SOURCES = \ gap_navi_activtable.c \ gap_navi_activtable.h \ gap_navigator_dialog.c \ gap_libgimpgap.h gap_player_SOURCES = \ gap_player_main.c \ gap_player_main.h \ gap_player_dialog.c \ gap_player_dialog.h \ gap_player_cache.c \ 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 gap_onion_SOURCES = \ gap_onion_main.c \ gap_onion_main.h \ gap_onion_dialog.c \ gap_onion_dialog.h \ gap_onion_worker.c \ gap_onion_worker.h \ gap_libgimpgap.h gap_storyboard_SOURCES = \ gap_story_main.c \ gap_story_main.h \ gap_story_dialog.c \ gap_story_dialog.h \ gap_story_undo.c \ gap_story_undo.h \ gap_story_undo_types.h \ gap_story_vthumb.c \ gap_story_vthumb.h \ gap_story_section_properties.c \ gap_story_section_properties.h \ gap_story_properties.c \ gap_story_properties.h \ gap_story_att_trans_dlg.c \ gap_story_att_trans_dlg.h \ gap_audio_extract.c \ gap_audio_extract.h \ gap_player_main.h \ gap_player_dialog.c \ 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 gap_video_extract_SOURCES = \ gap_bluebox.c \ gap_bluebox.h \ gap_vex_main.c \ gap_vex_main.h \ gap_vex_exec.c \ gap_vex_exec.h \ gap_vex_dialog.c \ gap_vex_dialog.h \ gap_audio_extract.c \ gap_audio_extract.h \ gap_player_main.h \ gap_player_dialog.c \ 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 gap_video_index_SOURCES = \ gap_video_index_creator.c \ gap_libgapstory.h \ gap_libgimpgap.h gap_wr_opacity_SOURCES = \ gap_lastvaldesc.c \ gap_lastvaldesc.h \ gap_wr_opacity.c \ gap_libgimpgap.h gap_wr_trans_SOURCES = \ gap_lastvaldesc.c \ gap_lastvaldesc.h \ gap_wr_trans.c \ gap_libgimpgap.h gap_wr_color_curve_SOURCES = \ gap_wr_color_curve.c \ gap_libgimpgap.h gap_wr_color_levels_SOURCES = \ gap_wr_color_levels.c \ gap_libgimpgap.h gap_wr_color_huesat_SOURCES = \ gap_wr_color_huesat.c \ gap_libgimpgap.h gap_wr_resynth_SOURCES = \ gap_wr_resynth.c \ gap_lastvaldesc.c \ gap_lastvaldesc.h \ gap_libgimpgap.h if OS_WIN32 mwindows = -mwindows endif AM_CPPFLAGS = \ -DGAPLIBDIR=\""$(GAPLIBDIR)"\" \ -DLOCALEDIR=\""$(LOCALEDIR)"\" INCLUDES = \ -I$(top_srcdir) \ -I$(top_srcdir)/libwavplayclient \ $(INC_LIBGAPBASE) \ $(INC_GAPVIDEOAPI) \ $(GIMP_CFLAGS) \ -I$(includedir) AM_LDFLAGS = $(mwindows) LDADD = $(GIMP_LIBS) gap_plugins_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_bluebox_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_decode_mplayer_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_morph_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_name2layer_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_navigator_dialog_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_player_LDADD = $(GAPVIDEOAPI) $(WAVPLAYCLIENT) ${LIBGAPSTORY} $(LIBGAPBASE) $(GIMP_LIBS) gap_onion_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_storyboard_LDADD = $(GAPVIDEOAPI) $(WAVPLAYCLIENT) ${LIBGAPSTORY} $(LIBGAPBASE) $(GIMP_LIBS) gap_video_extract_LDADD = $(GAPVIDEOAPI) $(WAVPLAYCLIENT) ${LIBGAPSTORY} $(LIBGAPBASE) $(GIMP_LIBS) gap_video_index_LDADD = $(GAPVIDEOAPI) $(LIBGAPSTORY) $(LIBGAPBASE) $(GIMP_LIBS) gap_wr_opacity_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_wr_trans_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_wr_color_curve_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_wr_color_levels_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_wr_color_huesat_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_wr_resynth_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) EXTRA_DIST = \ README \ README_developers \ TESTPROT_iter_ALT \ gimplastvaldesc.c \ gimplastvaldesc.h \ gap_story_render_lossless.c \ iter_ALT/README_iter_subdirs \ iter_ALT/gen/plug_in_CML_explorer_iter_ALT.inc \ iter_ALT/gen/plug_in_alpha2color_iter_ALT.inc \ iter_ALT/gen/plug_in_blinds_iter_ALT.inc \ iter_ALT/gen/plug_in_borderaverage_iter_ALT.inc \ iter_ALT/gen/plug_in_checkerboard_iter_ALT.inc \ iter_ALT/gen/plug_in_color_map_iter_ALT.inc \ iter_ALT/gen/plug_in_colorify_iter_ALT.inc \ iter_ALT/gen/plug_in_cubism_iter_ALT.inc \ iter_ALT/gen/plug_in_destripe_iter_ALT.inc \ iter_ALT/gen/plug_in_diffraction_iter_ALT.inc \ iter_ALT/gen/plug_in_displace_iter_ALT.inc \ iter_ALT/gen/plug_in_edge_iter_ALT.inc \ iter_ALT/gen/plug_in_engrave_iter_ALT.inc \ iter_ALT/gen/plug_in_flarefx_iter_ALT.inc \ iter_ALT/gen/plug_in_fractal_trace_iter_ALT.inc \ iter_ALT/gen/plug_in_gfig_iter_ALT.inc \ iter_ALT/gen/plug_in_glasstile_iter_ALT.inc \ iter_ALT/gen/plug_in_grid_iter_ALT.inc \ iter_ALT/gen/plug_in_jigsaw_iter_ALT.inc \ iter_ALT/gen/plug_in_mblur_iter_ALT.inc \ iter_ALT/gen/plug_in_mosaic_iter_ALT.inc \ iter_ALT/gen/plug_in_newsprint_iter_ALT.inc \ iter_ALT/gen/plug_in_noisify_iter_ALT.inc \ iter_ALT/gen/plug_in_pixelize_iter_ALT.inc \ iter_ALT/gen/plug_in_randomize_hurl_iter_ALT.inc \ iter_ALT/gen/plug_in_randomize_pick_iter_ALT.inc \ iter_ALT/gen/plug_in_randomize_slur_iter_ALT.inc \ iter_ALT/gen/plug_in_ripple_iter_ALT.inc \ iter_ALT/gen/plug_in_scatter_hsv_iter_ALT.inc \ iter_ALT/gen/plug_in_sharpen_iter_ALT.inc \ iter_ALT/gen/plug_in_shift_iter_ALT.inc \ iter_ALT/gen/plug_in_spread_iter_ALT.inc \ iter_ALT/gen/plug_in_video_iter_ALT.inc \ iter_ALT/gen/plug_in_vpropagate_iter_ALT.inc \ iter_ALT/gen/plug_in_waves_iter_ALT.inc \ iter_ALT/gen/plug_in_whirl_pinch_iter_ALT.inc \ iter_ALT/gen/plug_in_wind_iter_ALT.inc \ iter_ALT/mod/plug_in_Twist_iter_ALT.inc \ iter_ALT/mod/plug_in_alienmap_iter_ALT.inc \ iter_ALT/mod/plug_in_applylens_iter_ALT.inc \ iter_ALT/mod/plug_in_bump_map_iter_ALT.inc \ iter_ALT/mod/plug_in_cartoon_iter_ALT.inc \ iter_ALT/mod/plug_in_colors_channel_mixer_iter_ALT.inc \ iter_ALT/mod/plug_in_convmatrix_iter_ALT.inc \ iter_ALT/mod/plug_in_depth_merge_iter_ALT.inc \ iter_ALT/mod/plug_in_despeckle_iter_ALT.inc \ iter_ALT/mod/plug_in_dog_iter_ALT.inc \ iter_ALT/mod/plug_in_emboss_iter_ALT.inc \ iter_ALT/mod/plug_in_exchange_iter_ALT.inc \ iter_ALT/mod/plug_in_flame_iter_ALT.inc \ iter_ALT/mod/plug_in_gauss_iter_ALT.inc \ iter_ALT/mod/plug_in_gimpressionist_iter_ALT.inc \ iter_ALT/mod/plug_in_lighting_iter_ALT.inc \ iter_ALT/mod/plug_in_map_object_iter_ALT.inc \ iter_ALT/mod/plug_in_maze_iter_ALT.inc \ iter_ALT/mod/plug_in_neon_iter_ALT.inc \ iter_ALT/mod/plug_in_nlfilt_iter_ALT.inc \ iter_ALT/mod/plug_in_nova_iter_ALT.inc \ iter_ALT/mod/plug_in_oilify_iter_ALT.inc \ iter_ALT/mod/plug_in_pagecurl_iter_ALT.inc \ iter_ALT/mod/plug_in_papertile_iter_ALT.inc \ iter_ALT/mod/plug_in_photocopy_iter_ALT.inc \ iter_ALT/mod/plug_in_plasma_iter_ALT.inc \ iter_ALT/mod/plug_in_polar_coords_iter_ALT.inc \ iter_ALT/mod/plug_in_retinex_iter_ALT.inc \ iter_ALT/mod/plug_in_sample_colorize_iter_ALT.inc \ iter_ALT/mod/plug_in_sinus_iter_ALT.inc \ iter_ALT/mod/plug_in_softglow_iter_ALT.inc \ iter_ALT/mod/plug_in_solid_noise_iter_ALT.inc \ iter_ALT/mod/plug_in_sparkle_iter_ALT.inc \ iter_ALT/mod/plug_in_alienmap2_iter_ALT.inc \ iter_ALT/mod/plug_in_apply_canvas_iter_ALT.inc \ iter_ALT/mod/plug_in_colortoalpha_iter_ALT.inc \ iter_ALT/mod/plug_in_deinterlace_iter_ALT.inc \ iter_ALT/mod/plug_in_illusion_iter_ALT.inc \ iter_ALT/mod/plug_in_lic_iter_ALT.inc \ iter_ALT/mod/plug_in_sel_gauss_iter_ALT.inc \ iter_ALT/mod/plug_in_small_tiles_iter_ALT.inc \ iter_ALT/mod/plug_in_sobel_iter_ALT.inc \ iter_ALT/mod/plug_in_unsharp_mask_iter_ALT.inc \ iter_ALT/old/plug_in_CentralReflection_iter_ALT.inc \ iter_ALT/old/plug_in_anamorphose_iter_ALT.inc \ iter_ALT/old/plug_in_blur2_iter_ALT.inc \ iter_ALT/old/plug_in_colorify_iter_ALT.inc \ iter_ALT/old/plug_in_encript_iter_ALT.inc \ iter_ALT/old/plug_in_figures_iter_ALT.inc \ iter_ALT/old/plug_in_gflare_iter_ALT.inc \ iter_ALT/old/plug_in_holes_iter_ALT.inc \ iter_ALT/old/plug_in_julia_iter_ALT.inc \ iter_ALT/old/plug_in_magic_eye_iter_ALT.inc \ iter_ALT/old/plug_in_mandelbrot_iter_ALT.inc \ iter_ALT/old/plug_in_randomize_iter_ALT.inc \ iter_ALT/old/plug_in_refract_iter_ALT.inc \ iter_ALT/old/plug_in_struc_iter_ALT.inc \ iter_ALT/old/plug_in_tileit_iter_ALT.inc \ iter_ALT/old/plug_in_universal_filter_iter_ALT.inc \ iter_ALT/old/plug_in_warp_iter_ALT.inc \ $(scriptdata_DATA) gimp-gap-2.6.0+dfsg.orig/gap/gap_resi_dialog.c0000644000175000017500000010107311212030253020772 0ustar thibautthibaut/* gap_resi_dialog.c * 1998.07.01 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains the resize and scale Dialog for video frames. */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history * gimp 1.3.14a; 2003/05/25 hof: reincarnation of gap_resi_dialog, now uses GimpOffsetArea * dialog code was inspired by gimp-core resize-dialog.c * to give similar look and feel, * but without unit and resolution stuff. * (videoframes are measured in pixels) * gimp 1.1.13b; 1999/12/04 hof: some cosmetic gtk fixes * changed Buttons in action area * to same style as used in dialogs of the gimp 1.1.13 main dialogs * 0.96.00; 1998/07/01 hof: first release */ #include "config.h" /* SYTEM (UNIX) includes */ #include /* GIMP includes */ #include "gtk/gtk.h" #include "gap-intl.h" #include "libgimp/gimp.h" #include "libgimp/gimpui.h" /* GAP includes */ #include "gap_lib.h" #include "gap_range_ops.h" #include "gap_resi_dialog.h" /* common used spinbutton char width */ #define SB_WIDTH 10 #define GAP_HELP_ID_CROP "plug-in-gap-anim-crop" #define GAP_HELP_ID_RESIZE "plug-in-gap-anim-resize" #define GAP_HELP_ID_SCALE "plug-in-gap-anim-scale" typedef struct { GapRangeOpsAsiz asiz_mode; /* GAP specific resize mode GAP_ASIZ_SCALE, GAP_ASIZ_RESIZE, GAP_ASIZ_CROP */ gint32 image_id; gint32 orig_width; gint32 orig_height; gint32 width; gint32 height; gint32 offset_x; gint32 offset_y; gdouble ratio_x; gdouble ratio_y; GtkWidget *dlg; gint run; GtkWidget *shell; GtkWidget *constrain; GtkWidget *offset_area; /* GimpOffsetArea */ GtkWidget *orig_width_label; GtkWidget *orig_height_label; GtkObject *width_adj; GtkObject *height_adj; GtkObject *ratio_x_adj; GtkObject *ratio_y_adj; GtkObject *offset_x_adj; GtkObject *offset_y_adj; gboolean in_call; } GapResizePrivateType; /* ----------------------------- * p_resize_bound_off_x * p_resize_bound_off_y * ----------------------------- * IN: offset value * RETURN the offsetvalue CLAMped to the legal boundaries. * * This procedures do also set lowr/upper limits for the * offset adjustment widgets */ static gint p_resize_bound_off_x (GapResizePrivateType *res_private, gint off_x) { if( res_private->offset_x_adj == NULL) { return 0; } if (res_private->orig_width <= res_private->width) { off_x = CLAMP (off_x, 0, (res_private->width - res_private->orig_width)); GTK_ADJUSTMENT(res_private->offset_x_adj)->lower = 0; GTK_ADJUSTMENT(res_private->offset_x_adj)->upper = res_private->width - res_private->orig_width; } else { off_x = CLAMP (off_x, (res_private->width - res_private->orig_width), 0); GTK_ADJUSTMENT(res_private->offset_x_adj)->lower = res_private->width - res_private->orig_width; GTK_ADJUSTMENT(res_private->offset_x_adj)->upper = 0; } return off_x; } static gint p_resize_bound_off_y (GapResizePrivateType *res_private, gint off_y) { if( res_private->offset_y_adj == NULL) { return 0; } if (res_private->orig_height <= res_private->height) { off_y = CLAMP (off_y, 0, (res_private->height - res_private->orig_height)); GTK_ADJUSTMENT(res_private->offset_y_adj)->lower = 0; GTK_ADJUSTMENT(res_private->offset_y_adj)->upper = res_private->height - res_private->orig_height; } else { off_y = CLAMP (off_y, (res_private->height - res_private->orig_height), 0); GTK_ADJUSTMENT(res_private->offset_y_adj)->lower = res_private->height - res_private->orig_height; GTK_ADJUSTMENT(res_private->offset_y_adj)->upper = 0; } return off_y; } /* ----------------------------- * p_res_cancel_callback * ----------------------------- */ static void p_res_cancel_callback (GtkWidget *widget, GapResizePrivateType *res_private) { gtk_main_quit (); } /* end p_res_cancel_callback */ /* ----------------------------- * p_res_ok_callback * ----------------------------- */ static void p_res_ok_callback (GtkWidget *widget, GapResizePrivateType *res_private) { if(res_private) { res_private->run = TRUE; gtk_widget_destroy (GTK_WIDGET (res_private->dlg)); } } /* end p_res_ok_callback */ /* ----------------------------- * p_res_help_callback * ----------------------------- */ static void p_res_help_callback (GtkWidget *widget, GapResizePrivateType *res_private) { if(res_private) { switch(res_private->asiz_mode) { case GAP_ASIZ_SCALE: gimp_standard_help_func(GAP_HELP_ID_SCALE, res_private->dlg); break; case GAP_ASIZ_RESIZE: gimp_standard_help_func(GAP_HELP_ID_RESIZE, res_private->dlg); break; case GAP_ASIZ_CROP: gimp_standard_help_func(GAP_HELP_ID_CROP, res_private->dlg); break; } } } /* end p_res_help_callback */ /* ----------------------------- * p_set_size_spinbuttons * ----------------------------- */ static void p_set_size_spinbuttons(GapResizePrivateType *res_private) { gtk_adjustment_set_value (GTK_ADJUSTMENT (res_private->width_adj) , (gdouble)res_private->width); gtk_adjustment_set_value (GTK_ADJUSTMENT (res_private->height_adj) , (gdouble)res_private->height); gtk_adjustment_set_value (GTK_ADJUSTMENT (res_private->ratio_x_adj) , (gdouble)res_private->ratio_x); gtk_adjustment_set_value (GTK_ADJUSTMENT (res_private->ratio_y_adj) , (gdouble)res_private->ratio_y); } /* end p_set_size_spinbuttons */ /* ----------------------------- * p_set_offset_spinbuttons * ----------------------------- */ static void p_set_offset_spinbuttons(GapResizePrivateType *res_private) { if((res_private->offset_x_adj == NULL) || (res_private->offset_y_adj == NULL)) { return; } gtk_adjustment_set_value (GTK_ADJUSTMENT (res_private->offset_x_adj) , res_private->offset_x); gtk_adjustment_set_value (GTK_ADJUSTMENT (res_private->offset_y_adj) , res_private->offset_y); } /* end p_set_offset_spinbuttons */ /* ----------------------------- * p_res_reset_callback * ----------------------------- */ static void p_res_reset_callback (GtkWidget *widget, gpointer data) { GapResizePrivateType *res_private; res_private = (GapResizePrivateType *)data; if(res_private == NULL) {return;} res_private->width = res_private->orig_width; res_private->height = res_private->orig_height; p_set_size_spinbuttons(res_private); if((res_private->asiz_mode != GAP_ASIZ_SCALE) && (res_private->offset_area)) { res_private->offset_x = 0; res_private->offset_y = 0; p_set_offset_spinbuttons(res_private); gimp_offset_area_set_size (GIMP_OFFSET_AREA (res_private->offset_area), res_private->width, res_private->height); gimp_offset_area_set_offsets (GIMP_OFFSET_AREA (res_private->offset_area), res_private->offset_x, res_private->offset_y); } } /* end p_res_reset_callback */ /* ----------------------------- * p_size_update * ----------------------------- */ static void p_size_update (GapResizePrivateType *res_private, double width, double height, double ratio_x, double ratio_y) { res_private->width = (gint) (width + 0.5); res_private->height = (gint) (height + 0.5); res_private->ratio_x = ratio_x; res_private->ratio_y = ratio_y; if(res_private->in_call) { return; } res_private->in_call = TRUE; if (res_private->offset_area) { gimp_offset_area_set_size (GIMP_OFFSET_AREA (res_private->offset_area), res_private->width, res_private->height); p_resize_bound_off_x(res_private, 0); p_resize_bound_off_y(res_private, 0); p_set_offset_spinbuttons(res_private); } p_set_size_spinbuttons(res_private); res_private->in_call = FALSE; } /* end p_size_update */ /* ----------------------------- * p_size_callback * ----------------------------- */ static void p_size_callback(GtkWidget *w, gpointer data) { GapResizePrivateType *res_private; gdouble width; gdouble height; gdouble ratio_x; gdouble ratio_y; res_private = (GapResizePrivateType *) data; if(res_private == NULL) {return;} width = GTK_ADJUSTMENT (res_private->width_adj)->value; height = GTK_ADJUSTMENT (res_private->height_adj)->value; ratio_x = width / (gdouble) res_private->orig_width; ratio_y = height / (gdouble) res_private->orig_height; if (gimp_chain_button_get_active (GIMP_CHAIN_BUTTON (res_private->constrain))) { if (ratio_x != res_private->ratio_x) { ratio_y = ratio_x; height = (gdouble) res_private->orig_height * ratio_y; height = CLAMP (height, GIMP_MIN_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE); } else { ratio_x = ratio_y; width = (gdouble) res_private->orig_width * ratio_x; width = CLAMP (width, GIMP_MIN_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE); } } p_size_update (res_private, width, height, ratio_x, ratio_y); } /* end p_size_callback */ /* ----------------------------- * p_ratio_callback * ----------------------------- */ static void p_ratio_callback(GtkWidget *w, gpointer data) { GapResizePrivateType *res_private; gdouble width; gdouble height; gdouble ratio_x; gdouble ratio_y; res_private = (GapResizePrivateType *) data; if(res_private == NULL) {return;} if(res_private->in_call) {return;} width = GTK_ADJUSTMENT (res_private->width_adj)->value; height = GTK_ADJUSTMENT (res_private->height_adj)->value; ratio_x = GTK_ADJUSTMENT (res_private->ratio_x_adj)->value; ratio_y = GTK_ADJUSTMENT (res_private->ratio_y_adj)->value; if (gimp_chain_button_get_active (GIMP_CHAIN_BUTTON (res_private->constrain))) { if (ratio_x != res_private->ratio_x) { ratio_y = ratio_x; } else { ratio_x = ratio_y; } } width = CLAMP (res_private->orig_width * ratio_x, GIMP_MIN_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE); height = CLAMP (res_private->orig_height * ratio_y, GIMP_MIN_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE); p_size_update (res_private, width, height, ratio_x, ratio_y); } /* end p_ratio_callback */ /* ----------------------------- * p_offset_update * ----------------------------- */ static void p_offset_update(GtkWidget *w, gpointer data) { GapResizePrivateType *res_private; gdouble ofs_x; gdouble ofs_y; res_private = (GapResizePrivateType *) data; if(res_private == NULL) {return;} ofs_x = GTK_ADJUSTMENT(res_private->offset_x_adj)->value; ofs_y = GTK_ADJUSTMENT(res_private->offset_y_adj)->value; res_private->offset_x = p_resize_bound_off_x (res_private, RINT(ofs_x)); res_private->offset_y = p_resize_bound_off_y (res_private, RINT(ofs_y)); gimp_offset_area_set_offsets (GIMP_OFFSET_AREA (res_private->offset_area) , res_private->offset_x , res_private->offset_y); } /* end p_offset_update */ /* ----------------------------- * p_offset_x_center_clicked * ----------------------------- */ static void p_offset_x_center_clicked(GtkWidget *w, gpointer data) { GapResizePrivateType *res_private; gint off_x; res_private = (GapResizePrivateType *) data; if(res_private == NULL) {return;} off_x = p_resize_bound_off_x (res_private, (res_private->width - res_private->orig_width) / 2); res_private->offset_x = off_x; p_set_offset_spinbuttons(res_private); gimp_offset_area_set_offsets (GIMP_OFFSET_AREA (res_private->offset_area), res_private->offset_x, res_private->offset_y); } /* end p_offset_x_center_clicked */ /* ----------------------------- * p_offset_y_center_clicked * ----------------------------- */ static void p_offset_y_center_clicked(GtkWidget *w, gpointer data) { GapResizePrivateType *res_private; gint off_y; res_private = (GapResizePrivateType *) data; if(res_private == NULL) {return;} off_y = p_resize_bound_off_y (res_private, (res_private->height - res_private->orig_height) / 2); res_private->offset_y = off_y; p_set_offset_spinbuttons(res_private); gimp_offset_area_set_offsets (GIMP_OFFSET_AREA (res_private->offset_area), res_private->offset_x, res_private->offset_y); } /* end p_offset_y_center_clicked */ /* ----------------------------- * p_offset_area_offsets_changed * ----------------------------- */ /* XXX ?? wonder why glib calling code should know about the offest parameters * XXX standard G_CALLBACK procedures have 2 Parameters Widget and gpointer only ?? * XXX could it be some object oriented magic ?? */ static void p_offset_area_offsets_changed (GtkWidget *offset_area, gint offset_x, gint offset_y, gpointer data) { GapResizePrivateType *res_private; /* GimpOffsetArea *oa_ptr; */ /* gint offset_x; */ /* gint offset_y; */ res_private = (GapResizePrivateType *) data; if(res_private == NULL) {return;} /* oa_ptr = (GimpOffsetArea *)res_private->offset_area; */ /* size_x = oa_ptr->width; */ /* size_y = oa_ptr->height; */ /* offset_x = oa_ptr->offset_x; */ /* offset_y = oa_ptr->offset_y; */ if((res_private->offset_x != offset_x) || (res_private->offset_y != offset_y)) { res_private->offset_x = offset_x; res_private->offset_y = offset_y; p_set_offset_spinbuttons(res_private); } } /* end p_offset_area_offsets_changed */ /* -------------------------- * p_orig_labels_update * -------------------------- */ static void p_orig_labels_update (GtkWidget *widget, gpointer data) { GapResizePrivateType *res_private; gchar buf[32]; res_private = (GapResizePrivateType *) data; if(res_private) { g_snprintf (buf, sizeof (buf), "%d", res_private->orig_width); gtk_label_set_text (GTK_LABEL (res_private->orig_width_label), buf); g_snprintf (buf, sizeof (buf), "%d", res_private->orig_height); gtk_label_set_text (GTK_LABEL (res_private->orig_height_label), buf); } } /* end p_orig_labels_update */ /* -------------------------- * gap_resi_dialog * -------------------------- * Resize dialog used for resize and cropping frames * based on the GimpOffsetArea widget */ gint gap_resi_dialog (gint32 image_id, GapRangeOpsAsiz asiz_mode, char *title_text, long *size_x, long *size_y, long *offs_x, long *offs_y) { gint l_run; GapResizePrivateType *res_private; GtkWidget *hbbox; GtkWidget *button; GtkWidget *vbox; GtkWidget *main_vbox; GtkWidget *table; GtkWidget *table2; GtkWidget *table3; GtkWidget *label; GtkWidget *frame; GtkWidget *spinbutton; GtkWidget *abox; gdouble l_max_image_width; gdouble l_max_image_height; gdouble l_max_ratio_x; gdouble l_max_ratio_y; abox = NULL; frame = NULL; /* Initialize the GapResizePrivateType structure */ res_private = (GapResizePrivateType *) g_malloc (sizeof (GapResizePrivateType)); res_private->image_id = image_id; res_private->run = FALSE; res_private->in_call = FALSE; res_private->asiz_mode = asiz_mode; /* get info about the image (size is common to all frames) */ res_private->orig_width = gimp_image_width(image_id); res_private->orig_height = gimp_image_height(image_id); res_private->width = res_private->orig_width; res_private->height = res_private->orig_height; res_private->offset_x = 0; res_private->offset_y = 0; res_private->ratio_x = 1.0; res_private->ratio_y = 1.0; l_max_image_width = GIMP_MAX_IMAGE_SIZE; l_max_image_height = GIMP_MAX_IMAGE_SIZE; l_max_ratio_x = (gdouble) GIMP_MAX_IMAGE_SIZE / (double) res_private->width; l_max_ratio_y = (gdouble) GIMP_MAX_IMAGE_SIZE / (double) res_private->height; /* for CROP mode only: set sizelimit to original width/height */ if(res_private->asiz_mode == GAP_ASIZ_CROP) { l_max_image_width = res_private->orig_width; l_max_image_height = res_private->orig_height; l_max_ratio_x = 1.0; l_max_ratio_y = 1.0; } res_private->offset_area = NULL; gimp_ui_init ("gap_res_dialog", FALSE); /* the dialog */ res_private->shell = gtk_dialog_new (); res_private->dlg = res_private->shell; gtk_window_set_title (GTK_WINDOW (res_private->shell), title_text); gtk_window_set_position (GTK_WINDOW (res_private->shell), GTK_WIN_POS_MOUSE); g_signal_connect (G_OBJECT (res_private->shell), "destroy", G_CALLBACK (p_res_cancel_callback), NULL); switch(res_private->asiz_mode) { case GAP_ASIZ_SCALE: frame = gimp_frame_new (_("Scale Frames")); break; case GAP_ASIZ_RESIZE: frame = gimp_frame_new (_("Resize Frames")); break; case GAP_ASIZ_CROP: frame = gimp_frame_new (_("Crop Frames")); break; } /* the main vbox */ main_vbox = gtk_vbox_new (FALSE, 4); gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 4); /* gtk_container_add (GTK_CONTAINER (GTK_DIALOG (res_private->shell)->vbox), main_vbox); */ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (res_private->shell)->vbox), main_vbox, TRUE, TRUE, 0); /* button hbox */ gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (res_private->shell)->action_area), 2); gtk_box_set_homogeneous (GTK_BOX (GTK_DIALOG (res_private->shell)->action_area), FALSE); hbbox = gtk_hbutton_box_new (); gtk_box_set_spacing (GTK_BOX (hbbox), 4); gtk_box_pack_end (GTK_BOX (GTK_DIALOG (res_private->shell)->action_area), hbbox, FALSE, FALSE, 0); gtk_widget_show (hbbox); /* the pixel dimensions frame */ gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); vbox = gtk_vbox_new (FALSE, 2); gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); gtk_container_add (GTK_CONTAINER (frame), vbox); table = gtk_table_new (6, 2, FALSE); gtk_container_set_border_width (GTK_CONTAINER (table), 2); gtk_table_set_col_spacings (GTK_TABLE (table), 2); gtk_table_set_col_spacing (GTK_TABLE (table), 0, 4); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_table_set_row_spacing (GTK_TABLE (table), 0, 4); gtk_table_set_row_spacing (GTK_TABLE (table), 1, 4); gtk_table_set_row_spacing (GTK_TABLE (table), 3, 4); gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); /* the original width & height labels */ label = gtk_label_new (_("Current width:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_show (label); label = gtk_label_new (_("Current height:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_show (label); /* the original width & height Values labels */ res_private->orig_width_label = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC (res_private->orig_width_label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), res_private->orig_width_label, 1, 2, 0, 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_show (res_private->orig_width_label); res_private->orig_height_label = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC (res_private->orig_height_label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), res_private->orig_height_label, 1, 2, 1, 2, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_show (res_private->orig_height_label); /* the new size labels */ label = gtk_label_new (_("New width:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_show (label); label = gtk_label_new (_("New height:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_show (label); /* the spinbutton entry new_width */ spinbutton = gimp_spin_button_new (&res_private->width_adj, res_private->orig_width, GIMP_MIN_IMAGE_SIZE, l_max_image_width, 1, 10, 0, 1, 2); gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), SB_WIDTH); gtk_widget_show (spinbutton); gtk_table_attach (GTK_TABLE (table), spinbutton, 1, 2, 2, 3, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); g_signal_connect (res_private->width_adj, "value_changed", G_CALLBACK (p_size_callback), res_private); /* the spinbutton entry new_height */ spinbutton = gimp_spin_button_new (&res_private->height_adj, res_private->orig_height, GIMP_MIN_IMAGE_SIZE, l_max_image_height, 1, 10, 0, 1, 2); gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), SB_WIDTH); gtk_widget_show (spinbutton); gtk_table_attach (GTK_TABLE (table), spinbutton, 1, 2, 3, 4, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); g_signal_connect (res_private->height_adj, "value_changed", G_CALLBACK (p_size_callback), res_private); /* initialize the original width & height labels */ p_orig_labels_update(NULL, res_private); /* the scale ratio labels */ label = gtk_label_new (_("X ratio:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_show (label); label = gtk_label_new (_("Y ratio:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, 5, 6, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_show (label); /* a (2nd) table for the spinbuttons and the chainbutton */ abox = gtk_alignment_new (0.0, 0.5, 0.0, 1.0); table2 = gtk_table_new (2, 2, FALSE); gtk_table_set_col_spacing (GTK_TABLE (table2), 0, 2); gtk_table_set_row_spacing (GTK_TABLE (table2), 0, 2); gtk_container_add (GTK_CONTAINER (abox), table2); gtk_table_attach (GTK_TABLE (table), abox, 1, 2, 4, 6, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_show (abox); /* the spinbutton entry X-scale ratio */ spinbutton = gimp_spin_button_new (&res_private->ratio_x_adj, res_private->ratio_x, (double) GIMP_MIN_IMAGE_SIZE / (double) res_private->width, (double) l_max_ratio_x, 0.01, 0.1, 0, 0.01, 4); gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), SB_WIDTH); gtk_table_attach_defaults (GTK_TABLE (table2), spinbutton, 0, 1, 0, 1); gtk_widget_show (spinbutton); g_signal_connect (res_private->ratio_x_adj, "value_changed", G_CALLBACK (p_ratio_callback), res_private); /* the spinbutton entry Y-scale ratio */ spinbutton = gimp_spin_button_new (&res_private->ratio_y_adj, res_private->ratio_y, (double) GIMP_MIN_IMAGE_SIZE / (double) res_private->height, (double) l_max_ratio_y, 0.01, 0.1, 0, 0.01, 4); gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), SB_WIDTH); gtk_table_attach_defaults (GTK_TABLE (table2), spinbutton, 0, 1, 1, 2); gtk_widget_show (spinbutton); g_signal_connect (res_private->ratio_y_adj, "value_changed", G_CALLBACK (p_ratio_callback), res_private); /* the constrain ratio chainbutton */ res_private->constrain = gimp_chain_button_new (GIMP_CHAIN_RIGHT); gimp_chain_button_set_active (GIMP_CHAIN_BUTTON (res_private->constrain), TRUE); gtk_table_attach_defaults (GTK_TABLE (table2), res_private->constrain, 1, 2, 0, 2); gtk_widget_show (res_private->constrain); gimp_help_set_help_data (GIMP_CHAIN_BUTTON (res_private->constrain)->button, _("Constrain aspect ratio"), NULL); /* the state of the contrain ratio chainbutton is checked in other callbacks (where needed) * there is no need for the chainbutton to have its own callback procedure */ gtk_widget_show (table2); gtk_widget_show (table); gtk_widget_show (vbox); /* code for GAP_ASIZ_RESIZE GAP_ASIZ_CROP using offsets, GAP_ASIZ_SCALE does not */ if(res_private->asiz_mode != GAP_ASIZ_SCALE) { /* the offset frame */ frame = gimp_frame_new (_("Offset")); gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); vbox = gtk_vbox_new (FALSE, 4); gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); gtk_container_add (GTK_CONTAINER (frame), vbox); abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); gtk_box_pack_start (GTK_BOX (vbox), abox, FALSE, FALSE, 0); /* a (3rd) table for the offset spinbuttons */ table3 = gtk_table_new (2, 3, FALSE); gtk_table_set_col_spacing (GTK_TABLE (table3), 0, 2); gtk_table_set_row_spacing (GTK_TABLE (table3), 0, 2); /* gtk_container_add (GTK_CONTAINER (abox), table3); */ /* the x/y offest labels */ label = gtk_label_new (_("X:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table3), label, 0, 1, 0, 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_show (label); label = gtk_label_new (_("Y:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table3), label, 0, 1, 1, 2, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_show (label); /* the spinbutton entry offset_x */ spinbutton = gimp_spin_button_new (&res_private->offset_x_adj, 0, -GIMP_MAX_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE, 1, 10, 0, 1, 2); gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), SB_WIDTH); gtk_table_attach (GTK_TABLE (table3), spinbutton, 1, 2, 0, 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_show (spinbutton); g_signal_connect (res_private->offset_x_adj, "value_changed", G_CALLBACK (p_offset_update), res_private); /* the spinbutton entry offset_y */ spinbutton = gimp_spin_button_new (&res_private->offset_y_adj, 0, -GIMP_MAX_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE, 1, 10, 0, 1, 2); gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), SB_WIDTH); gtk_table_attach (GTK_TABLE (table3), spinbutton, 1, 2, 1, 2, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_show (spinbutton); g_signal_connect (res_private->offset_y_adj, "value_changed", G_CALLBACK (p_offset_update), res_private); /* the center offsetX button */ button = gtk_button_new_with_label (_("Center Horizontal")); gtk_widget_show (button); gtk_table_attach (GTK_TABLE (table3), button, 2, 3, 0, 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); g_signal_connect (button, "clicked", G_CALLBACK (p_offset_x_center_clicked), res_private); /* the center offsetY button */ button = gtk_button_new_with_label (_("Center Vertical")); gtk_widget_show (button); gtk_table_attach (GTK_TABLE (table3), button, 2, 3, 1, 2, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); g_signal_connect (button, "clicked", G_CALLBACK (p_offset_y_center_clicked), res_private); gtk_container_add (GTK_CONTAINER (abox), table3); gtk_widget_show (table3); gtk_widget_show (abox); /* frame to hold GimpOffsetArea */ abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); gtk_box_pack_start (GTK_BOX (vbox), abox, FALSE, FALSE, 0); frame = gimp_frame_new (NULL); gtk_container_add (GTK_CONTAINER (abox), frame); /* the GimpOffsetArea widget */ res_private->offset_area = gimp_offset_area_new (res_private->orig_width , res_private->orig_height); gtk_container_add (GTK_CONTAINER (frame), res_private->offset_area); gtk_widget_show (res_private->offset_area); g_signal_connect (res_private->offset_area, "offsets_changed", G_CALLBACK (p_offset_area_offsets_changed), res_private); gtk_widget_show (frame); gtk_widget_show (abox); gtk_widget_show (vbox); } /* Action area */ if (gimp_show_help_button ()) { button = gtk_button_new_from_stock ( GTK_STOCK_HELP); gtk_box_pack_end (GTK_BOX (hbbox), button, TRUE, TRUE, 0); gtk_widget_show (button); g_signal_connect (GTK_OBJECT (button), "clicked", G_CALLBACK (p_res_help_callback), res_private); } button = gtk_button_new_from_stock ( GIMP_STOCK_RESET); gtk_box_pack_start (GTK_BOX (hbbox), button, TRUE, TRUE, 0); gtk_widget_show (button); g_signal_connect (GTK_OBJECT (button), "clicked", G_CALLBACK (p_res_reset_callback), res_private); button = gtk_button_new_from_stock ( GTK_STOCK_CANCEL); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (hbbox), button, TRUE, TRUE, 0); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (p_res_cancel_callback), NULL); button = gtk_button_new_from_stock ( GTK_STOCK_OK); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (hbbox), button, TRUE, TRUE, 0); gtk_widget_grab_default (button); gtk_widget_show (button); g_signal_connect (GTK_OBJECT (button), "clicked", G_CALLBACK (p_res_ok_callback), res_private); gtk_widget_show (main_vbox); gtk_widget_show (res_private->shell); gtk_main (); gdk_flush (); *size_x = res_private->width; *size_y = res_private->height; *offs_x = res_private->offset_x; *offs_y = res_private->offset_y; if(res_private->asiz_mode == GAP_ASIZ_CROP) { /* the widgets deliver negative offsets when new size is smaller * than original (as needed for gimp_image_resize calls) * but gimp_image_crop needs positive offets * therefore the sign is switched just for CROP operations */ *offs_x = - res_private->offset_x; *offs_y = - res_private->offset_y; } l_run = res_private->run; g_free(res_private); return (l_run); } /* end gap_resi_dialog */ gimp-gap-2.6.0+dfsg.orig/gap/gap_split.h0000644000175000017500000000312211212030253017645 0ustar thibautthibaut/* gap_split.h * 1997.11.01 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * Split image to video frames (separate Images on disk) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 1.3.14a; 2003/05/25 hof: added digits parameter * 0.96.00; 1998/07/03 hof: 1.st releas */ #ifndef _GAP_SPLIT_H #define _GAP_SPLIT_H #include "libgimp/gimp.h" int gap_split_image(GimpRunMode run_mode, gint32 image_id, gint32 inverse_order, gint32 no_alpha, char *extension, gint32 only_visible, gint32 copy_properties, gint32 digits ); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_video_index_creator.c0000644000175000017500000014110411212030253022524 0ustar thibautthibaut/* gap_video_index_creator.c * utility plug-in for explicite creation of a video index for list of videofiles. * plug-in by Wolfgang Hofer 2007/04/02 * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Revision history * (2007/04/02) v1.0 hof: created */ #include "config.h" #include #include #include #include #include #include #include #include "gap_libgapbase.h" #include "gap_arr_dialog.h" #include "gap_story_file.h" #include "gap_story_syntax.h" #include "gap_libgimpgap.h" #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* Includes for GAP Video API */ #include #endif #include "gap-intl.h" /* Defines */ #define PLUG_IN_NAME "plug_in_gap_video_index_creator" #define PLUG_IN_HELP_ID "plug-in-gap-video-index-creator" #define PLUG_IN_PRINT_NAME "Video Index Creator" #define PLUG_IN_AUTHOR "Wolfgang Hofer (hof@gimp.org)" #define PLUG_IN_COPYRIGHT "Wolfgang Hofer" int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */ #define QICK_MODE 0 #define SMART_MODE 1 #define FULLSCAN_MODE 2 #define GAP_VINDEX_PROGRESS_PLUG_IN_PROC "plug_in_gap_vindex_creation_progress" #define PROCESSING_STATUS_STRING "@@@PROCESSING" #define DEFAULT_SMART_PERCENTAGE 15.0 typedef struct { gint32 seltrack; gchar videofile[4000]; gchar preferred_decoder[100]; gint32 mode; gdouble percentage_smart_mode; /* range 1.0 upto 100.0 percent */ } VindexValues; typedef struct GapVideoIndexCreatorProgressParams { /* nickname vipp */ GtkWidget *shell_window; GtkListStore *store; GtkWidget *tv; GtkTreeSelection *sel; GtkWidget *progress_bar_master; GtkWidget *progress_bar_sub; gboolean cancel_video_api; gboolean cancel_immedeiate_request; gboolean cancel_enabled_smart; gboolean processing_finished; VindexValues *val_ptr; GapStoryVideoFileRef *vref; GapStoryVideoFileRef *vref_list; gint32 timertag; t_GVA_Handle *gvahand; GTimeVal startTime; GTimeVal endTime; gint32 numberOfVideos; gint32 numberOfValidVideos; gint32 countVideos; gdouble breakPercentage; gint32 breakFrames; } GapVideoIndexCreatorProgressParams; static VindexValues glob_vindex_vals = { 1 /* seltrack */ , "Test.mpg" /* videofile */ , "libavformat" /* preferred_decoder*/ , FULLSCAN_MODE /* mode */ , DEFAULT_SMART_PERCENTAGE /* percentage_smart_mode */ }; static void query (void); static void run (const gchar *name, /* name of plugin */ gint nparams, /* number of in-paramters */ const GimpParam * param, /* in-parameters */ gint *nreturn_vals, /* number of out-parameters */ GimpParam ** return_vals); /* out-parameters */ static void p_do_processing (GapVideoIndexCreatorProgressParams *vipp); static gboolean p_check_videofile(const char *filename, gint32 seltrack , const char *preferred_decoder); static void p_create_video_index(const char *filename, gint32 seltrack , const char *preferred_decoder , GapVideoIndexCreatorProgressParams *vipp); static void p_set_vref_userdata(GapStoryVideoFileRef *vref, const char *userdata); static void p_set_userdata_processingstatus_check_videofile(GapStoryVideoFileRef *vref , GapVideoIndexCreatorProgressParams *vipp); static void p_make_all_video_index(const char *filename, gint32 seltrack , const char *preferred_decoder ,GapVideoIndexCreatorProgressParams *vipp ); static gint p_vindex_dialog (VindexValues *val_ptr); static void p_vipp_dlg_destroy (GtkWidget *widget, GapVideoIndexCreatorProgressParams *vipp_1); static void p_cancel_button_cb (GtkWidget *w, GapVideoIndexCreatorProgressParams *vipp); static void p_elapsedTimeToString (GapVideoIndexCreatorProgressParams *vipp, char *timeString, gint sizeOfTimeString); static void p_print_vref_list (GapVideoIndexCreatorProgressParams *vipp, GapStoryVideoFileRef *vref_list); static void p_tree_fill (GapVideoIndexCreatorProgressParams *vipp, GapStoryVideoFileRef *vref_list); static void p_create_video_list_widget(GapVideoIndexCreatorProgressParams *vipp, GtkWidget *vbox); static void p_create_progress_window(GapVideoIndexCreatorProgressParams *vipp); static void on_timer_start(GapVideoIndexCreatorProgressParams *vipp); static gboolean p_vid_progress_callback(gdouble progress ,gpointer user_data ); /* Global Variables */ GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run /* run_proc */ }; static GimpParamDef in_args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, { GIMP_PDB_STRING, "videofile", "name of videofile. this file can be a video or textfile containing" " names of videofiles or a storyboard file containing references to videclips"}, { GIMP_PDB_INT32, "seltrack", "selected video track number >= 1 (most videos have only one track)"}, { GIMP_PDB_STRING, "preferred_decoder", "name of the decoder (libavformat or libmpeg3) "}, { GIMP_PDB_INT32, "mode", "0 .. QICK_MODE, 1 .. SMART_MODE, 2 .. FULLSCAN_MODE"}, { GIMP_PDB_FLOAT, "percentage_smart_mode", "1 to 100.0 perceent. stop verifying timecodes after the specidfeid percentage is scanned" " and no critical errors were found so far. (only relevant in SMART_MODE)"} }; static gint global_number_in_args = G_N_ELEMENTS (in_args); /* Functions */ MAIN () static void query (void) { gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); /* the actual installation of the adjust plugin */ gimp_install_procedure (PLUG_IN_NAME, "Create video index for videofile(s)", "This plug-in creates a video index for the specified videofile, " "index creation is skipped if a valid vide index already exists. " "the specified videofilename may refere to a textfile that contains " "a list of videofiles (one videofilename per line)." "in this case all referred vidofiles are processed.", PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("Video Index Creation..."), NULL, GIMP_PLUGIN, global_number_in_args, 0, in_args, NULL); { /* Menu names */ const char *menupath_toolbox_video_split = N_("/Xtns/"); //gimp_plugin_menu_branch_register("", "Video"); gimp_plugin_menu_register (PLUG_IN_NAME, menupath_toolbox_video_split); } } /* end query */ static void run (const gchar *name, /* name of plugin */ gint nparams, /* number of in-paramters */ const GimpParam * param, /* in-parameters */ gint *nreturn_vals, /* number of out-parameters */ GimpParam ** return_vals) /* out-parameters */ { const gchar *l_env; /* Get the runmode from the in-parameters */ GimpRunMode run_mode = param[0].data.d_int32; /* status variable, use it to check for errors in invocation usualy only during non-interactive calling */ GimpPDBStatusType status = GIMP_PDB_SUCCESS; /* always return at least the status to the caller. */ static GimpParam values[2]; INIT_I18N(); l_env = g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } if(gap_debug) fprintf(stderr, "\n\nDEBUG: run %s\n", name); /* initialize the return of the status */ values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; values[1].type = GIMP_PDB_DRAWABLE; values[1].data.d_drawable = -1; *nreturn_vals = 1; *return_vals = values; /* how are we running today? */ switch (run_mode) { case GIMP_RUN_INTERACTIVE: /* Possibly retrieve data from a previous run */ gimp_get_data (PLUG_IN_NAME, &glob_vindex_vals); /* Get information from the dialog */ if (p_vindex_dialog(&glob_vindex_vals) != 0) return; break; case GIMP_RUN_NONINTERACTIVE: /* check to see if invoked with the correct number of parameters */ if (nparams == global_number_in_args) { if(param[1].data.d_string != NULL) { g_snprintf(glob_vindex_vals.videofile, sizeof(glob_vindex_vals.videofile) , "%s" , param[1].data.d_string ); } glob_vindex_vals.seltrack = (gint) param[2].data.d_int32; if(param[3].data.d_string != NULL) { g_snprintf(glob_vindex_vals.preferred_decoder, sizeof(glob_vindex_vals.preferred_decoder) , "%s" , param[3].data.d_string ); } glob_vindex_vals.mode = (gint) param[4].data.d_int32; glob_vindex_vals.percentage_smart_mode = (gint) param[5].data.d_float; } else { status = GIMP_PDB_CALLING_ERROR; } break; case GIMP_RUN_WITH_LAST_VALS: /* Possibly retrieve data from a previous run */ gimp_get_data (PLUG_IN_NAME, &glob_vindex_vals); break; default: break; } if (status == GIMP_PDB_SUCCESS) { GapVideoIndexCreatorProgressParams vip_struct; GapVideoIndexCreatorProgressParams *vipp; vipp = &vip_struct; vipp->vref = NULL; vipp->vref_list = NULL; vipp->shell_window = NULL; vipp->gvahand = NULL; vipp->tv = NULL; vipp->progress_bar_master = NULL; vipp->progress_bar_sub = NULL; vipp->cancel_video_api = FALSE; vipp->timertag = -1; vipp->cancel_immedeiate_request = FALSE; vipp->val_ptr = &glob_vindex_vals; /* Store variable states for next run */ if (run_mode == GIMP_RUN_INTERACTIVE) { gimp_set_data (PLUG_IN_NAME, &glob_vindex_vals, sizeof (VindexValues)); } if (run_mode == GIMP_RUN_NONINTERACTIVE) { /* Run the main processing */ p_do_processing(vipp); } else { /* creaate and open the progress dialog window + (dferred start main processing from the progres dialog) */ p_create_progress_window(vipp); } } values[0].data.d_status = status; } /* end run */ /* --------------- * p_do_processing * --------------- */ static void p_do_processing (GapVideoIndexCreatorProgressParams *vipp) { p_make_all_video_index(vipp->val_ptr->videofile ,vipp->val_ptr->seltrack ,vipp->val_ptr->preferred_decoder ,vipp ); } /* end p_do_processing */ /* -------------------------------- * p_check_videofile * -------------------------------- * check if specified filename is a videofile. * * return FALSE if specified video filename could not be opened as videofile. * */ static gboolean p_check_videofile(const char *filename, gint32 seltrack , const char *preferred_decoder) { t_GVA_Handle *gvahand; /* first check the filename for known video extensions (.avi, .mpeg ...) * before attempt to open as video. * Note that the check_sig call of the gap_vid_api_gimp.c API implementation * allows access to anim frames via the videoapi. * But it does not make sense to detect anim frame images as video here, where * video index creation makes no sense and therefore is not supported. */ if(gap_story_filename_is_videofile_by_ext(filename)) { gvahand = GVA_open_read_pref(filename , seltrack , 1 /* aud_track */ , preferred_decoder , FALSE /* use MMX if available (disable_mmx == FALSE) */ ); if(gvahand) { GVA_close(gvahand); return(TRUE); } } return(FALSE); } /* end p_check_videofile */ /* -------------------------------- * p_is_valid_vindex_available * -------------------------------- */ static gboolean p_is_valid_vindex_available(t_GVA_Handle *gvahand) { gboolean l_have_valid_vindex; l_have_valid_vindex = FALSE; if(gvahand->vindex) { if(gvahand->vindex->total_frames > 0) { l_have_valid_vindex = TRUE; } } return (l_have_valid_vindex); } /* -------------------------------- * p_create_video_index * -------------------------------- * check if specified filename is a videofile and if there is * a valid video index available for that videofile. * In case there is no valid video index, this procedure * will create the video index. * * return FALSE if specified video filename could not be opened as videofile. * */ static void p_create_video_index(const char *filename, gint32 seltrack , const char *preferred_decoder,GapVideoIndexCreatorProgressParams *vipp) { char *vindex_file; gboolean l_have_valid_vindex; t_GVA_Handle *gvahand; vipp->cancel_enabled_smart = FALSE; vindex_file = NULL; l_have_valid_vindex = FALSE; gvahand = GVA_open_read_pref(filename , seltrack , 1 /* aud_track */ , preferred_decoder , FALSE /* use MMX if available (disable_mmx == FALSE) */ ); if(gvahand) { vipp->gvahand = gvahand; /* gvahand->emulate_seek = TRUE; */ gvahand->do_gimp_progress = FALSE; gvahand->progress_cb_user_data = vipp; gvahand->fptr_progress_callback = p_vid_progress_callback; if ((vipp->val_ptr->mode == QICK_MODE) || (vipp->val_ptr->mode == SMART_MODE)) { t_GVA_SeekSupport seekSupp; seekSupp = GVA_check_seek_support(gvahand); if (seekSupp == GVA_SEEKSUPP_NATIVE) { if(gap_debug) { printf("NATIVE SEEK seems to work for video:%s\n SKIPPING video index creation due to QUICK mode.\n" , filename ); } if (vipp->val_ptr->mode == QICK_MODE) { vipp->gvahand = NULL; GVA_close(gvahand); p_set_vref_userdata(vipp->vref, _("NO vindex created (QUICK)")); return; } vipp->cancel_enabled_smart = TRUE; } } /* get video index name */ { t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(dec_elem->decoder_name) { vindex_file = GVA_build_videoindex_filename(filename ,seltrack /* track */ ,dec_elem->decoder_name ); } } l_have_valid_vindex = p_is_valid_vindex_available(gvahand); if (vindex_file == NULL) { vindex_file = g_strdup(""); } if (l_have_valid_vindex) { p_set_vref_userdata(vipp->vref, _("vindex already OK")); if(gap_debug) { printf("VALID VIDEO INDEX found for video:%s\n (index:%s)\n" , filename , vindex_file ); } } else { if(gap_debug) { printf("CREATING VIDEO INDEX for video:%s\n (index:%s)\n" , filename , vindex_file ); } gvahand->create_vindex = TRUE; GVA_count_frames(gvahand); /* here we CRREATE the vindex */ if ((vipp->cancel_video_api != TRUE) && (TRUE == p_is_valid_vindex_available(gvahand))) { p_set_vref_userdata(vipp->vref, _("vindex created (FULLSCAN OK)")); } else { char *usrdata; if (vipp->val_ptr->mode == SMART_MODE) { if(g_file_test(vindex_file, G_FILE_TEST_EXISTS)) { if(gap_debug) { printf("DELETE uncomplete vindex:%s\n", vindex_file); } g_remove(vindex_file); } usrdata = g_strdup_printf(_("NO vindex created (SMART %.1f%% %d frames)") ,(float)vipp->breakPercentage ,(int)vipp->breakFrames ); } else { usrdata = g_strdup_printf(_("incomplete vindex created (%d frames)") ,(int)gvahand->frame_counter ); } p_set_vref_userdata(vipp->vref, usrdata); g_free(usrdata); } } if (vindex_file != NULL) { g_free(vindex_file); } vipp->gvahand = NULL; GVA_close(gvahand); } } /* end p_create_video_index */ /* ----------------------------------------------- * p_set_vref_userdata * ----------------------------------------------- */ static void p_set_vref_userdata(GapStoryVideoFileRef *vref, const char *userdata) { if(vref) { if(vref->userdata != NULL) { g_free(vref->userdata); } vref->userdata = NULL; if(userdata != NULL) { vref->userdata = g_strdup(userdata); } } } /* end p_set_vref_userdata */ /* ----------------------------------------------- * p_set_userdata_processingstatus_check_videofile * ----------------------------------------------- * set userdata to NULL for files that are NO videofiles * (vref elements with userdata NULL are skipped at further processing * but show up in the tv widget list) * * Videofiles that could be opened successfully get * the string "unprocessed" as userdata attribute. */ static void p_set_userdata_processingstatus_check_videofile(GapStoryVideoFileRef *vref_list, GapVideoIndexCreatorProgressParams *vipp) { gboolean l_file_is_videofile; gint32 numberOfFiles; gint32 filesCount; GapStoryVideoFileRef *vref; numberOfFiles = 0; vipp->numberOfVideos = 0; for(vref = vref_list; vref != NULL; vref = vref->next) { numberOfFiles++; vipp->numberOfVideos++; } filesCount = 0; for(vref = vref_list; vref != NULL; vref = vref->next) { if(gap_debug) { printf("filesCount:%d numberOfFiles:%d\n" ,(int)filesCount ,(int)numberOfFiles ); } if(vipp->progress_bar_sub) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(vipp->progress_bar_sub), _("counting and checking videofiles")); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(vipp->progress_bar_sub) , CLAMP(((gdouble)filesCount / (gdouble)numberOfFiles), 0.0, 1.0) ); while(g_main_context_iteration(NULL, FALSE)); if(vipp->cancel_immedeiate_request == TRUE) { p_vipp_dlg_destroy(NULL, vipp); return; } } filesCount++; l_file_is_videofile = FALSE; if(g_file_test(vref->videofile, G_FILE_TEST_EXISTS)) { l_file_is_videofile = p_check_videofile(vref->videofile, vref->seltrack, vref->preferred_decoder); if(gap_debug) { printf("FILE_EXISTS:%s\n .. is_vieofile:%d\n" , vref->videofile , (int)l_file_is_videofile ); } } if (l_file_is_videofile) { p_set_vref_userdata(vref, _("unprocessed")); vipp->numberOfValidVideos++; } else { p_set_vref_userdata(vref, NULL); } } } /* end p_set_userdata_processingstatus_check_videofile */ /* -------------------------------- * p_make_all_video_index * -------------------------------- * the specified filename shall be the name of a single videofile * or the name of a textfile containing names of videofiles * (one name per line) * This procedure processes all the specified videofilenames * by creating a videoindex for all videofiles that * do not yet have a valid videoindex. */ static void p_make_all_video_index(const char *filename, gint32 seltrack , const char *preferred_decoder, GapVideoIndexCreatorProgressParams *vipp) { #define BUF_SIZE 4000 FILE *l_fp; char l_buf[BUF_SIZE]; gboolean l_file_is_videofile; gint l_video_count; GapStoryVideoFileRef *vref_list; GapStoryVideoFileRef *vref; vipp->numberOfVideos = 0; vipp->numberOfValidVideos = 0; vref_list = NULL; /* check if filename is a single viedeofile */ l_file_is_videofile = p_check_videofile(filename, seltrack, preferred_decoder); if (l_file_is_videofile) { vipp->numberOfVideos = 1; vipp->numberOfValidVideos = 1; vref_list = p_new_GapStoryVideoFileRef(filename, seltrack, preferred_decoder , 1 /* max_ref_framenr */ ); p_set_vref_userdata(vref_list, _("unprocessed")); } else { /* 2nd attempt: if the filename does not directly refere to a videofile * it may be a textfile containing a list of videofile names. */ l_fp = g_fopen(filename, "r"); if(l_fp) { while(NULL != fgets(l_buf, BUF_SIZE-1, l_fp)) { l_buf[BUF_SIZE-1] = '\0'; /* chop trailing newline and whitespace */ gap_file_chop_trailingspace_and_nl(&l_buf[0]); if((l_buf[0] == '\0') || (l_buf[0] == '#')) { continue; } if(gap_debug) { printf("LINE scanned:%s\n", &l_buf[0]); } if((strcmp(&l_buf[0], GAP_STBKEY_STB_HEADER) == 0) || (strcmp(&l_buf[0], GAP_STBKEY_CLIP_HEADER) == 0)) { break; } vref = p_new_GapStoryVideoFileRef(&l_buf[0], seltrack, preferred_decoder , 1 /* max_ref_framenr */ ); /* add new elem at begin of list */ vref->next = vref_list; vref_list = vref; } fclose(l_fp); p_set_userdata_processingstatus_check_videofile(vref_list, vipp); } } if ((vref_list == NULL) || (vipp->numberOfValidVideos == 0)) { GapStoryBoard *stb; /* 3rd attempt: check if file is a storyboard file that contains movie clip references * it may be a textfile containing a list of videofile names. */ stb = gap_story_parse(filename); vref_list = gap_story_get_video_file_ref_list(stb); p_set_userdata_processingstatus_check_videofile(vref_list, vipp); } if (vipp->tv != NULL) { p_tree_fill (vipp, vref_list); } vipp->vref_list = vref_list; l_video_count = 0; for(vref = vref_list; (vref != NULL && vipp->numberOfVideos > 0); vref = vref->next) { vipp->cancel_video_api = FALSE; vipp->vref = vref; if(gap_debug) { printf("vref->videofile: %s\n seltrack:%d preferred_decoder:%s" , vref->videofile , (int)vref->seltrack , vref->preferred_decoder ); } if(vipp->progress_bar_master) { gchar *message; gchar *suffix; char timeString[20]; gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(vipp->progress_bar_master) , CLAMP(((gdouble)l_video_count / (gdouble)vipp->numberOfVideos), 0.0, 1.0) ); g_get_current_time(&vipp->endTime); p_elapsedTimeToString (vipp, &timeString[0], sizeof(timeString)); l_video_count++; suffix = g_strdup_printf(_(" %s (%d of %d)") ,timeString ,(int)l_video_count ,(int)vipp->numberOfVideos ); message = gap_base_shorten_filename(NULL /* prefix */ ,vref->videofile /* filenamepart */ ,suffix /* suffix */ ,90 /* l_max_chars */ ); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(vipp->progress_bar_master), message); g_free(suffix); g_free(message); } if(vref->userdata != NULL) { p_set_vref_userdata(vref, PROCESSING_STATUS_STRING); if (vipp->tv != NULL) { p_tree_fill (vipp, vref_list); } p_create_video_index(vref->videofile, vref->seltrack, vref->preferred_decoder, vipp); if (vipp->tv != NULL) { p_tree_fill (vipp, vref_list); } if (vipp->cancel_immedeiate_request == TRUE) { if(gap_debug) { printf("CANCEL_IMMEDEIATE_REQUEST vref->videofile: %s\n seltrack:%d preferred_decoder:%s userdata:%s" , vref->videofile , (int)vref->seltrack , vref->preferred_decoder , vref->userdata ); } vipp->processing_finished = TRUE; return; } } if(vipp->progress_bar_master) { gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(vipp->progress_bar_master) , CLAMP(((gdouble)l_video_count / (gdouble)vipp->numberOfVideos), 0.0, 1.0) ); } } } /* end p_make_all_video_index */ /* ------------------ * p_vindex_dialog * ------------------ * initial dialog to specify parameters. * * return 0 .. OK * -1 .. in case of Error or cancel */ static gint p_vindex_dialog(VindexValues *val_ptr) { #define VR_DIALOG_ARGC 7 #define VR_DECODERS_SIZE 2 #define MODE_SIZE 3 static GapArrArg argv[VR_DIALOG_ARGC]; gint ii; gint ii_seltrack; gint ii_preferred_decoder; gint ii_mode; gint ii_percentage_smart_mode; static char *radio_modes[VR_DECODERS_SIZE] = {"libavformat", "libmpeg3" }; static char *mode_args[MODE_SIZE] = { "QUICK", "SMART", "FULLSCAN" }; static char *mode_help[MODE_SIZE] = { N_("Conditional video index creation, " " based on a few quick timcode probereads.\n" "Skip index creation if native seek seems possible\n" "\nWARNING: positioning via native seek may not work exact in case critical " "timecode steps were not detected in the quick test)") , N_("Conditional video index creation, " "based on probereads for the specified percentage of frames.\n" "Skip index creation if native seek seems possible " "and no critical timecode steps are detected in the probereads so far.\n" "\nWARNING: positioning via native seek may not work exact in case critical " "timecode steps were not detected in the probereads.") , N_("Create video index. Requires unconditional full scann of all frames." "Native seek is enabled only in case all timecodes are OK.") }; gimp_ui_init ("vindex_progress", FALSE); ii=0; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_FILESEL); argv[ii].label_txt = _("Videofile:"); argv[ii].help_txt = _("Name of a videofile to create a videoindex for." " You also can enter the name of a textfile containing a list" " of videofile names (one name per line) to create all videoindexes at once." " a video index enables fast and exact positioning in the videofile."); argv[ii].text_buf_len = sizeof(val_ptr->videofile); argv[ii].text_buf_ret = &val_ptr->videofile[0]; argv[ii].entry_width = 400; ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_OPT_ENTRY); ii_preferred_decoder = ii; argv[ii].label_txt = _("Decoder:"); argv[ii].help_txt = _("Create video index based on the specified decoder library"); argv[ii].radio_argc = VR_DECODERS_SIZE; argv[ii].radio_argv = radio_modes; argv[ii].radio_ret = 0; argv[ii].has_default = TRUE; argv[ii].radio_default = 0; argv[ii].text_buf_ret = &val_ptr->preferred_decoder[0]; argv[ii].text_buf_len = sizeof(val_ptr->preferred_decoder); argv[ii].text_buf_default = g_strdup("libavformat\0"); ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_INT); ii_seltrack = ii; argv[ii].constraint = TRUE; argv[ii].label_txt = _("Track:"); argv[ii].help_txt = _("Select video track"); argv[ii].int_min = (gint)1; argv[ii].int_max = (gint)100; argv[ii].int_ret = (gint)glob_vindex_vals.seltrack; argv[ii].entry_width = 60; argv[ii].has_default = TRUE; argv[ii].int_default = 1; ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_RADIO); ii_mode = ii; argv[ii].constraint = TRUE; argv[ii].label_txt = _("Mode:"); argv[ii].help_txt = _("operation mode"); argv[ii].radio_argc = (gint)MODE_SIZE; argv[ii].radio_argv = mode_args; argv[ii].radio_help_argv = mode_help; argv[ii].radio_ret = (gint)glob_vindex_vals.mode; argv[ii].has_default = TRUE; argv[ii].radio_default = FULLSCAN_MODE; ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_FLT); ii_percentage_smart_mode = ii; argv[ii].constraint = TRUE; argv[ii].label_txt = _("Percentage:"); argv[ii].help_txt = _("stop scann after percentage reached and no unplausible timecode was detected so far (only relevant in smart mode)"); argv[ii].flt_min = 1.0; argv[ii].flt_max = (gint)100.0; argv[ii].flt_step = 1.0; argv[ii].flt_ret = (gint)glob_vindex_vals.percentage_smart_mode; argv[ii].entry_width = 60; argv[ii].has_default = TRUE; argv[ii].flt_default = DEFAULT_SMART_PERCENTAGE; ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_DEFAULT_BUTTON); argv[ii].label_txt = _("Default"); argv[ii].help_txt = _("Reset all parameters to default values"); ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_HELP_BUTTON); argv[ii].help_id = PLUG_IN_HELP_ID; if(TRUE == gap_arr_ok_cancel_dialog(_("Video Index Creation"), _("Settings :"), VR_DIALOG_ARGC, argv)) { val_ptr->seltrack = (gint)(argv[ii_seltrack].int_ret); val_ptr->mode = (gint)(argv[ii_mode].int_ret); val_ptr->percentage_smart_mode = (gdouble)(argv[ii_percentage_smart_mode].flt_ret); if(gap_debug) { printf("p_vindex_dialog: PRAMETERS entered via dialog:\n"); printf(" videofile: %s\n", &val_ptr->videofile[0]); printf(" decoder: %s\n", &val_ptr->preferred_decoder[0]); printf(" seltrack: %d\n", (int)val_ptr->seltrack); printf(" mode: %d\n", (int)val_ptr->mode); printf(" percentage_smart_mode: %f\n", (float)val_ptr->percentage_smart_mode); } return 0; } else { return -1; } } /* end p_vindex_dialog */ /* ========================================== progress dialog procedures ===================== */ /* --------------------------------- * p_vipp_dlg_destroy * --------------------------------- */ static void p_vipp_dlg_destroy (GtkWidget *widget, GapVideoIndexCreatorProgressParams *vipp_1) { GtkWidget *dialog; GapVideoIndexCreatorProgressParams *vipp; dialog = NULL; if(vipp_1 != NULL) { vipp = vipp_1; } else { vipp = (GapVideoIndexCreatorProgressParams *)g_object_get_data(G_OBJECT(widget), "vipp"); } if(vipp) { dialog = vipp->shell_window; if(dialog) { vipp->shell_window = NULL; vipp->tv = NULL; vipp->progress_bar_master = NULL; vipp->progress_bar_sub = NULL; vipp->cancel_video_api = TRUE; vipp->cancel_immedeiate_request = TRUE; gtk_widget_destroy (dialog); } } gtk_main_quit (); } /* end p_vipp_dlg_destroy */ /* ----------------------------- * p_cancel_button_cb * ----------------------------- */ static void p_cancel_button_cb (GtkWidget *w, GapVideoIndexCreatorProgressParams *vipp) { if(gap_debug) { printf("VINDEX-PROGRESS-CANCEL BUTTON clicked\n"); } if(vipp) { vipp->cancel_immedeiate_request = TRUE; if (vipp->processing_finished) { p_vipp_dlg_destroy(NULL, vipp); } } } /* end p_cancel_button_cb */ /* ---------------------------- * p_elapsedTimeToString * ---------------------------- */ static void p_elapsedTimeToString (GapVideoIndexCreatorProgressParams *vipp, char *timeString, gint sizeOfTimeString) { glong secondsElapsed; glong microSecondsElapsed; gint32 tmsec; secondsElapsed = vipp->endTime.tv_sec - vipp->startTime.tv_sec; microSecondsElapsed = vipp->endTime.tv_usec - vipp->startTime.tv_usec; tmsec = secondsElapsed * 1000 + ((microSecondsElapsed /1000) % 1000); gap_timeconv_msecs_to_timestr(tmsec, timeString, sizeOfTimeString); } /* end p_elapsedTimeToString */ /* ---------------------------- * p_print_vref_list * ---------------------------- * print the vref_list to stdout */ static void p_print_vref_list (GapVideoIndexCreatorProgressParams *vipp, GapStoryVideoFileRef *vref_list) { gint count_elem; GapStoryVideoFileRef *vref; printf("\n\n----------------------------------------------\n"); printf("Video index creation processing results:\n"); printf("----------------------------------------------\n"); count_elem = 0; for(vref = vref_list; vref != NULL; vref = (GapStoryVideoFileRef *) vref->next) { gchar *label; gchar *video_filename; gchar *processing_status; label = g_strdup_printf("%3d.", (int)count_elem +1); video_filename = gap_base_shorten_filename(NULL /* prefix */ ,vref->videofile /* filenamepart */ ,NULL /* suffix */ ,90 /* l_max_chars */ ); if (vref->userdata == NULL) { processing_status = g_strdup(_(" ** no video **")); } else { if (strcmp(PROCESSING_STATUS_STRING, vref->userdata) == 0) { processing_status = g_strdup(_("processing not finished")); } else { processing_status = g_strdup(vref->userdata); } } printf("%3s %-90.90s %s\n" , label /* visible number starting at 1 */ , video_filename , processing_status ); g_free (label); g_free (video_filename); g_free (processing_status); count_elem++; } { char timeString[20]; p_elapsedTimeToString (vipp, &timeString[0], sizeof(timeString)); printf("\nElapsed Time %s\n", &timeString[0]); printf("----------------------------------------------\n"); } } /* end p_print_vref_list */ /* ---------------------------- * p_tree_fill * ---------------------------- * fill videofile names into the treeview */ static void p_tree_fill (GapVideoIndexCreatorProgressParams *vipp, GapStoryVideoFileRef *vref_list) { GtkTreeIter iter; GtkTreePath *treePathCurrent; GapStoryVideoFileRef *vref; gint count_elem; vipp->store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); gtk_tree_view_set_model (GTK_TREE_VIEW (vipp->tv) ,GTK_TREE_MODEL (vipp->store) ); g_object_unref (vipp->store); count_elem = 0; treePathCurrent = NULL; for(vref = vref_list; vref != NULL; vref = (GapStoryVideoFileRef *) vref->next) { gchar *numtxt; gchar *label; gchar *video_filename; gchar *processing_status; gboolean currentFlag; currentFlag = FALSE; label = g_strdup_printf("%3d.", (int)count_elem +1); numtxt = g_strdup_printf("%d", (int)count_elem); video_filename = gap_base_shorten_filename(NULL /* prefix */ ,vref->videofile /* filenamepart */ ,NULL /* suffix */ ,90 /* l_max_chars */ ); if (vref->userdata == NULL) { processing_status = g_strdup(_(" ** no video **")); } else { if (strcmp(PROCESSING_STATUS_STRING, vref->userdata) == 0) { processing_status = g_strdup(_("processing in progress")); currentFlag = TRUE; } else { processing_status = g_strdup(vref->userdata); } } gtk_list_store_append (vipp->store, &iter); gtk_list_store_set (vipp->store, &iter ,0, numtxt /* internal invisible number starting at 0 */ ,1, label /* visible number starting at 1 */ ,2, video_filename ,3, processing_status ,-1); if(currentFlag == TRUE) { treePathCurrent = gtk_tree_model_get_path (GTK_TREE_MODEL (vipp->store), &iter); } g_free (numtxt); g_free (label); g_free (video_filename); g_free (processing_status); count_elem++; } if (count_elem == 0) { gtk_list_store_append (vipp->store, &iter); gtk_list_store_set (vipp->store, &iter ,0, "-1" ,1, " " ,2, _("** Empty **") ,3, " " ,-1); } gtk_tree_model_get_iter_first (GTK_TREE_MODEL (vipp->store), &iter); gtk_tree_selection_select_iter (vipp->sel, &iter); gtk_tree_selection_unselect_all(vipp->sel); if(treePathCurrent != NULL) { gtk_tree_view_set_cursor(vipp->tv ,treePathCurrent ,NULL /* focus_column */ ,FALSE /* start_editing */ ); } } /* end p_tree_fill */ /* ----------------------------- * p_create_video_list_widget * ----------------------------- */ void p_create_video_list_widget(GapVideoIndexCreatorProgressParams *vipp, GtkWidget *vbox) { GtkWidget *scrolled_window; GtkCellRenderer *renderer; /* list : list in a scrolled_win */ scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0); gtk_widget_show (scrolled_window); vipp->tv = gtk_tree_view_new (); renderer = gtk_cell_renderer_text_new (); gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (vipp->tv), -1, _("Nr"), renderer, "text", 1, NULL); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (vipp->tv), -1, _("videofile"), renderer, "text", 2, NULL); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (vipp->tv), -1, _("Status"), renderer, "text", 3, NULL); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (vipp->tv), TRUE); gtk_widget_set_size_request (vipp->tv, 840 /*WIDTH*/, 250 /*HEIGHT*/); gtk_container_add (GTK_CONTAINER (scrolled_window), vipp->tv); gtk_widget_show (vipp->tv); vipp->sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (vipp->tv)); // g_signal_connect (vipp->sel, "changed", // G_CALLBACK (p_procedure_select_callback), vipp); } /* end p_create_video_list_widget */ /* ----------------------------- * p_create_progress_window * ----------------------------- */ static void p_create_progress_window(GapVideoIndexCreatorProgressParams *vipp) { GtkWidget *dialog; GtkWidget *vbox; GtkWidget *hbox; /* Init UI */ gimp_ui_init ("vindex_progress", FALSE); gap_stock_init(); /* The Storyboard dialog */ vipp->progress_bar_master = NULL; vipp->progress_bar_sub = NULL; /* The dialog and main vbox */ /* the help_id is passed as NULL to avoid creation of the HELP button * (the Help Button would be the only button in the action area and results * in creating an extra row * additional note: the Storyboard dialog provides * Help via Menu-Item */ dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (dialog), _("Video Index Creation Progress")); gtk_window_set_role (GTK_WINDOW (dialog), "vindex-creator-progress"); g_object_set_data (G_OBJECT (dialog), "vipp" , (gpointer)vipp); g_signal_connect (dialog, "destroy", G_CALLBACK (p_vipp_dlg_destroy), vipp); gimp_help_connect (dialog, gimp_standard_help_func, GAP_VINDEX_PROGRESS_PLUG_IN_PROC, NULL); /* the vbox */ vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (dialog), vbox); gtk_widget_show (vbox); vipp->shell_window = dialog; p_create_video_list_widget(vipp, vbox); /* the hbox */ hbox = gtk_hbox_new (FALSE, 2); gtk_container_set_border_width (GTK_CONTAINER (hbox), 2); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); /* The Video ProgressBar */ { GtkWidget *button; GtkWidget *progress_bar; GtkWidget *vbox_progress; vbox_progress = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox_progress); progress_bar = gtk_progress_bar_new (); vipp->progress_bar_master = progress_bar; gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress_bar), " "); gtk_widget_show (progress_bar); gtk_box_pack_start (GTK_BOX (vbox_progress), progress_bar, TRUE, TRUE, 0); progress_bar = gtk_progress_bar_new (); vipp->progress_bar_sub = progress_bar; gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress_bar), " "); gtk_widget_show (progress_bar); gtk_box_pack_start (GTK_BOX (vbox_progress), progress_bar, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox), vbox_progress, TRUE, TRUE, 0); button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); gtk_widget_show (button); gimp_help_set_help_data (button , _("Cancel video access if in progress and disable automatic videothumbnails") , NULL); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (p_cancel_button_cb), vipp); } vipp->timertag = (gint32) g_timeout_add(200 /* millisecs*/ , (GtkFunction)on_timer_start, vipp); gtk_widget_show (dialog); gtk_main (); gdk_flush (); } /* end p_create_progress_window */ /* ----------------------------- * on_timer_start * ----------------------------- * This procedure triggers processing start * in interactive run modes. */ static void on_timer_start(GapVideoIndexCreatorProgressParams *vipp) { if(gap_debug) { printf("on_timer_start\n"); } if(vipp) { if(vipp->timertag >= 0) { g_source_remove(vipp->timertag); vipp->timertag = -1; } vipp->processing_finished = FALSE; if (vipp->cancel_immedeiate_request == TRUE) { if(gap_debug) { printf("pending CANCEL_IMMEDEIATE_REQUEST\n"); } } else { g_get_current_time(&vipp->startTime); p_do_processing(vipp); g_get_current_time(&vipp->endTime); } if(vipp->progress_bar_master) { if(vipp->cancel_immedeiate_request != TRUE) { gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(vipp->progress_bar_master), 1.0); } } if(vipp->progress_bar_sub) { if(vipp->cancel_immedeiate_request == TRUE) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(vipp->progress_bar_sub), _("processing cancelled")); } else { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(vipp->progress_bar_sub), _("processing finished")); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(vipp->progress_bar_sub), 1.0); } } vipp->processing_finished = TRUE; if(vipp->vref_list != NULL) { p_print_vref_list(vipp, vipp->vref_list); } } } /* end on_timer_start */ /* -------------------------------- * p_vid_progress_callback * -------------------------------- * return: TRUE: cancel videoapi immediate * FALSE: continue */ static gboolean p_vid_progress_callback(gdouble progress ,gpointer user_data ) { GapVideoIndexCreatorProgressParams *vipp; gboolean critical_timecode_found; gdouble currentPercentageLimit; vipp = (GapVideoIndexCreatorProgressParams *)user_data; if(vipp == NULL) { return (TRUE); } critical_timecode_found = FALSE; if (vipp->gvahand != NULL) { critical_timecode_found = vipp->gvahand->critical_timecodesteps_found; } if(vipp->progress_bar_sub != NULL) { char *message; if(gap_debug) { printf("p_vid_progress_callback progress:%f\n", progress); } gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(vipp->progress_bar_sub), CLAMP(progress, 0.0, 1.0)); switch (vipp->val_ptr->mode) { case QICK_MODE: message = g_strdup_printf(_("Quick check %0.3f %%"), progress * 100.0); break; case SMART_MODE: if (critical_timecode_found == TRUE) { currentPercentageLimit = 100.0; } else { currentPercentageLimit = vipp->val_ptr->percentage_smart_mode; } message = g_strdup_printf(_("Smart check %0.3f %% (of %0.3f %%)") , progress * 100.0 , currentPercentageLimit ); break; case FULLSCAN_MODE: message = g_strdup_printf(_("Creating video index %0.3f %%"), progress * 100.0); break; default: message = g_strdup_printf("%0.3f %%", progress * 100.0); break; } gtk_progress_bar_set_text(GTK_PROGRESS_BAR(vipp->progress_bar_sub), message); g_free(message); } if ((vipp->val_ptr->mode == SMART_MODE) && (vipp->cancel_enabled_smart == TRUE)) { if ((progress * 100.0 > vipp->val_ptr->percentage_smart_mode) && (critical_timecode_found == FALSE)) { if(gap_debug) { printf("SMART_MODE cancel at progress: %.3f, (limit: %.3f)\n" ,(float)progress ,(float)vipp->val_ptr->percentage_smart_mode ); } vipp->cancel_video_api = TRUE; vipp->breakPercentage = progress * 100.0; vipp->breakFrames = vipp->gvahand->frame_counter; } } /* g_main_context_iteration makes sure that * gtk does refresh widgets, and react on events while the videoapi * is busy with searching for the next frame. */ while(g_main_context_iteration(NULL, FALSE)); return(vipp->cancel_video_api || vipp->cancel_immedeiate_request); /* return (TRUE); */ /* cancel video api if playback was stopped */ } /* end p_vid_progress_callback */ gimp-gap-2.6.0+dfsg.orig/gap/gap_onion_main.h0000644000175000017500000001172011212030253020643 0ustar thibautthibaut/* gap_onion_main.h * 2001.12.10 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module handles ONION Skin Layers in the GIMP Video Menu. * Onion Layer(s) usually do show previous (or next) frame(s) * of the video in the current frame. * * Video/OnionSkin/Configuration ... GUI to configure, create abd delete onionskin Layer(s) for framerange * Video/OnionSkin/Create or Replace ... create or replace onionskin Layer(s) and set visible. * Video/OnionSkin/Delete ... delete onionskin Layer(s) * Video/OnionSkin/Toggle Visibility ... show/hide onionskin layer(s) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 1.3.16c; 2003/07/09 hof: splitted off gap_onion_base.h * 1.3.14a; 2003/05/22 hof: integration into gimp-gap-1.3.14 * 1.3.12a; 2003/05/03 hof: started port to gimp-1.3 /gtk+2.2 * version 1.2.2a; 2001.12.10 hof: created */ #ifndef _GAP_ONION_MAIN_H #define _GAP_ONION_MAIN_H #include "config.h" /* SYTEM (UNIX) includes */ #include #include #include #include #include /* #include */ #include #include #include #include #include #include #include #include #include #include #define GAP_PLUGIN_NAME_ONION_CFG "plug_in_gap_onionskin_configuration" #define GAP_HELP_ID_ONION_CFG "plug-in-gap-onionskin-configuration" #define GAP_PLUGIN_NAME_ONION_APPLY "plug_in_onionskin_create_or_replace" #define GAP_PLUGIN_NAME_ONION_DEL "plug_in_onionskin_del" #define GAP_PLUGIN_NAME_ONION_VISI "plug_in_onionskin_toggle_visibility" #define GAP_ONION_RUN_CANCEL 0 #define GAP_ONION_RUN_SET 1 #define GAP_ONION_RUN_APPLY 2 #define GAP_ONION_RUN_DELETE 3 /* how many frames are kept in cache for range processing */ #define GAP_ONION_CACHE_SIZE 12 /* note: plugin mames starting with plug_in_gap_ * cannot be used as filter in other gap functions (Video->Frames Modify) * that is the reason why MAKE and DEL names do not contain "gap" */ typedef struct GapOnionMainAinfo { long first_frame_nr; long last_frame_nr; long curr_frame_nr; long frame_cnt; char basename[1024]; /* may include path */ char extension[50]; gdouble framerate; } GapOnionMainAinfo; typedef struct GapOnionMainImageCache { gint32 count; gint32 framenr[GAP_ONION_CACHE_SIZE]; gint32 image_id[GAP_ONION_CACHE_SIZE]; gint32 layer_id[GAP_ONION_CACHE_SIZE]; } GapOnionMainImageCache; typedef struct { GapVinVideoInfo vin; gint run; GapOnionMainAinfo ainfo; GapOnionMainImageCache cache; gint32 range_from; gint32 range_to; gint32 image_ID; /* -1 if there is no valid current image */ gint32 layer_ID; /* -1 if there is no valid current image */ GimpRunMode run_mode; GtkWidget *main_dialog; GtkWidget *oni__entry_select_string; GtkWidget *oni__combo_ref_mode; GtkWidget *oni__combo_select_mode; GtkWidget *oni__spinbutton_ignore_botlayers; GtkWidget *oni__spinbutton_num_olayers; GtkWidget *oni__spinbutton_opacity; GtkWidget *oni__spinbutton_opacity_delta; GtkWidget *oni__spinbutton_range_from; GtkWidget *oni__spinbutton_range_to; GtkWidget *oni__spinbutton_ref_delta; GtkWidget *oni__spinbutton_stack_pos; GtkWidget *oni__checkbutton_ref_cycle; GtkWidget *oni__checkbutton_select_case; GtkWidget *oni__checkbutton_select_invert; GtkWidget *oni__checkbutton_stack_top; GtkWidget *oni__checkbutton_asc_opacity; GtkWidget *oni__checkbutton_auto_replace; GtkWidget *oni__checkbutton_auto_delete; GtkObject *oni__spinbutton_ignore_botlayers_adj; GtkObject *oni__spinbutton_num_olayers_adj; GtkObject *oni__spinbutton_opacity_adj; GtkObject *oni__spinbutton_opacity_delta_adj; GtkObject *oni__spinbutton_range_from_adj; GtkObject *oni__spinbutton_range_to_adj; GtkObject *oni__spinbutton_ref_delta_adj; GtkObject *oni__spinbutton_stack_pos_adj; } GapOnionMainGlobalParams; extern GapOnionMainGlobalParams global_params; #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_layer_copy.h0000644000175000017500000000757711212030253020702 0ustar thibautthibaut/* gap_layer_copy.h * 1997.11.06 hof (Wolfgang Hofer) * gap_layer_copy_to_dest_image * can copy layers from a drawable in another image. * * returns the id of the new layer * and the offests of the original within the source image */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 2.1.0a 2004.04.11 hof: added gap_layer_clear_to_color * version 1.3.26a 2004.01.28 hof: added gap_layer_copy_from_buffer * version 1.3.21c 2003.11.02 hof: added gap_layer_copy_to_image * version 1.3.5a 2002.04.20 hof: use gimp_layer_new_from_drawable (API cleanup, requries gimp.1.3.6) * removed channel_copy * version 0.98.00 1998.11.26 hof: added channel copy * version 0.90.00; hof: 1.st (pre) release */ #ifndef _GAP_LAYER_COPY_H #define _GAP_LAYER_COPY_H /* SYTEM (UNIX) includes */ #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" gint32 gap_layer_copy_to_dest_image (gint32 dst_image_id, gint32 src_layer_id, gdouble opacity, /* 0.0 upto 100.0 */ GimpLayerModeEffects mode, gint *src_offset_x, gint *src_offset_y ); gint32 gap_layer_copy_to_image (gint32 dst_image_id, gint32 src_layer_id); gboolean gap_layer_copy_content (gint32 dst_drawable_id, gint32 src_drawable_id); gboolean gap_layer_copy_picked_channel (gint32 dst_drawable_id, guint dst_channel_pick , gint32 src_drawable_id, guint src_channel_pick , gboolean shadow); gint32 gap_layer_new_from_buffer(gint32 dst_image_id , gint32 width , gint32 height , gint32 bpp , guchar *data ); void gap_layer_clear_to_color(gint32 layer_id ,gdouble red ,gdouble green ,gdouble blue ,gdouble alpha ); gint32 gap_layer_flip(gint32 layer_id, gint32 flip_request); void gap_layer_copy_paste_drawable(gint32 image_id, gint32 dst_drawable_id, gint32 src_drawable_id); gint32 gap_layer_get_stackposition(gint32 image_id, gint32 ref_layer_id); gint32 gap_layer_get_id_by_stackposition(gint32 image_id, gint32 stackposition); gint32 gap_layer_make_duplicate(gint32 src_layer_id, gint32 image_id , const char *name_prefix, const char *name_suffix); gint32 gap_layer_create_layer_from_layermask(gint32 src_layer_id , gint32 image_id , const char *name_prefix, const char *name_suffix); gint32 gap_layer_create_layer_from_alpha(gint32 src_layer_id, gint32 image_id , const char *name_prefix, const char *name_suffix , gboolean applyExistingLayermask, gboolean useTransferAlpha); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_story_att_trans_dlg.h0000644000175000017500000000273711212030253022612 0ustar thibautthibaut/* gap_story_att_trans_dlg.h * * This module handles GAP storyboard dialog transition attribute properties window */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 2.2.1-214; 2006/03/31 hof: created */ #ifndef _GAP_STORY_ATT_TRANS_DLG_H #define _GAP_STORY_ATT_TRANS_DLG_H #include "libgimp/gimp.h" #include "gap_story_main.h" GtkWidget * gap_story_attw_properties_dialog (GapStbAttrWidget *attw); void gap_story_att_stb_elem_properties_dialog ( GapStbTabWidgets *tabw , GapStoryElem *stb_elem , GapStoryBoard *stb_dst); void gap_story_att_fw_properties_dialog (GapStbFrameWidget *fw); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_wr_trans.c0000644000175000017500000005416111212030253020355 0ustar thibautthibaut/* gap_wr_trans.c * wrapper plugins to flip or roatate Layer by Wolfgang Hofer * 2005/05/01 */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Revision history * 1.0.0; 2005/05/01 hof: created */ #include "config.h" #include #include #include #include #include #include #include "gap_lastvaldesc.h" #include "gap-intl.h" /* Defines */ #define PLUG_IN_NAME_ANY "plug_in_wr_layer_rotate_any" #define PLUG_IN_NAME_180 "plug_in_wr_layer_rotate_180" #define PLUG_IN_NAME_90 "plug_in_wr_layer_rotate_90" #define PLUG_IN_NAME_270 "plug_in_wr_layer_rotate_270" #define PLUG_IN_NAME_HOR "plug_in_wr_layer_flip_horizontal" #define PLUG_IN_NAME_VER "plug_in_wr_layer_flip_vetrical" #define PLUG_IN_IMAGE_TYPES "RGB*, INDEXED*, GRAY*" #define PLUG_IN_AUTHOR "Wolfgang Hofer (hof@gimp.org)" #define PLUG_IN_COPYRIGHT "Wolfgang Hofer" #define PLUG_IN_BINARY "gap_wr_trans" #define SCALE_WIDTH 200 typedef enum { GAP_TRANS_UNDEFINED ,GAP_TRANS_FLIP_HOR ,GAP_TRANS_FLIP_VER ,GAP_TRANS_ROT_90 ,GAP_TRANS_ROT_180 ,GAP_TRANS_ROT_270 ,GAP_TRANS_ROT_ANY } GapTransLayerMode; typedef struct { gdouble angle_deg; } TransValues; static TransValues glob_vals = { 0.0 /* rotation angle in degree */ }; static void iter_query (); static void query (void); static void run (const gchar *name, /* name of plugin */ gint nparams, /* number of in-paramters */ const GimpParam * param, /* in-parameters */ gint *nreturn_vals, /* number of out-parameters */ GimpParam ** return_vals); /* out-parameters */ static gint32 p_transform_layer(gint32 image_id, gint32 drawable_id, GapTransLayerMode trans_mode, TransValues *val_ptr); static gboolean p_dialog(GapTransLayerMode trans_mode, TransValues *val_ptr); /* Global Variables */ int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */ GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run /* run_proc */ }; static GimpParamDef in_args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, { GIMP_PDB_IMAGE, "image", "Input image" }, { GIMP_PDB_DRAWABLE, "drawable", "Input drawable ()"}, }; static gint global_number_in_args = G_N_ELEMENTS (in_args); static gint global_number_out_args = 0; /* Functions */ MAIN () static void query (void) { static GimpLastvalDef lastvalsRotAny[] = { GIMP_LASTVALDEF_GDOUBLE (GIMP_ITER_TRUE, glob_vals.angle_deg, "angle in degree"), }; static GimpLastvalDef lastvals[] = { GIMP_LASTVALDEF_GDOUBLE (GIMP_ITER_FALSE, glob_vals.angle_deg, "dummy"), }; gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); /* registration for last values buffer structure (useful for animated filter apply) */ gimp_lastval_desc_register(PLUG_IN_NAME_ANY, &glob_vals, sizeof(glob_vals), G_N_ELEMENTS (lastvalsRotAny), lastvalsRotAny); gimp_lastval_desc_register(PLUG_IN_NAME_90, &glob_vals, sizeof(glob_vals), G_N_ELEMENTS (lastvals), lastvals); gimp_lastval_desc_register(PLUG_IN_NAME_180, &glob_vals, sizeof(glob_vals), G_N_ELEMENTS (lastvals), lastvals); gimp_lastval_desc_register(PLUG_IN_NAME_270, &glob_vals, sizeof(glob_vals), G_N_ELEMENTS (lastvals), lastvals); gimp_lastval_desc_register(PLUG_IN_NAME_HOR, &glob_vals, sizeof(glob_vals), G_N_ELEMENTS (lastvals), lastvals); gimp_lastval_desc_register(PLUG_IN_NAME_VER, &glob_vals, sizeof(glob_vals), G_N_ELEMENTS (lastvals), lastvals); /* the actual installation of the plugin */ gimp_install_procedure (PLUG_IN_NAME_HOR, "Flip Layer horizontal", "This plug-in is a wrapper for gimp flip functionality, " "and provides the typical PDB interface for calling it as " "filter in animations." "(for the use with GAP Video Frame manipulation)", PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("Flip Horizontal"), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, global_number_in_args, global_number_out_args, in_args, NULL); gimp_install_procedure (PLUG_IN_NAME_VER, "Flip Layer vertical", "This plug-in is a wrapper for gimp flip functionality, " "and provides the typical PDB interface for calling it as " "filter in animations." "(for the use with GAP Video Frame manipulation)", PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("Flip Vertical"), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, global_number_in_args, global_number_out_args, in_args, NULL); gimp_install_procedure (PLUG_IN_NAME_90, "Rotate Layer by 90 degree", "This plug-in is a wrapper for gimp simple rotate functionality, " "and provides the typical PDB interface for calling it as " "filter in animations." "(for the use with GAP Video Frame manipulation)", PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("Rotate 90 degrees CW"), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, global_number_in_args, global_number_out_args, in_args, NULL); gimp_install_procedure (PLUG_IN_NAME_180, "Rotate Layer by 180 degree", "This plug-in is a wrapper for gimp simple rotate functionality, " "and provides the typical PDB interface for calling it as " "filter in animations." "(for the use with GAP Video Frame manipulation)", PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("Rotate 180 degrees"), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, global_number_in_args, global_number_out_args, in_args, NULL); gimp_install_procedure (PLUG_IN_NAME_270, "Rotate Layer by 270 degree", "This plug-in is a wrapper for gimp simple rotate functionality, " "and provides the typical PDB interface for calling it as " "filter in animations." "(for the use with GAP Video Frame manipulation)", PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("Rotate 90 degrees CCW"), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, global_number_in_args, global_number_out_args, in_args, NULL); gimp_install_procedure (PLUG_IN_NAME_ANY, "Rotate Layer by specified angle in degree", "This plug-in is a wrapper for gimp rotate functionality, " "and provides the typical PDB interface for calling it as " "filter in animations." "(for the use with GAP Video Frame manipulation)", PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("Rotate any angle"), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, global_number_in_args, global_number_out_args, in_args, NULL); { /* Menu names */ const char *menupath_image_video_layer_transform = N_("/Video/Layer/Transform/"); //gimp_plugin_menu_branch_register("", "Video"); //gimp_plugin_menu_branch_register("/Video", "Layer"); //gimp_plugin_menu_branch_register("/Video/Layer", "Transform"); gimp_plugin_menu_register (PLUG_IN_NAME_HOR, menupath_image_video_layer_transform); gimp_plugin_menu_register (PLUG_IN_NAME_VER, menupath_image_video_layer_transform); gimp_plugin_menu_register (PLUG_IN_NAME_90, menupath_image_video_layer_transform); gimp_plugin_menu_register (PLUG_IN_NAME_180, menupath_image_video_layer_transform); gimp_plugin_menu_register (PLUG_IN_NAME_270, menupath_image_video_layer_transform); gimp_plugin_menu_register (PLUG_IN_NAME_ANY, menupath_image_video_layer_transform); } } /* end query */ static void run (const gchar *name, /* name of plugin */ gint nparams, /* number of in-paramters */ const GimpParam * param, /* in-parameters */ gint *nreturn_vals, /* number of out-parameters */ GimpParam ** return_vals) /* out-parameters */ { const gchar *l_env; gint32 image_id = -1; gint32 drawable_id = -1; gint32 trans_drawable_id = -1; GapTransLayerMode trans_mode; trans_mode = GAP_TRANS_UNDEFINED; /* Get the runmode from the in-parameters */ GimpRunMode run_mode = param[0].data.d_int32; /* status variable, use it to check for errors in invocation usualy only during non-interactive calling */ GimpPDBStatusType status = GIMP_PDB_SUCCESS; /* always return at least the status to the caller. */ static GimpParam values[2]; INIT_I18N(); l_env = g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } if(gap_debug) printf("\n\nDEBUG: run %s\n", name); /* initialize the return of the status */ values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; values[1].type = GIMP_PDB_DRAWABLE; values[1].data.d_drawable = -1; *nreturn_vals = 1; *return_vals = values; /* get image and drawable */ image_id = param[1].data.d_int32; drawable_id = param[2].data.d_int32; if (strcmp (name, PLUG_IN_NAME_HOR) == 0) { trans_mode = GAP_TRANS_FLIP_HOR; } if (strcmp (name, PLUG_IN_NAME_VER) == 0) { trans_mode = GAP_TRANS_FLIP_VER; } if (strcmp (name, PLUG_IN_NAME_90) == 0) { trans_mode = GAP_TRANS_ROT_90; } if (strcmp (name, PLUG_IN_NAME_180) == 0) { trans_mode = GAP_TRANS_ROT_180; } if (strcmp (name, PLUG_IN_NAME_270) == 0) { trans_mode = GAP_TRANS_ROT_270; } if (strcmp (name, PLUG_IN_NAME_ANY) == 0) { trans_mode = GAP_TRANS_ROT_ANY; } if(trans_mode != GAP_TRANS_UNDEFINED) { if(gimp_drawable_is_layer(drawable_id)) { gboolean run_flag; /* Initial values */ glob_vals.angle_deg = 0; run_flag = TRUE; /* Possibly retrieve data from a previous run */ gimp_get_data (name, &glob_vals); switch (run_mode) { case GIMP_RUN_INTERACTIVE: /* Get information from the dialog */ run_flag = p_dialog(trans_mode, &glob_vals); break; case GIMP_RUN_NONINTERACTIVE: /* check to see if invoked with the correct number of parameters */ if (nparams >= 4) { glob_vals.angle_deg = param[3].data.d_float; } else { status = GIMP_PDB_CALLING_ERROR; } break; case GIMP_RUN_WITH_LAST_VALS: break; default: break; } /* here the action starts, we transform the drawable */ trans_drawable_id = p_transform_layer(image_id , drawable_id , trans_mode , &glob_vals ); if (trans_drawable_id < 0) { status = GIMP_PDB_CALLING_ERROR; } else { values[1].data.d_drawable = drawable_id; /* Store variable states for next run * (the parameters for the transform wrapper plugins are stored * even if they contain just a dummy * this is done to fullfill the GIMP-GAP LAST_VALUES conventions * for filtermacro and animated calls) */ if (run_mode == GIMP_RUN_INTERACTIVE) { gimp_set_data (name, &glob_vals, sizeof (TransValues)); } } } else { status = GIMP_PDB_CALLING_ERROR; if (run_mode == GIMP_RUN_INTERACTIVE) { g_message(_("The plug-in %s\noperates only on layers\n" "(but was called on mask or channel)") , name ); } } } if (status == GIMP_PDB_SUCCESS) { /* If run mode is interactive, flush displays, else (script) don't * do it, as the screen updates would make the scripts slow */ if (run_mode != GIMP_RUN_NONINTERACTIVE) gimp_displays_flush (); } values[0].data.d_status = status; } /* end run */ /* -------------------------- * p_transform_layer * -------------------------- */ static gint32 p_transform_layer(gint32 image_id, gint32 drawable_id, GapTransLayerMode trans_mode, TransValues *val_ptr) { gboolean auto_center; gboolean clip_result; gdouble axis; gboolean has_selection; gboolean non_empty; gint x1, y1, x2, y2; gint32 sav_selection_id; gint32 trans_drawable_id; gint32 center_x; gint32 center_y; gimp_image_undo_group_start(image_id); sav_selection_id = -1; has_selection = gimp_selection_bounds(image_id, &non_empty, &x1, &y1, &x2, &y2); center_x = gimp_drawable_width(drawable_id) / 2; center_y = gimp_drawable_height(drawable_id) / 2; if(non_empty) { sav_selection_id = gimp_selection_save(image_id); } trans_drawable_id = -1; auto_center = TRUE; clip_result = TRUE; /* here the action starts, we transform the drawable */ switch(trans_mode) { case GAP_TRANS_FLIP_HOR: clip_result = TRUE; axis = (gdouble)(gimp_drawable_width(drawable_id)) / 2.0; trans_drawable_id = gimp_drawable_transform_flip_simple(drawable_id ,GIMP_ORIENTATION_HORIZONTAL ,auto_center ,axis ,clip_result ); break; case GAP_TRANS_FLIP_VER: clip_result = TRUE; axis = (gdouble)(gimp_drawable_height(drawable_id)) / 2.0; trans_drawable_id = gimp_drawable_transform_flip_simple(drawable_id ,GIMP_ORIENTATION_VERTICAL ,auto_center ,axis ,clip_result ); break; case GAP_TRANS_ROT_90: clip_result = FALSE; trans_drawable_id = gimp_drawable_transform_rotate_simple(drawable_id ,GIMP_ROTATE_90 ,auto_center ,center_x ,center_y ,clip_result ); break; case GAP_TRANS_ROT_180: clip_result = FALSE; trans_drawable_id = gimp_drawable_transform_rotate_simple(drawable_id ,GIMP_ROTATE_180 ,auto_center ,center_x ,center_y ,clip_result ); break; case GAP_TRANS_ROT_270: clip_result = FALSE; trans_drawable_id = gimp_drawable_transform_rotate_simple(drawable_id ,GIMP_ROTATE_270 ,auto_center ,center_x ,center_y ,clip_result ); break; case GAP_TRANS_ROT_ANY: { gdouble l_angle_rad; clip_result = FALSE; l_angle_rad = (val_ptr->angle_deg * G_PI) / 180.0; trans_drawable_id = gimp_drawable_transform_rotate_default(drawable_id , l_angle_rad , FALSE /* auto_center */ , center_x , center_y , TRUE /* interpolation (TRUE use default interpolation) */ , clip_result ); } /* end gap_pdb_gimp_rotate_degree */ break; default: break; } if((non_empty) && (sav_selection_id >= 0)) { /* if there was a selection, the transform (flip or simple rotate) operation * is restricted to the selected region. in this case * the treansform has created a new drawable as floating selection. * * we automatically anchor the floating selection and restore the orginal selection, * because our plug-in is typically called more than once * in non-interactive sequence on all layers of the same image * * this would not work for the 2.nd call if the 1.st call produces a floating selection. */ gimp_floating_sel_anchor (gimp_image_get_floating_sel (image_id)); gimp_selection_load(sav_selection_id); gimp_image_remove_channel(image_id, sav_selection_id); //gimp_drawable_delete(sav_selection_id); } gimp_image_undo_group_end(image_id); return (trans_drawable_id); } /* end p_transform_layer */ /* -------------------------- * p_dialog * -------------------------- */ static gboolean p_dialog (GapTransLayerMode trans_mode, TransValues *val_ptr) { GtkWidget *dialog; GtkWidget *main_vbox; GtkWidget *preview; GtkWidget *table; GtkObject *adj; gboolean run; if(trans_mode != GAP_TRANS_ROT_ANY) { /* all other modes have no dialog and shall run immediate when invoked */ return (TRUE); } gimp_ui_init (PLUG_IN_BINARY, TRUE); dialog = gimp_dialog_new (_("Rotate any angle"), PLUG_IN_BINARY, NULL, 0, gimp_standard_help_func, PLUG_IN_NAME_ANY, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); gimp_window_set_transient (GTK_WINDOW (dialog)); main_vbox = gtk_vbox_new (FALSE, 12); gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12); gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox); gtk_widget_show (main_vbox); /* Controls */ table = gtk_table_new (3, 3, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 6); gtk_table_set_row_spacings (GTK_TABLE (table), 6); gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0); gtk_widget_show (table); adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0, _("Rotate angle:"), SCALE_WIDTH, 7, val_ptr->angle_deg, -3600.0, 3600.0, 1.0, 15.0, 2, TRUE, 0, 0, NULL, NULL); g_signal_connect (adj, "value-changed", G_CALLBACK (gimp_double_adjustment_update), &val_ptr->angle_deg); /* Done */ gtk_widget_show (dialog); run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK); gtk_widget_destroy (dialog); return run; } /* end p_dialog */ gimp-gap-2.6.0+dfsg.orig/gap/gap_vex_dialog.c0000644000175000017500000027277211212030253020651 0ustar thibautthibaut/* * gap_vex_dialog.c * A GIMP / GAP Plugin to extract frames and/or audio from Videofiles * * This is a special kind of File Load Plugin, * based on gap_vid_api (GVA) (an API to read various Videoformats/CODECS) */ /* * Changelog: * 2004/04/10 v2.1.0: integrated sourcecode into gimp-gap project */ /* * Copyright * * 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 #include #include #include #include #include #include #include "gap_vex_main.h" #include "gap_vex_dialog.h" #include "gap_lib_common_defs.h" #include "gap-intl.h" /* GAP_ENABLE_VIDEOAPI_SUPPORT (1) */ #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT #define ENC_MENU_ITEM_INDEX_KEY "gap_enc_menu_item_index" #define GAP_VEX_PLAYER_HELP_ID "plug-in-gap-extract-player" #define SPIN_WIDTH_SMALL 40 #define SPIN_WIDTH_LARGE 80 #define ENTRY_WIDTH_LARGE 320 #define TIME_UNDEF_STRING "mm:ss:msec" /* -------- GUI TOOL PROCEDURES -----------*/ static const char *p_timeconv_framenr_to_timestr_fps( gint32 framenr, gdouble framerate); static void p_update_time_labels (GapVexMainGlobalParams *gpp); static void p_update_range_widgets(GapVexMainGlobalParams *gpp); static void p_update_wgt_sensitivity(GapVexMainGlobalParams *gpp); static void p_init_mw__main_window_widgets (GapVexMainGlobalParams *gpp); static void p_call_player_widget(GapVexMainGlobalParams *gpp , char *imagename , gint32 imagewidth , gint32 imageheight , gint32 begin_frame , gint32 end_frame , gint32 seltrack , gdouble delace , gboolean docked_mode ); static void p_vex_set_range_cb(GapPlayerAddClip *plac_ptr); static void p_check_videofile(GapVexMainGlobalParams *gpp); /* -------- GUI CALLBACK PROCEDURES -----------*/ static void on_mw_response (GtkWidget *widget, gint response_id, GapVexMainGlobalParams *gpp); static void on_mw__combo_preferred_decoder (GtkWidget *widget, GapVexMainGlobalParams *gpp); static void on_mw__combo_deinterlace (GtkWidget *widget, GapVexMainGlobalParams *gpp); static void on_mw__checkbutton_bluebox_toggled (GtkToggleButton *togglebutton, GapVexMainGlobalParams *gpp); static void on_mw__checkbutton_disable_mmx_toggled (GtkToggleButton *togglebutton, GapVexMainGlobalParams *gpp); static void on_mw__spinbutton_begin_frame_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp); static void on_mw__spinbutton_end_frame_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp); static void on_mw__spinbutton_videotrack_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp); static void on_mw__spinbutton_audiotrack_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp); static void on_mw__entry_video_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp); static void on_mw__button_video_clicked (GtkButton *button, GapVexMainGlobalParams *gpp); static void on_mw__entry_basename_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp); static void on_mw__button_basename_clicked (GtkButton *button, GapVexMainGlobalParams *gpp); static void on_mw__entry_extension_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp); static void on_mw__spinbutton_basenum_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp); static void on_mw__entry_audiofile_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp); static void on_mw__button_audiofile_clicked (GtkButton *button, GapVexMainGlobalParams *gpp); static void on_mw__checkbutton_multilayer_toggled (GtkToggleButton *togglebutton, GapVexMainGlobalParams *gpp); static void on_mw__button_vrange_dialog_clicked (GtkButton *button, GdkEventButton *bevent, GapVexMainGlobalParams *gpp); static void on_mw__button_vrange_docked_clicked (GtkButton *button, GapVexMainGlobalParams *gpp); static void on_mw__entry_preferred_decoder_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp); static void on_mw__checkbutton_exact_seek_toggled (GtkToggleButton *togglebutton, GapVexMainGlobalParams *gpp); static void on_mw__spinbutton_delace_threshold_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp); static void on_mw__spinbutton_fn_digits_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp); static void on_fsv__fileselection_destroy (GtkObject *object, GapVexMainGlobalParams *gpp); static void on_fsv__button_OK_clicked (GtkButton *button, GapVexMainGlobalParams *gpp); static void on_fsv__button_cancel_clicked (GtkButton *button, GapVexMainGlobalParams *gpp); static void on_fsb__fileselection_destroy (GtkObject *object, GapVexMainGlobalParams *gpp); static void on_fsb__button_OK_clicked (GtkButton *button, GapVexMainGlobalParams *gpp); static void on_fsb__button_cancel_clicked (GtkButton *button, GapVexMainGlobalParams *gpp); static void on_fsa__fileselection_destroy (GtkObject *object, GapVexMainGlobalParams *gpp); static void on_fsa__button_OK_clicked (GtkButton *button, GapVexMainGlobalParams *gpp); static void on_fsa__button_cancel_clicked (GtkButton *button, GapVexMainGlobalParams *gpp); /* -------- GUI DIALOG Creationg PROCEDURES -----------*/ static GtkWidget* create_fsv__fileselection (GapVexMainGlobalParams *gpp); static GtkWidget* create_fsb__fileselection (GapVexMainGlobalParams *gpp); static GtkWidget* create_fsa__fileselection (GapVexMainGlobalParams *gpp); /* PUBLIC: gap_vex_dlg_create_mw__main_window */ /* ------------------------ * gap_vex_dlg_init_gpp * ------------------------ */ void gap_vex_dlg_init_gpp (GapVexMainGlobalParams *gpp) { if(gap_debug) printf("INIT: init_global params\n"); /* set initial values in val */ g_snprintf(gpp->val.videoname, sizeof(gpp->val.videoname), "TEST.MPG"); g_snprintf(gpp->val.basename, sizeof(gpp->val.basename), "frame_"); g_snprintf(gpp->val.extension, sizeof(gpp->val.extension), ".xcf"); g_snprintf(gpp->val.audiofile, sizeof(gpp->val.audiofile), "frame.wav"); gpp->val.basenum = 0; gpp->val.fn_digits = GAP_LIB_DEFAULT_DIGITS; gpp->val.preferred_decoder[0] = '\0'; gpp->val.deinterlace = 0; gpp->val.delace_threshold = 1.0; gpp->val.exact_seek = 0; gpp->val.begin_frame = 1.0; gpp->val.end_frame = 1.0; gpp->val.videotrack = 1; gpp->val.audiotrack = 1; gpp->val.multilayer = 0; gpp->val.disable_mmx = 0; gpp->val.pos_unit = 0; /* unit FRAMES */ gpp->plp = NULL; gpp->in_player_call = FALSE; gpp->video_width = 320; gpp->video_height = 200; gpp->val.image_ID = -1; } /* end gap_vex_dlg_init_gpp */ /* ---------------------------- * gap_vex_dlg_overwrite_dialog * ---------------------------- * check if filename already exists. * if file exists and we are running interactive * Ask the user what to do in an overwrite dialog window. * in non interactive runmode the parameter overwrite_mode * is used for overwrite permission. * * return -1 overwrite is NOT allowed, calling program should skip write (and exit) * 0 OVERWRITE permission for one file * 1 OVERWRITE permission for all files */ gint gap_vex_dlg_overwrite_dialog(GapVexMainGlobalParams *gpp, gchar *filename, gint overwrite_mode) { static GapArrButtonArg l_argv[3]; static GapArrArg argv[1]; if(gap_lib_file_exists(filename)) if(g_file_test(filename, G_FILE_TEST_EXISTS)) { if (overwrite_mode < 1) { gchar *msg; gint l_rc; l_argv[0].but_txt = _("Overwrite File"); l_argv[0].but_val = 0; l_argv[1].but_txt = _("Overwrite All"); l_argv[1].but_val = 1; l_argv[2].but_txt = GTK_STOCK_CANCEL; l_argv[2].but_val = -1; gap_arr_arg_init(&argv[0], GAP_ARR_WGT_LABEL); argv[0].label_txt = filename; msg = g_strdup_printf(_("File: %s already exists"), filename); l_rc = gap_arr_std_dialog ( _("Overwrite") , msg , 1, argv , 3, l_argv , -1 ); g_free(msg); return(l_rc); } } return (overwrite_mode); } /* end gap_vex_dlg_overwrite_dialog */ /* --------------------------------- * p_timeconv_framenr_to_timestr_fps * --------------------------------- * return constant string with converted time and framerate information * Do not attemt to free the returned string. (it refers to a static constant buffer) */ static const char * p_timeconv_framenr_to_timestr_fps( gint32 framenr, gdouble framerate) { static char txt_buf[100]; gint len; gap_timeconv_framenr_to_timestr( framenr , framerate , txt_buf , sizeof(txt_buf) ); len = strlen(txt_buf); g_snprintf(&txt_buf[len], sizeof(txt_buf) - len, " @ %2.3f fps", (float)framerate); return (txt_buf); } /* end p_timeconv_framenr_to_timestr_fps */ /* -------------------------------- * p_update_time_labels * -------------------------------- */ static void p_update_time_labels (GapVexMainGlobalParams *gpp) { if(gpp == NULL) return; if(!gpp->val.chk_is_compatible_videofile) { gtk_label_set_text ( GTK_LABEL(gpp->mw__begin_time_label), TIME_UNDEF_STRING); gtk_label_set_text ( GTK_LABEL(gpp->mw__end_time_label), TIME_UNDEF_STRING); return; } gtk_label_set_text ( GTK_LABEL(gpp->mw__begin_time_label) , p_timeconv_framenr_to_timestr_fps((gint32)(gpp->val.begin_frame -1) ,(gdouble)gpp->video_speed ) ); gtk_label_set_text ( GTK_LABEL(gpp->mw__end_time_label) , p_timeconv_framenr_to_timestr_fps((gint32)(gpp->val.end_frame -1) ,(gdouble)gpp->video_speed ) ); } /* end p_update_time_labels */ /* ------------------------ * p_update_range_widgets * ------------------------ */ static void p_update_range_widgets(GapVexMainGlobalParams *gpp) { GtkAdjustment *adj; adj = GTK_ADJUSTMENT(gpp->mw__spinbutton_begin_frame_adj); gtk_adjustment_set_value(adj, (gfloat)gpp->val.begin_frame); adj = GTK_ADJUSTMENT(gpp->mw__spinbutton_end_frame_adj); gtk_adjustment_set_value(adj, (gfloat)gpp->val.end_frame); p_update_time_labels(gpp); } /* end p_update_range_widgets */ /* ------------------------ * p_update_wgt_sensitivity * ------------------------ */ static void p_update_wgt_sensitivity(GapVexMainGlobalParams *gpp) { gboolean sensitive; gboolean sensitive_vid; if(gap_debug) printf("p_update_wgt_sensitivity : START\n"); if(gap_debug) printf(" chk_is_compatible_videofile :%d\n", (int)gpp->val.chk_is_compatible_videofile); if(gap_debug) printf(" chk_vtracks :%d\n", (int)gpp->val.chk_vtracks); if(gap_debug) printf(" chk_atracks :%d\n", (int)gpp->val.chk_atracks); if(gap_debug) printf(" videotrack :%d\n", (int)gpp->val.videotrack); if((gpp->val.chk_is_compatible_videofile) && ((gpp->val.videotrack > 0) || (gpp->val.audiotrack > 0)) ) { sensitive = TRUE; } else { sensitive = FALSE; } if(gpp->mw__button_OK) { gtk_widget_set_sensitive(gpp->mw__button_OK, sensitive); } if(gpp->val.chk_is_compatible_videofile) { sensitive = TRUE; } else { sensitive = FALSE; } gtk_widget_set_sensitive(gpp->mw__spinbutton_begin_frame, sensitive); gtk_widget_set_sensitive(gpp->mw__spinbutton_end_frame, sensitive); gtk_widget_set_sensitive(gpp->mw__button_vrange_dialog, sensitive); gtk_widget_set_sensitive(gpp->mw__button_vrange_docked, sensitive); gtk_widget_set_sensitive(gpp->mw__spinbutton_videotrack, sensitive); gtk_widget_set_sensitive(gpp->mw__spinbutton_audiotrack, sensitive); if((gpp->val.videotrack > 0) && (gpp->val.chk_vtracks > 0) && (gpp->val.chk_is_compatible_videofile)) { sensitive = TRUE; } else { sensitive = FALSE; } sensitive_vid = sensitive; gtk_widget_set_sensitive(gpp->mw__spinbutton_basenum, sensitive); gtk_widget_set_sensitive(gpp->mw__combo_deinterlace, sensitive); gtk_widget_set_sensitive(gpp->mw__checkbutton_multilayer, sensitive); gtk_widget_set_sensitive(gpp->mw__checkbutton_generate_alpha_via_bluebox, sensitive); if(gpp->val.generate_alpha_via_bluebox != TRUE) { sensitive = FALSE; } gtk_widget_set_sensitive(gpp->mw__checkbutton_extract_alpha_as_gray_frames, sensitive); gtk_widget_set_sensitive(gpp->mw__checkbutton_extract_with_layermask, sensitive); if((gpp->val.multilayer == 0) && (sensitive_vid)) { sensitive = TRUE; /* we want to extract to frame files on disc */ } else { sensitive = FALSE; /* we want to extract to one multilayer image */ } gtk_widget_set_sensitive(gpp->mw__entry_basename, sensitive); gtk_widget_set_sensitive(gpp->mw__button_basename, sensitive); gtk_widget_set_sensitive(gpp->mw__spinbutton_fn_digits, sensitive); gtk_widget_set_sensitive(gpp->mw__entry_extension, sensitive); if((gpp->val.audiotrack > 0) && (gpp->val.chk_atracks > 0) && (gpp->val.chk_is_compatible_videofile)) { sensitive = TRUE; } else { sensitive = FALSE; } gtk_widget_set_sensitive(gpp->mw__entry_audiofile, sensitive); gtk_widget_set_sensitive(gpp->mw__button_audiofile, sensitive); if((gpp->val.deinterlace != 0) && (sensitive_vid)) { sensitive = TRUE; } else { sensitive = FALSE; } gtk_widget_set_sensitive(gpp->mw__spinbutton_delace_threshold, sensitive); p_update_range_widgets(gpp); } /* end p_update_wgt_sensitivity */ /* ------------------------------ * p_init_mw__main_window_widgets * ------------------------------ */ static void p_init_mw__main_window_widgets (GapVexMainGlobalParams *gpp) { GtkWidget *wgt; GtkAdjustment *adj; GtkEntry *entry; if(gap_debug) printf("INIT: init_mw__main_window_widgets\n"); /* put initial values to the widgets */ adj = GTK_ADJUSTMENT(gpp->mw__spinbutton_videotrack_adj); gtk_adjustment_set_value(adj, (gfloat)gpp->val.videotrack); adj = GTK_ADJUSTMENT(gpp->mw__spinbutton_audiotrack_adj); gtk_adjustment_set_value(adj, (gfloat)gpp->val.audiotrack); adj = GTK_ADJUSTMENT(gpp->mw__spinbutton_basenum_adj); gtk_adjustment_set_value(adj, (gfloat)gpp->val.basenum); adj = GTK_ADJUSTMENT(gpp->mw__spinbutton_fn_digits_adj); gtk_adjustment_set_value(adj, (gfloat)gpp->val.fn_digits); adj = GTK_ADJUSTMENT(gpp->mw__spinbutton_delace_threshold_adj); gtk_adjustment_set_value(adj, (gfloat)gpp->val.delace_threshold); entry = GTK_ENTRY(gpp->mw__entry_video); gtk_entry_set_text(entry, gpp->val.videoname); entry = GTK_ENTRY(gpp->mw__entry_basename); gtk_entry_set_text(entry, gpp->val.basename); entry = GTK_ENTRY(gpp->mw__entry_extension); gtk_entry_set_text(entry, gpp->val.extension); entry = GTK_ENTRY(gpp->mw__entry_audiofile); gtk_entry_set_text(entry, gpp->val.audiofile); entry = GTK_ENTRY(gpp->mw__entry_preferred_decoder); gtk_entry_set_text(entry, gpp->val.preferred_decoder); wgt = gpp->mw__checkbutton_multilayer; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wgt), gpp->val.multilayer ); wgt = gpp->mw__checkbutton_disable_mmx; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wgt), gpp->val.disable_mmx ); wgt = gpp->mw__checkbutton_exact_seek; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wgt), gpp->val.exact_seek ); p_update_range_widgets(gpp); p_update_wgt_sensitivity(gpp); } /* end p_init_mw__main_window_widgets */ /* ----------------------------- * p_vex_set_range_cb * ----------------------------- * Player Callback procedure * to set range widgets */ static void p_vex_set_range_cb(GapPlayerAddClip *plac_ptr) { GapVexMainGlobalParams *gpp; gpp = (GapVexMainGlobalParams *)plac_ptr->user_data_ptr; if(gap_debug) { printf("p_vex_set_range_cb:\n"); printf(" FROM : %d\n", (int)plac_ptr->range_from); printf(" TO : %d\n", (int)plac_ptr->range_to); } if(gpp == NULL) { return; } gpp->val.begin_frame = MIN(plac_ptr->range_from, plac_ptr->range_to); gpp->val.end_frame = MAX(plac_ptr->range_from, plac_ptr->range_to); p_update_range_widgets(gpp); } /* end p_vex_set_range_cb */ /* ----------------------------- * p_call_player_widget * ----------------------------- * IN: imagename of one frame to playback in normal mode (or the name of a videofile) * * IN: begin_frame use -1 to start play from 1.st frame * IN: end_frame use -1 to start play until last frame * * Call the Player * If it is the 1.st call or the player window has closed since last call * create the player widget * else * reset the player widget */ static void p_call_player_widget(GapVexMainGlobalParams *gpp , char *imagename , gint32 imagewidth , gint32 imageheight , gint32 begin_frame , gint32 end_frame , gint32 seltrack , gdouble delace , gboolean docked_mode ) { if(gpp->in_player_call) { /* this procedure is already active, and locked against * calls while busy */ return; } gpp->in_player_call = TRUE; if(gpp->plp) { if(gpp->plp->shell_window != NULL) { gtk_window_present(GTK_WINDOW(gpp->plp->shell_window)); } if((gpp->plp->shell_window == NULL) && (gpp->plp->docking_container == NULL)) { if(gap_debug) printf("Player shell has gone, force Reopen now\n"); gap_player_dlg_cleanup(gpp->plp); g_free(gpp->plp); gpp->plp = NULL; } } if(gpp->plp == NULL) { /* 1. START mode */ gpp->plp = (GapPlayerMainGlobalParams *)g_malloc0(sizeof(GapPlayerMainGlobalParams)); if(gpp->plp) { gpp->plp->standalone_mode = FALSE; /* player acts as widget and does not call gtk_main_quit */ gpp->plp->help_id = NULL; if(docked_mode) { gtk_widget_show(gpp->mw__player_frame); gpp->plp->docking_container = gpp->mw__player_frame; /* player is docked */ } else { gpp->plp->docking_container = NULL; /* player has own window (not docked) */ gpp->plp->help_id = GAP_VEX_PLAYER_HELP_ID; } gpp->plp->autostart = FALSE; gpp->plp->caller_range_linked = TRUE; gpp->plp->use_thumbnails = FALSE; gpp->plp->exact_timing = FALSE; gpp->plp->play_selection_only = FALSE; gpp->plp->play_loop = FALSE; gpp->plp->play_pingpong = FALSE; gpp->plp->play_backward = FALSE; gpp->plp->stb_ptr = NULL; gpp->plp->image_id = -1; /* have no image_id, operate on videofile */ gpp->plp->imagename = NULL; if(imagename) { gpp->plp->imagename = g_strdup(imagename); } gpp->plp->imagewidth = imagewidth; gpp->plp->imageheight = imageheight; gpp->plp->aspect_ratio = GAP_PLAYER_DONT_FORCE_ASPECT; gpp->plp->play_current_framenr = 0; gpp->plp->begin_frame = begin_frame; gpp->plp->end_frame = end_frame; gpp->plp->fptr_set_range = p_vex_set_range_cb; gpp->plp->user_data_ptr = gpp; gpp->plp->seltrack = seltrack; gpp->plp->delace = delace; gpp->plp->preferred_decoder = g_strdup(gpp->val.preferred_decoder); gpp->plp->force_open_as_video = TRUE; /* TRUE: try video open even for unknown videofile extensions */ gpp->plp->have_progress_bar = TRUE; gap_player_dlg_create(gpp->plp); } } else { /* RESTART mode */ gap_player_dlg_restart(gpp->plp , FALSE /* gboolean autostart */ , -1 /* have no image_id, operate on videofile */ , imagename , imagewidth , imageheight , NULL /* have no storyboard */ , begin_frame , end_frame , FALSE /* gboolean play_selection_only */ , seltrack , delace , gpp->val.preferred_decoder , TRUE /* force_open_as_video */ , GAP_STB_FLIP_NONE /* flip_request */ , GAP_STB_FLIP_NONE /* flip_status */ , 1 /* stb_in_track */ ); } if(gpp->plp) { if((gpp->plp->from_button) && (gpp->plp->to_button)) { gimp_help_set_help_data (gpp->plp->from_button , _("Set range to extract") , NULL); gimp_help_set_help_data (gpp->plp->to_button , _("Set range to extract") , NULL); } } gpp->in_player_call = FALSE; } /* end p_call_player_widget */ /* ------------------- * p_check_aspect * ------------------- */ gboolean p_check_aspect(gdouble aspect_ratio, gint width, gint height) { gdouble w_div_h; if(height) { w_div_h = (gdouble)width / (gdouble)height; if ((aspect_ratio <= w_div_h + 0.001) && (aspect_ratio >= w_div_h - 0.001)) { return(TRUE); } } return (FALSE); } /* end p_check_aspect */ /* ------------------- * p_check_videofile * ------------------- * check videofile compatibility * and get some information about the file */ static void p_check_videofile(GapVexMainGlobalParams *gpp) { t_GVA_Handle *gvahand; GtkLabel *lbl; char *active_decoder; gdouble aspect_ratio; gpp->val.chk_is_compatible_videofile = FALSE; gpp->val.chk_vtracks = 0; gpp->val.chk_atracks = 0; gpp->val.chk_total_frames = 0; aspect_ratio = 0; active_decoder = NULL; if(g_file_test(gpp->val.videoname, G_FILE_TEST_EXISTS)) { if(gap_debug) printf("p_check_videofile: %s vid_track:%d aud_track:%d\n", gpp->val.videoname, (int)gpp->val.videotrack, (int)gpp->val.audiotrack ); gvahand = GVA_open_read_pref(gpp->val.videoname ,gpp->val.videotrack ,gpp->val.audiotrack ,gpp->val.preferred_decoder , FALSE /* use MMX if available (disable_mmx == FALSE) */ ); if(gvahand) { gpp->val.chk_is_compatible_videofile = TRUE; gpp->val.chk_vtracks = gvahand->vtracks; gpp->val.chk_atracks = gvahand->atracks; gpp->val.chk_total_frames = gvahand->total_frames; gpp->video_width = gvahand->width; gpp->video_height = gvahand->height; gpp->video_speed = gvahand->framerate; aspect_ratio = gvahand->aspect_ratio; if(gvahand->dec_elem) { t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)gvahand->dec_elem; if(dec_elem->decoder_name) { active_decoder = g_strdup(dec_elem->decoder_name); } /* if(dec_elem->decoder_description) */ } GVA_close(gvahand); } } /* update label aspect ratio */ lbl = GTK_LABEL(gpp->mw__label_aspect_ratio); if(aspect_ratio != 0.0) { char ratio_txt[20]; char ratio2_txt[20]; ratio2_txt[0] = '\0'; if(p_check_aspect(aspect_ratio, 3, 2)) { g_snprintf(ratio2_txt, sizeof(ratio2_txt), " (3:2)"); } if(p_check_aspect(aspect_ratio, 4, 3)) { g_snprintf(ratio2_txt, sizeof(ratio2_txt), " (4:3)"); } if(p_check_aspect(aspect_ratio, 16, 9)) { g_snprintf(ratio2_txt, sizeof(ratio2_txt), " (16:9)"); } g_snprintf(ratio_txt, sizeof(ratio_txt) , "%0.5f%s" , (float)aspect_ratio , ratio2_txt ); gtk_label_set_text(lbl, ratio_txt); } else { gtk_label_set_text(lbl, _("unknown") ); } /* update label active decoder */ lbl = GTK_LABEL(gpp->mw__label_active_decoder); if(active_decoder) { gtk_label_set_text(lbl, active_decoder); g_free(active_decoder); active_decoder = NULL; } else { gtk_label_set_text(lbl, "*******"); } p_update_wgt_sensitivity(gpp); } /* end p_check_videofile */ /* --------------------------------- * on_mw_response * --------------------------------- */ static void on_mw_response (GtkWidget *widget, gint response_id, GapVexMainGlobalParams *gpp) { GtkWidget *dialog; if(gpp) { gpp->val.run = FALSE; } switch (response_id) { case GTK_RESPONSE_OK: if(gpp) { gpp->val.run = TRUE; } default: dialog = NULL; if(gpp) { dialog = gpp->mw__main_window; if(dialog) { gpp->mw__main_window = NULL; gtk_widget_destroy (dialog); } } gtk_main_quit (); break; } } /* end on_mw_response */ /* ----------------------------------- * on_mw__combo_preferred_decoder * ----------------------------------- */ static void on_mw__combo_preferred_decoder (GtkWidget *widget, GapVexMainGlobalParams *gpp) { GtkEntry *entry; gint l_idx; gint value; const char *preferred_decoder; if(gap_debug) printf("CB: on_mw__combo_preferred_decoder\n"); if(gpp == NULL) return; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value); l_idx = value; preferred_decoder = "\0"; if(gap_debug) printf("CB: on_mw__combo_preferred_decoder index: %d\n", (int)l_idx); switch(l_idx) { case GAP_VEX_DECODER_NONE: preferred_decoder = "\0"; break; case GAP_VEX_DECODER_LIBMPEG3: preferred_decoder = "libmpeg3"; break; case GAP_VEX_DECODER_QUICKTIME: preferred_decoder = "quicktime4linux"; break; case GAP_VEX_DECODER_LIBAVFORMAT: preferred_decoder = "libavformat"; break; } g_snprintf(gpp->val.preferred_decoder, sizeof(gpp->val.preferred_decoder) , preferred_decoder ); entry = GTK_ENTRY(gpp->mw__entry_preferred_decoder); if(entry) { gtk_entry_set_text(entry, preferred_decoder); } } /* end on_mw__combo_preferred_decoder */ /* ------------------------------ * on_mw__combo_deinterlace * ------------------------------ */ static void on_mw__combo_deinterlace (GtkWidget *widget, GapVexMainGlobalParams *gpp) { gint l_idx; gint value; gboolean sensitive; if(gap_debug) printf("CB: on_mw__combo_deinterlace\n"); if(gpp == NULL) return; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value); l_idx = value; if(gap_debug) printf("CB: on_mw__combo_deinterlace index: %d\n", (int)l_idx); gpp->val.deinterlace = l_idx; if(gpp->val.deinterlace != 0) { sensitive = TRUE; } else { sensitive = FALSE; } if(gpp->mw__spinbutton_delace_threshold) { gtk_widget_set_sensitive(gpp->mw__spinbutton_delace_threshold, sensitive); } } /* end on_mw__combo_deinterlace */ /* -------------------------------- * on_mw__checkbutton_bluebox_toggled * -------------------------------- */ static void on_mw__checkbutton_bluebox_toggled (GtkToggleButton *togglebutton, GapVexMainGlobalParams *gpp) { GtkWidget *wgt; if(gap_debug) printf("CB: on_mw__checkbutton_bluebox_toggled\n"); if(gpp == NULL) return; wgt = gpp->mw__checkbutton_generate_alpha_via_bluebox; if (GTK_TOGGLE_BUTTON (wgt)->active) { gpp->val.generate_alpha_via_bluebox = TRUE; } else { gpp->val.generate_alpha_via_bluebox = FALSE; } p_update_wgt_sensitivity(gpp); } /* -------------------------------- * on_mw__checkbutton_graymask_toggled * -------------------------------- */ static void on_mw__checkbutton_graymask_toggled (GtkToggleButton *togglebutton, GapVexMainGlobalParams *gpp) { GtkWidget *wgt; if(gap_debug) printf("CB: on_mw__checkbutton_graymask_toggled\n"); if(gpp == NULL) return; wgt = gpp->mw__checkbutton_extract_alpha_as_gray_frames; if (GTK_TOGGLE_BUTTON (wgt)->active) { gpp->val.extract_alpha_as_gray_frames = TRUE; } else { gpp->val.extract_alpha_as_gray_frames = FALSE; } } /* -------------------------------- * on_mw__checkbutton_layermask_toggled * -------------------------------- */ static void on_mw__checkbutton_layermask_toggled (GtkToggleButton *togglebutton, GapVexMainGlobalParams *gpp) { GtkWidget *wgt; if(gap_debug) printf("CB: on_mw__checkbutton_layermask_toggled\n"); if(gpp == NULL) return; wgt = gpp->mw__checkbutton_extract_with_layermask; if (GTK_TOGGLE_BUTTON (wgt)->active) { gpp->val.extract_with_layermask = TRUE; } else { gpp->val.extract_with_layermask = FALSE; } } /* -------------------------------- * on_mw__checkbutton_disable_mmx_toggled * -------------------------------- */ static void on_mw__checkbutton_disable_mmx_toggled (GtkToggleButton *togglebutton, GapVexMainGlobalParams *gpp) { GtkWidget *wgt; if(gap_debug) printf("CB: on_mw__checkbutton_disable_mmx_toggled\n"); if(gpp == NULL) return; wgt = gpp->mw__checkbutton_disable_mmx; if (GTK_TOGGLE_BUTTON (wgt)->active) { gpp->val.disable_mmx = TRUE; } else { gpp->val.disable_mmx = FALSE; } } /* -------------------------------- * on_mw__spinbutton_begin_frame_changed * -------------------------------- */ static void on_mw__spinbutton_begin_frame_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp) { GtkAdjustment *adj; if(gap_debug) printf("CB: on_mw__spinbutton_begin_frame_changed\n"); if(gpp == NULL) return; adj = GTK_ADJUSTMENT(gpp->mw__spinbutton_begin_frame_adj); if(gap_debug) printf("spin value: %f\n", (float)adj->value ); if((gdouble)adj->value != gpp->val.begin_frame) { gpp->val.begin_frame = (gdouble)adj->value; p_update_time_labels(gpp); } } /* -------------------------------- * on_mw__spinbutton_end_frame_changed * -------------------------------- */ static void on_mw__spinbutton_end_frame_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp) { GtkAdjustment *adj; if(gap_debug) printf("CB: on_mw__spinbutton_end_frame_changed\n"); if(gpp == NULL) return; adj = GTK_ADJUSTMENT(gpp->mw__spinbutton_end_frame_adj); if(gap_debug) printf("spin value: %f\n", (float)adj->value ); if((gdouble)adj->value != gpp->val.end_frame) { gpp->val.end_frame = (gdouble)adj->value; p_update_time_labels(gpp); } } /* ------------------------------------ * on_mw__spinbutton_videotrack_changed * ------------------------------------ */ static void on_mw__spinbutton_videotrack_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp) { GtkAdjustment *adj; if(gap_debug) printf("CB: on_mw__spinbutton_videotrack_changed\n"); if(gpp == NULL) return; if(gpp->mw__spinbutton_videotrack_adj) { adj = GTK_ADJUSTMENT(gpp->mw__spinbutton_videotrack_adj); if(gap_debug) printf("videotrack spin value: %f\n", (float)adj->value ); if((gint)adj->value != gpp->val.videotrack) { gpp->val.videotrack = (gint)adj->value; if((gpp->val.chk_is_compatible_videofile == TRUE) &&(gpp->val.videotrack > gpp->val.chk_vtracks)) { /* if we have a valid videofile constraint videotracks to available tracks */ gtk_adjustment_set_value(adj, (gfloat)gpp->val.chk_vtracks ); } p_update_wgt_sensitivity(gpp); } } } /* -------------------------------- * on_mw__spinbutton_audiotrack_changed * -------------------------------- */ static void on_mw__spinbutton_audiotrack_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp) { GtkAdjustment *adj; if(gap_debug) printf("CB: on_mw__spinbutton_audiotrack_changed\n"); if(gpp == NULL) return; if(gpp->mw__spinbutton_audiotrack_adj) { adj = GTK_ADJUSTMENT(gpp->mw__spinbutton_audiotrack_adj); if(gap_debug) printf("audiotrack spin value: %f\n", (float)adj->value ); if((gint)adj->value != gpp->val.audiotrack) { gpp->val.audiotrack = (gint)adj->value; if((gpp->val.chk_is_compatible_videofile == TRUE) &&(gpp->val.audiotrack > gpp->val.chk_atracks)) { /* if we have a valid videofile constraint audiotracks to available tracks */ gtk_adjustment_set_value(adj, (gfloat)gpp->val.chk_atracks ); } p_update_wgt_sensitivity(gpp); } } } /* -------------------------------- * on_mw__entry_video_changed * -------------------------------- */ static void on_mw__entry_video_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp) { if(gap_debug) printf("CB: on_mw__entry_video_changed\n"); if(gpp == NULL) return; if(gpp->mw__entry_video) { g_snprintf(gpp->val.videoname, sizeof(gpp->val.videoname), "%s" , gtk_entry_get_text(GTK_ENTRY(gpp->mw__entry_video))); p_check_videofile(gpp); } } /* -------------------------------- * on_mw__button_video_clicked * -------------------------------- */ static void on_mw__button_video_clicked (GtkButton *button, GapVexMainGlobalParams *gpp) { if(gap_debug) printf("CB: on_mw__button_video_clicked\n"); if(gpp == NULL) return; if(gpp->fsv__fileselection == NULL) { gpp->fsv__fileselection = create_fsv__fileselection(gpp); gtk_file_selection_set_filename (GTK_FILE_SELECTION (gpp->fsv__fileselection), gpp->val.videoname); gtk_widget_show (gpp->fsv__fileselection); } else { gtk_window_present(GTK_WINDOW(gpp->fsv__fileselection)); } } /* -------------------------------- * on_mw__entry_basename_changed * -------------------------------- */ static void on_mw__entry_basename_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp) { if(gap_debug) printf("CB: on_mw__entry_basename_changed\n"); if(gpp == NULL) return; if(gpp->mw__entry_basename) { g_snprintf(gpp->val.basename, sizeof(gpp->val.basename), "%s" , gtk_entry_get_text(GTK_ENTRY(gpp->mw__entry_basename))); } } /* -------------------------------- * on_mw__button_basename_clicked * -------------------------------- */ static void on_mw__button_basename_clicked (GtkButton *button, GapVexMainGlobalParams *gpp) { if(gap_debug) printf("CB: on_mw__button_basename_clicked\n"); if(gpp == NULL) return; if(gpp->fsb__fileselection == NULL) { gpp->fsb__fileselection = create_fsb__fileselection(gpp); gtk_file_selection_set_filename (GTK_FILE_SELECTION (gpp->fsb__fileselection), gpp->val.basename); gtk_widget_show (gpp->fsb__fileselection); } else { gtk_window_present(GTK_WINDOW(gpp->fsb__fileselection)); } } /* -------------------------------- * on_mw__entry_extension_changed * -------------------------------- */ static void on_mw__entry_extension_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp) { if(gap_debug) printf("CB: on_mw__entry_extension_changed\n"); if(gpp == NULL) return; if(gpp->mw__entry_extension) { g_snprintf(gpp->val.extension, sizeof(gpp->val.extension), "%s" , gtk_entry_get_text(GTK_ENTRY(gpp->mw__entry_extension))); } } /* -------------------------------- * on_mw__spinbutton_basenum_changed * -------------------------------- */ static void on_mw__spinbutton_basenum_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp) { GtkAdjustment *adj; if(gap_debug) printf("CB: on_mw__spinbutton_basenum_changed\n"); if(gpp == NULL) return; if(gpp->mw__spinbutton_basenum_adj) { adj = GTK_ADJUSTMENT(gpp->mw__spinbutton_basenum_adj); if(gap_debug) printf("basenum spin value: %f\n", (float)adj->value ); if((gint)adj->value != gpp->val.basenum) { gpp->val.basenum = (gint)adj->value; } } } /* -------------------------------- * on_mw__entry_audiofile_changed * -------------------------------- */ static void on_mw__entry_audiofile_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp) { if(gap_debug) printf("CB: on_mw__entry_audiofile_changed\n"); if(gpp == NULL) return; if(gpp->mw__entry_audiofile) { g_snprintf(gpp->val.audiofile, sizeof(gpp->val.audiofile), "%s" , gtk_entry_get_text(GTK_ENTRY(gpp->mw__entry_audiofile))); } } /* -------------------------------- * on_mw__button_audiofile_clicked * -------------------------------- */ static void on_mw__button_audiofile_clicked (GtkButton *button, GapVexMainGlobalParams *gpp) { if(gap_debug) printf("CB: on_mw__button_audiofile_clicked\n"); if(gpp == NULL) return; if(gpp->fsa__fileselection == NULL) { gpp->fsa__fileselection = create_fsa__fileselection(gpp); gtk_file_selection_set_filename (GTK_FILE_SELECTION (gpp->fsa__fileselection), gpp->val.audiofile); gtk_widget_show (gpp->fsa__fileselection); } else { gtk_window_present(GTK_WINDOW(gpp->fsa__fileselection)); } } /* -------------------------------- * on_mw__checkbutton_multilayer_toggled * -------------------------------- */ static void on_mw__checkbutton_multilayer_toggled (GtkToggleButton *togglebutton, GapVexMainGlobalParams *gpp) { GtkWidget *wgt; if(gap_debug) printf("CB: on_mw__checkbutton_multilayer_toggled\n"); if(gpp == NULL) return; wgt = gpp->mw__checkbutton_multilayer; if (GTK_TOGGLE_BUTTON (wgt)->active) { gpp->val.multilayer = TRUE; } else { gpp->val.multilayer = FALSE; } p_update_wgt_sensitivity(gpp); } /* -------------------------------- * on_mw__button_vrange_dialog_clicked * -------------------------------- */ static void on_mw__button_vrange_dialog_clicked (GtkButton *button, GdkEventButton *bevent, GapVexMainGlobalParams *gpp) { gdouble delace; gboolean docked_mode; delace = gpp->val.deinterlace; if(delace == GAP_VEX_DELACE_ODD_X2) { delace = GAP_VEX_DELACE_ODD; } if(delace == GAP_VEX_DELACE_EVEN_X2) { delace = GAP_VEX_DELACE_EVEN; } delace += CLAMP(gpp->val.delace_threshold, 0.0, 0.9999); if(gap_debug) printf("CB: on_mw__button_vrange_dialog_clicked\n"); if(gpp == NULL) return; docked_mode = TRUE; if(bevent) { if ((bevent->state & GDK_SHIFT_MASK)) /* SHIFT Click */ { docked_mode = FALSE; } } p_call_player_widget(gpp ,gpp->val.videoname ,gpp->video_width ,gpp->video_height , gpp->val.begin_frame , gpp->val.end_frame , gpp->val.videotrack , delace , docked_mode ); } /* -------------------------------- * on_mw__button_vrange_docked_clicked * -------------------------------- */ static void on_mw__button_vrange_docked_clicked (GtkButton *button, GapVexMainGlobalParams *gpp) { gdouble delace; delace = gpp->val.deinterlace; if(delace == GAP_VEX_DELACE_ODD_X2) { delace = GAP_VEX_DELACE_ODD; } if(delace == GAP_VEX_DELACE_EVEN_X2) { delace = GAP_VEX_DELACE_EVEN; } delace += CLAMP(gpp->val.delace_threshold, 0.0, 0.9999); if(gap_debug) printf("CB: on_mw__button_vrange_docked_clicked\n"); if(gpp == NULL) return; p_call_player_widget(gpp ,gpp->val.videoname ,gpp->video_width ,gpp->video_height , gpp->val.begin_frame , gpp->val.end_frame , gpp->val.videotrack , delace , TRUE /* docked_mode */ ); } /* -------------------------------- * on_mw__entry_preferred_decoder_changed * -------------------------------- */ static void on_mw__entry_preferred_decoder_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp) { const char *preferred_decoder; GtkEntry *entry; if(gap_debug) printf("CB: on_mw__entry_preferred_decoder_changed\n"); if(gpp == NULL) return; entry = GTK_ENTRY(gpp->mw__entry_preferred_decoder); if(entry) { preferred_decoder = gtk_entry_get_text(entry); g_snprintf(gpp->val.preferred_decoder, sizeof(gpp->val.preferred_decoder), "%s" , preferred_decoder); p_check_videofile(gpp); } } /* -------------------------------- * on_mw__checkbutton_exact_seek_toggled * -------------------------------- */ static void on_mw__checkbutton_exact_seek_toggled (GtkToggleButton *togglebutton, GapVexMainGlobalParams *gpp) { GtkWidget *wgt; if(gap_debug) printf("CB: on_mw__checkbutton_exact_seek_toggled\n"); if(gpp == NULL) return; wgt = gpp->mw__checkbutton_exact_seek; if (GTK_TOGGLE_BUTTON (wgt)->active) { gpp->val.exact_seek = TRUE; } else { gpp->val.exact_seek = FALSE; } } /* -------------------------------- * on_mw__spinbutton_delace_threshold_changed * -------------------------------- */ static void on_mw__spinbutton_delace_threshold_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp) { GtkAdjustment *adj; if(gap_debug) printf("CB: on_mw__spinbutton_delace_threshold_changed\n"); if(gpp == NULL) return; if(gpp->mw__spinbutton_delace_threshold_adj) { adj = GTK_ADJUSTMENT(gpp->mw__spinbutton_delace_threshold_adj); if(gap_debug) printf("spin value: %f\n", (float)adj->value ); if((gdouble)adj->value != gpp->val.delace_threshold) { gpp->val.delace_threshold = (gdouble)adj->value; } } } /* -------------------------------- * on_mw__spinbutton_fn_digits_changed * -------------------------------- */ static void on_mw__spinbutton_fn_digits_changed (GtkEditable *editable, GapVexMainGlobalParams *gpp) { GtkAdjustment *adj; if(gap_debug) printf("CB: on_mw__spinbutton_fn_digits_changed\n"); if(gpp == NULL) return; if(gpp->mw__spinbutton_fn_digits_adj) { adj = GTK_ADJUSTMENT(gpp->mw__spinbutton_fn_digits_adj); if(gap_debug) printf("spin value: %f\n", (float)adj->value ); if((gint32)adj->value != gpp->val.fn_digits) { gpp->val.fn_digits = (gint32)adj->value; } } } /* XXXXXXXXXXXXXXXXXXXXXXXXX Videofile Select XXXXXXXXXXXXXXXXXXXXXXX FSV */ /* -------------------------------- * on_fsv__fileselection_destroy * -------------------------------- */ static void on_fsv__fileselection_destroy (GtkObject *object, GapVexMainGlobalParams *gpp) { if(gap_debug) printf("CB: on_fsv__fileselection_destroy\n"); if(gpp == NULL) return; gpp->fsv__fileselection = NULL; } /* -------------------------------- * on_fsv__button_OK_clicked * -------------------------------- */ static void on_fsv__button_OK_clicked (GtkButton *button, GapVexMainGlobalParams *gpp) { const gchar *filename; GtkEntry *entry; if(gap_debug) printf("CB: on_fsv__button_OK_clicked\n"); if(gpp == NULL) return; if(gpp->fsv__fileselection) { filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (gpp->fsv__fileselection)); g_snprintf(gpp->val.videoname, sizeof(gpp->val.videoname), "%s" ,filename); entry = GTK_ENTRY(gpp->mw__entry_video); if(entry) { gtk_entry_set_text(entry, filename); p_update_wgt_sensitivity(gpp); } on_fsv__button_cancel_clicked(NULL, (gpointer)gpp); } } /* -------------------------------- * on_fsv__button_cancel_clicked * -------------------------------- */ static void on_fsv__button_cancel_clicked (GtkButton *button, GapVexMainGlobalParams *gpp) { if(gap_debug) printf("CB: on_fsv__button_cancel_clicked\n"); if(gpp == NULL) return; if(gpp->fsv__fileselection) { gtk_widget_destroy(gpp->fsv__fileselection); gpp->fsv__fileselection = NULL; } } /* XXXXXXXXXXXXXXXXXXXXXXXXX Basename Fileselect XXXXXXXXXXXXXXXXXXXXXXX FSB */ /* -------------------------------- * on_fsb__fileselection_destroy * -------------------------------- */ static void on_fsb__fileselection_destroy (GtkObject *object, GapVexMainGlobalParams *gpp) { if(gap_debug) printf("CB: on_fsb__fileselection_destroy\n"); if(gpp == NULL) return; gpp->fsb__fileselection = NULL; } /* -------------------------------- * on_fsb__button_OK_clicked * -------------------------------- */ static void on_fsb__button_OK_clicked (GtkButton *button, GapVexMainGlobalParams *gpp) { GtkEntry *entry; const gchar *filename; if(gap_debug) printf("CB: on_fsb__button_OK_clicked\n"); if(gpp == NULL) return; if(gpp->fsb__fileselection) { filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (gpp->fsb__fileselection)); g_snprintf(gpp->val.basename, sizeof(gpp->val.basename), "%s" , filename); entry = GTK_ENTRY(gpp->mw__entry_basename); if(entry) { gtk_entry_set_text(entry, filename); } on_fsb__button_cancel_clicked(NULL, (gpointer)gpp); } } /* -------------------------------- * on_fsb__button_cancel_clicked * -------------------------------- */ static void on_fsb__button_cancel_clicked (GtkButton *button, GapVexMainGlobalParams *gpp) { if(gap_debug) printf("CB: on_fsb__button_cancel_clicked\n"); if(gpp == NULL) return; if(gpp->fsb__fileselection) { gtk_widget_destroy(gpp->fsb__fileselection); gpp->fsb__fileselection = NULL; } } /* XXXXXXXXXXXXXXXXXXXXXXXXX Audio Fileselect XXXXXXXXXXXXXXXXXXXXXXX FSA */ /* -------------------------------- * on_fsa__fileselection_destroy * -------------------------------- */ static void on_fsa__fileselection_destroy (GtkObject *object, GapVexMainGlobalParams *gpp) { if(gap_debug) printf("CB: on_fsa__fileselection_destroy\n"); if(gpp == NULL) return; gpp->fsa__fileselection = NULL; } /* -------------------------------- * on_fsa__button_OK_clicked * -------------------------------- */ static void on_fsa__button_OK_clicked (GtkButton *button, GapVexMainGlobalParams *gpp) { const gchar *filename; GtkEntry *entry; if(gap_debug) printf("CB: on_fsa__button_OK_clicked\n"); if(gpp == NULL) return; if(gpp->fsa__fileselection) { filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (gpp->fsa__fileselection)); g_snprintf(gpp->val.audiofile, sizeof(gpp->val.audiofile), "%s" , filename); entry = GTK_ENTRY(gpp->mw__entry_audiofile); if(entry) { gtk_entry_set_text(entry, filename); } on_fsa__button_cancel_clicked(NULL, (gpointer)gpp); } } /* -------------------------------- * on_fsa__button_cancel_clicked * -------------------------------- */ static void on_fsa__button_cancel_clicked (GtkButton *button, GapVexMainGlobalParams *gpp) { if(gap_debug) printf("CB: on_fsa__button_cancel_clicked\n"); if(gpp == NULL) return; if(gpp->fsa__fileselection) { gtk_widget_destroy(gpp->fsa__fileselection); gpp->fsa__fileselection = NULL; } } /* ---------------------------------- * create_fsv__fileselection * ---------------------------------- * videofile selection dialog */ static GtkWidget* create_fsv__fileselection (GapVexMainGlobalParams *gpp) { GtkWidget *fsv__fileselection; GtkWidget *fsv__button_OK; GtkWidget *fsv__button_cancel; fsv__fileselection = gtk_file_selection_new (_("Select input videofile")); gtk_container_set_border_width (GTK_CONTAINER (fsv__fileselection), 10); fsv__button_OK = GTK_FILE_SELECTION (fsv__fileselection)->ok_button; gtk_widget_show (fsv__button_OK); GTK_WIDGET_SET_FLAGS (fsv__button_OK, GTK_CAN_DEFAULT); fsv__button_cancel = GTK_FILE_SELECTION (fsv__fileselection)->cancel_button; gtk_widget_show (fsv__button_cancel); GTK_WIDGET_SET_FLAGS (fsv__button_cancel, GTK_CAN_DEFAULT); g_signal_connect (G_OBJECT (fsv__fileselection), "destroy", G_CALLBACK (on_fsv__fileselection_destroy), gpp); g_signal_connect (G_OBJECT (fsv__button_OK), "clicked", G_CALLBACK (on_fsv__button_OK_clicked), gpp); g_signal_connect (G_OBJECT (fsv__button_cancel), "clicked", G_CALLBACK (on_fsv__button_cancel_clicked), gpp); gtk_widget_grab_default (fsv__button_cancel); return fsv__fileselection; } /* end create_fsv__fileselection */ /* ---------------------------------- * create_fsb__fileselection * ---------------------------------- * basename (for extracted frames) selection dialog */ static GtkWidget* create_fsb__fileselection (GapVexMainGlobalParams *gpp) { GtkWidget *fsb__fileselection; GtkWidget *fsb__button_OK; GtkWidget *fsb__button_cancel; fsb__fileselection = gtk_file_selection_new (_("Select basename for frame(s)")); gtk_container_set_border_width (GTK_CONTAINER (fsb__fileselection), 10); fsb__button_OK = GTK_FILE_SELECTION (fsb__fileselection)->ok_button; gtk_widget_show (fsb__button_OK); GTK_WIDGET_SET_FLAGS (fsb__button_OK, GTK_CAN_DEFAULT); fsb__button_cancel = GTK_FILE_SELECTION (fsb__fileselection)->cancel_button; gtk_widget_show (fsb__button_cancel); GTK_WIDGET_SET_FLAGS (fsb__button_cancel, GTK_CAN_DEFAULT); g_signal_connect (G_OBJECT (fsb__fileselection), "destroy", G_CALLBACK (on_fsb__fileselection_destroy), gpp); g_signal_connect (G_OBJECT (fsb__button_OK), "clicked", G_CALLBACK (on_fsb__button_OK_clicked), gpp); g_signal_connect (G_OBJECT (fsb__button_cancel), "clicked", G_CALLBACK (on_fsb__button_cancel_clicked), gpp); gtk_widget_grab_default (fsb__button_cancel); return fsb__fileselection; } /* end create_fsb__fileselection */ /* ---------------------------------- * create_fsa__fileselection * ---------------------------------- * audiofile selection dialog */ static GtkWidget* create_fsa__fileselection (GapVexMainGlobalParams *gpp) { GtkWidget *fsa__fileselection; GtkWidget *fsa__button_OK; GtkWidget *fsa__button_cancel; fsa__fileselection = gtk_file_selection_new (_("Select Audiofilename")); gtk_container_set_border_width (GTK_CONTAINER (fsa__fileselection), 10); fsa__button_OK = GTK_FILE_SELECTION (fsa__fileselection)->ok_button; gtk_widget_show (fsa__button_OK); GTK_WIDGET_SET_FLAGS (fsa__button_OK, GTK_CAN_DEFAULT); fsa__button_cancel = GTK_FILE_SELECTION (fsa__fileselection)->cancel_button; gtk_widget_show (fsa__button_cancel); GTK_WIDGET_SET_FLAGS (fsa__button_cancel, GTK_CAN_DEFAULT); g_signal_connect (G_OBJECT (fsa__fileselection), "destroy", G_CALLBACK (on_fsa__fileselection_destroy), gpp); g_signal_connect (G_OBJECT (fsa__button_OK), "clicked", G_CALLBACK (on_fsa__button_OK_clicked), gpp); g_signal_connect (G_OBJECT (fsa__button_cancel), "clicked", G_CALLBACK (on_fsa__button_cancel_clicked), gpp); gtk_widget_grab_default (fsa__button_cancel); return fsa__fileselection; } /* end create_fsa__fileselection */ /* endif GAP_ENABLE_VIDEOAPI_SUPPORT (1) */ #endif /* ---------------------------------- * p_align_widget_columns * ---------------------------------- * IN: array of pointers to widgets * (the array contains widgets that are arranged in one column * but do not belong to the same table) * this procedure does check for the max width of all those widgets, * and forces them all to use the same width. * (to get same alignment in the different tables) */ static void p_align_widget_columns(GtkWidget **wgt_array, gint max_elements) { gint max_label_width; gint ii; max_label_width = 0; for(ii=0; ii < max_elements; ii++) { GtkRequisition requisition; gtk_widget_size_request(wgt_array[ii], &requisition); if(gap_debug) { printf("WIDGET[%02d].width: %d\n" ,(int)ii ,(int)requisition.width ); } if(requisition.width > max_label_width) { max_label_width = requisition.width; } } /* force all labels to use the max width * (to reach same alignment in both frames) */ for(ii=0; ii < max_elements; ii++) { gtk_widget_set_size_request (wgt_array[ii], max_label_width, -1); } } /* end p_align_widget_columns */ /* ---------------------------------- * gap_vex_dlg_create_mw__main_window * ---------------------------------- * create the main window for video extract plug-in */ GtkWidget* gap_vex_dlg_create_mw__main_window (GapVexMainGlobalParams *gpp) { GtkWidget *mw__main_window; GtkWidget *mw__dialog_vbox1; GtkWidget *mw__vbox1; GtkWidget *mw__frame1; GtkWidget *mw__vbox2; GtkWidget *mw__table_in; GtkWidget *mw__table_out; GtkWidget *mw__label_video; GtkWidget *mw__checkbutton_disable_mmx; GtkWidget *mw__entry_video; GtkWidget *mw__button_vrange_dialog; GtkWidget *mw__button_vrange_docked; GtkWidget *mw__button_video; GtkWidget *mw__combo_preferred_decoder; GtkWidget *mw__label_active_decoder; GtkWidget *mw__label_aspect_ratio; GtkWidget *mw__entry_preferred_decoder; GtkObject *mw__spinbutton_audiotrack_adj; GtkWidget *mw__spinbutton_audiotrack; GtkObject *mw__spinbutton_videotrack_adj; GtkWidget *mw__spinbutton_videotrack; GtkObject *mw__spinbutton_end_frame_adj; GtkWidget *mw__spinbutton_end_frame; GtkObject *mw__spinbutton_begin_frame_adj; GtkWidget *mw__spinbutton_begin_frame; GtkWidget *mw__checkbutton_exact_seek; GtkWidget *mw__frame2; GtkWidget *mw__vbox10; GtkWidget *mw__label_basename; GtkWidget *mw__entry_basename; GtkWidget *mw__button_basename; GtkWidget *mw__label_extension; GtkObject *mw__spinbutton_basenum_adj; GtkWidget *mw__spinbutton_basenum; GtkWidget *mw__label_audifile; GtkWidget *mw__entry_audiofile; GtkWidget *mw__button_audiofile; GtkWidget *mw__checkbutton_multilayer; GtkWidget *mw__combo_deinterlace; GtkObject *mw__spinbutton_delace_threshold_adj; GtkWidget *mw__spinbutton_delace_threshold; GtkWidget *mw__entry_extension; GtkObject *mw__spinbutton_fn_digits_adj; GtkWidget *mw__spinbutton_fn_digits; GtkWidget *mw__button_OK; GtkWidget *mw__player_frame; GtkWidget *mw__main_hbox; GtkWidget *checkbutton; GtkWidget *label; GtkWidget *hbox2; GtkWidget *wgt_array[50]; GtkWidget *lbl_array[50]; gint wgt_idx; gint lbl_idx; gint out_row; gint in_row; mw__main_window = NULL; wgt_idx = 0; lbl_idx = 0; #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT mw__main_window = gimp_dialog_new (_("Extract Videorange"), GAP_VEX_PLUG_IN_NAME, NULL, 0, gimp_standard_help_func, GAP_VEX_PLUG_IN_HELP_ID, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_window_set_type_hint (mw__main_window, GDK_WINDOW_TYPE_HINT_NORMAL); g_signal_connect (G_OBJECT (mw__main_window), "response", G_CALLBACK (on_mw_response), gpp); mw__dialog_vbox1 = GTK_DIALOG (mw__main_window)->vbox; gtk_widget_show (mw__dialog_vbox1); mw__main_hbox = gtk_hbox_new (FALSE, 0); gtk_widget_show (mw__main_hbox); gtk_box_pack_start (GTK_BOX (mw__dialog_vbox1), mw__main_hbox, TRUE, TRUE, 5); mw__vbox1 = gtk_vbox_new (FALSE, 0); gtk_widget_show (mw__vbox1); gtk_box_pack_start (GTK_BOX (mw__main_hbox), mw__vbox1, TRUE, TRUE, 10); /*gtk_container_set_border_width (GTK_CONTAINER (mw__vbox1), 5);*/ /* XXXXXXXXXXX Player Frame XXXXXXXXXXXX */ /* the player_frame */ mw__player_frame = gimp_frame_new ( _("Select Videorange") ); gtk_frame_set_shadow_type (GTK_FRAME (mw__player_frame) ,GTK_SHADOW_ETCHED_IN); gtk_box_pack_start (GTK_BOX (mw__main_hbox), mw__player_frame, TRUE, TRUE, 0); /* the mw__player_frame widget is hidden at startup * and becomes visible, when the user wants to select * the videorange via player in docked mode */ /* gtk_widget_show (mw__player_frame); */ /* not yet, show the widget later */ mw__frame1 = gimp_frame_new (_("Input Video selection")); gtk_widget_show (mw__frame1); gtk_box_pack_start (GTK_BOX (mw__vbox1), mw__frame1, TRUE, TRUE, 0); mw__vbox2 = gtk_vbox_new (FALSE, 0); gtk_widget_show (mw__vbox2); gtk_container_add (GTK_CONTAINER (mw__frame1), mw__vbox2); gtk_container_set_border_width (GTK_CONTAINER (mw__vbox2), 4); mw__table_in = gtk_table_new (7, 3, FALSE); gtk_widget_show (mw__table_in); gtk_box_pack_start (GTK_BOX (mw__vbox2), mw__table_in, TRUE, TRUE, 2); gtk_table_set_row_spacings (GTK_TABLE (mw__table_in), 1); gtk_table_set_col_spacings (GTK_TABLE (mw__table_in), 1); in_row = 0; /* the videofile label */ mw__label_video = gtk_label_new (_("Videofilename:")); lbl_array[lbl_idx] = mw__label_video; lbl_idx++; gtk_widget_show (mw__label_video); gtk_misc_set_alignment (GTK_MISC (mw__label_video), 0.0, 0.0); gtk_table_attach (GTK_TABLE (mw__table_in), mw__label_video, 0, 1, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* the videofile entry */ mw__entry_video = gtk_entry_new (); gtk_widget_show (mw__entry_video); gtk_widget_set_size_request (mw__entry_video, ENTRY_WIDTH_LARGE, -1); gtk_table_attach (GTK_TABLE (mw__table_in), mw__entry_video, 1, 2, in_row, in_row+1, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (mw__entry_video, _("Name of videofile (used as inputfile)"), NULL); /* the videofile button (that invokes fileselection dialog) */ mw__button_video = gtk_button_new_with_label (_("...")); gtk_widget_show (mw__button_video); wgt_array[wgt_idx] = mw__button_video; wgt_idx++; gtk_table_attach (GTK_TABLE (mw__table_in), mw__button_video, 2, 3, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (mw__button_video, _("Select video using file browser"), NULL); /* MMX sometimes gives unusable results, and therefore is always OFF * checkbox is not needed any more.. */ mw__checkbutton_disable_mmx = gtk_check_button_new_with_label (_("Disable MMX")); gtk_widget_hide (mw__checkbutton_disable_mmx); in_row++; /* the videoextract range from label */ label = gtk_label_new (_("From Frame:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); lbl_array[lbl_idx] = label; lbl_idx++; gtk_widget_show (label); gtk_table_attach (GTK_TABLE (mw__table_in), label, 0, 1, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* from spinbutton */ hbox2 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox2); gtk_table_attach (GTK_TABLE (mw__table_in), hbox2, 1, 2, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); mw__spinbutton_begin_frame_adj = gtk_adjustment_new (1, 1, 999999, 1, 10, 0); mw__spinbutton_begin_frame = gtk_spin_button_new (GTK_ADJUSTMENT (mw__spinbutton_begin_frame_adj), 1, 0); gtk_widget_show (mw__spinbutton_begin_frame); gtk_widget_set_size_request (mw__spinbutton_begin_frame, SPIN_WIDTH_LARGE, -1); gtk_box_pack_start (GTK_BOX (hbox2), mw__spinbutton_begin_frame, FALSE, FALSE, 0); gimp_help_set_help_data (mw__spinbutton_begin_frame, _("Frame number of 1.st frame to extract"), NULL); /* from timecode label */ label = gtk_label_new(TIME_UNDEF_STRING); gpp->mw__begin_time_label = label; gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 12); gtk_widget_show(label); /* dummy label to fill up the hbox2 */ label = gtk_label_new (" "); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (hbox2), label, TRUE, TRUE, 0); /* the videorange button (that invokes the player for video range selection) */ mw__button_vrange_dialog = gtk_button_new_with_label (_("Video Range")); gtk_widget_show (mw__button_vrange_dialog); wgt_array[wgt_idx] = mw__button_vrange_dialog; wgt_idx++; gtk_table_attach (GTK_TABLE (mw__table_in), mw__button_vrange_dialog, 2, 3, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (mw__button_vrange_dialog , _("Visual video range selection via videoplayer\n" "SHIFT: Open a separate player window") , NULL); in_row++; /* the videoextract range to label */ label = gtk_label_new (_("To Frame:")); gtk_widget_show (label); lbl_array[lbl_idx] = label; lbl_idx++; gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0); gtk_table_attach (GTK_TABLE (mw__table_in), label, 0, 1, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* to spinbutton */ hbox2 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox2); gtk_table_attach (GTK_TABLE (mw__table_in), hbox2, 1, 2, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); mw__spinbutton_end_frame_adj = gtk_adjustment_new (1, 1, 999999, 1, 10, 0); mw__spinbutton_end_frame = gtk_spin_button_new (GTK_ADJUSTMENT (mw__spinbutton_end_frame_adj), 1, 0); gtk_widget_show (mw__spinbutton_end_frame); gtk_box_pack_start (GTK_BOX (hbox2), mw__spinbutton_end_frame, FALSE, FALSE, 0); gtk_widget_set_size_request (mw__spinbutton_end_frame, SPIN_WIDTH_LARGE, -1); gimp_help_set_help_data (mw__spinbutton_end_frame , _("Frame number of last frame to extract. " "To extract all frames use a range from 1 to 999999. " "(Extract stops at the last available frame)") , NULL); /* to timecode label */ label = gtk_label_new(TIME_UNDEF_STRING); gpp->mw__end_time_label = label; gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 12); gtk_widget_show(label); /* dummy label to fill up the hbox2 */ label = gtk_label_new (" "); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (hbox2), label, TRUE, TRUE, 0); /* the videorange button (that invokes the player for video range selection in docked mode) */ mw__button_vrange_docked = gtk_button_new_with_label (_("VideoRange")); // gtk_widget_show (mw__button_vrange_docked); // wgt_array[wgt_idx] = mw__button_vrange_docked; // wgt_idx++; // gtk_table_attach (GTK_TABLE (mw__table_in), mw__button_vrange_docked, 2, 3, in_row, in_row+1, // (GtkAttachOptions) (GTK_FILL), // (GtkAttachOptions) (0), 0, 0); // gimp_help_set_help_data (mw__button_vrange_docked, _("visual video range selection (docked mode)"), NULL); in_row++; /* the videotrack to label */ label = gtk_label_new (_("Videotrack:")); gtk_widget_show (label); lbl_array[lbl_idx] = label; lbl_idx++; gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0); gtk_table_attach (GTK_TABLE (mw__table_in), label, 0, 1, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* videotrack spinbutton */ hbox2 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox2); gtk_table_attach (GTK_TABLE (mw__table_in), hbox2, 1, 2, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0); mw__spinbutton_videotrack_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 0); mw__spinbutton_videotrack = gtk_spin_button_new (GTK_ADJUSTMENT (mw__spinbutton_videotrack_adj), 1, 0); gtk_widget_show (mw__spinbutton_videotrack); gtk_widget_set_size_request (mw__spinbutton_videotrack, SPIN_WIDTH_SMALL, -1); gtk_box_pack_start (GTK_BOX (hbox2), mw__spinbutton_videotrack, FALSE, FALSE, 0); gimp_help_set_help_data (mw__spinbutton_videotrack, _("Videotrack number (0 == extract no frames)"), NULL); /* dummy label to fill up the hbox2 */ label = gtk_label_new (" "); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (hbox2), label, TRUE, TRUE, 0); in_row++; /* the audiotrack to label */ label = gtk_label_new (_("Audiotrack:")); gtk_widget_show (label); lbl_array[lbl_idx] = label; lbl_idx++; gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0); gtk_table_attach (GTK_TABLE (mw__table_in), label, 0, 1, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* audiotrack spinbutton */ hbox2 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox2); gtk_table_attach (GTK_TABLE (mw__table_in), hbox2, 1, 2, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0); mw__spinbutton_audiotrack_adj = gtk_adjustment_new (0, 0, 100, 1, 10, 0); mw__spinbutton_audiotrack = gtk_spin_button_new (GTK_ADJUSTMENT (mw__spinbutton_audiotrack_adj), 1, 0); gtk_widget_show (mw__spinbutton_audiotrack); gtk_widget_set_size_request (mw__spinbutton_audiotrack, SPIN_WIDTH_SMALL, -1); gtk_box_pack_start (GTK_BOX (hbox2), mw__spinbutton_audiotrack, FALSE, FALSE, 0); gimp_help_set_help_data (mw__spinbutton_audiotrack, _("Audiotrack number (0 == extract no audio)"), NULL); /* dummy label to fill up the hbox2 */ label = gtk_label_new (" "); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (hbox2), label, TRUE, TRUE, 0); in_row++; /* the (preferred) Decoder label */ label = gtk_label_new (_("Decoder:")); gtk_widget_show (label); lbl_array[lbl_idx] = label; lbl_idx++; gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); gtk_table_attach (GTK_TABLE (mw__table_in), label, 0, 1, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); mw__entry_preferred_decoder = gtk_entry_new (); gtk_widget_show (mw__entry_preferred_decoder); gtk_widget_set_size_request (mw__entry_preferred_decoder, ENTRY_WIDTH_LARGE, -1); gtk_table_attach (GTK_TABLE (mw__table_in), mw__entry_preferred_decoder, 1, 2, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (mw__entry_preferred_decoder, _("leave empty or select your preferred decoder (libmpeg3, libavformat, quicktime4linux)"), NULL); /* the menu to select the preferred decoder */ mw__combo_preferred_decoder = gimp_int_combo_box_new (_("(none, automatic)"), GAP_VEX_DECODER_NONE , "libmpeg3", GAP_VEX_DECODER_LIBMPEG3, "libavformat", GAP_VEX_DECODER_LIBAVFORMAT, "quicktime4linux", GAP_VEX_DECODER_QUICKTIME, NULL); gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (mw__combo_preferred_decoder), GAP_VEX_DECODER_NONE, /* initial value */ G_CALLBACK (on_mw__combo_preferred_decoder), gpp); gtk_widget_show (mw__combo_preferred_decoder); wgt_array[wgt_idx] = mw__combo_preferred_decoder; wgt_idx++; gtk_table_attach (GTK_TABLE (mw__table_in), mw__combo_preferred_decoder, 2, 3, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); in_row++; /* the (Active) Decoder Label(s) */ label = gtk_label_new (_("Active Decoder:")); gtk_widget_show (label); lbl_array[lbl_idx] = label; lbl_idx++; gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0); gtk_table_attach (GTK_TABLE (mw__table_in), label, 0, 1, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); mw__label_active_decoder = gtk_label_new (_("****")); gtk_widget_show (mw__label_active_decoder); gtk_table_attach (GTK_TABLE (mw__table_in), mw__label_active_decoder, 1, 2, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_padding (GTK_MISC (mw__label_active_decoder), 4, 0); gtk_misc_set_alignment (GTK_MISC (mw__label_active_decoder), 0.0, 0.0); /* exact_seek option to disable fast videoindex based positioning. * (the videoapi delivers exact frame positions on most videos * but sometimes is not exact when libmepg3 is used) */ mw__checkbutton_exact_seek = gtk_check_button_new_with_label (_("Exact Seek")); gtk_widget_show (mw__checkbutton_exact_seek); gimp_help_set_help_data (mw__checkbutton_exact_seek , _("ON: emulate seek operations by sequential reads, " "even when videoindex is available") , NULL); gtk_table_attach (GTK_TABLE (mw__table_in), mw__checkbutton_exact_seek, 2, 3, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); in_row++; /* the Aspect Ratio Label(s) */ label = gtk_label_new (_("Aspect Ratio:")); gtk_widget_show (label); lbl_array[lbl_idx] = label; lbl_idx++; gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0); gtk_table_attach (GTK_TABLE (mw__table_in), label, 0, 1, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); mw__label_aspect_ratio = gtk_label_new (_("****")); gtk_widget_show (mw__label_aspect_ratio); gtk_table_attach (GTK_TABLE (mw__table_in), mw__label_aspect_ratio, 1, 2, in_row, in_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_padding (GTK_MISC (mw__label_aspect_ratio), 4, 0); gtk_misc_set_alignment (GTK_MISC (mw__label_aspect_ratio), 0.0, 0.0); mw__frame2 = gimp_frame_new (_("Output")); gtk_widget_show (mw__frame2); gtk_box_pack_start (GTK_BOX (mw__vbox1), mw__frame2, TRUE, TRUE, 10); mw__vbox10 = gtk_vbox_new (FALSE, 0); gtk_widget_show (mw__vbox10); gtk_container_add (GTK_CONTAINER (mw__frame2), mw__vbox10); gtk_container_set_border_width (GTK_CONTAINER (mw__vbox10), 4); mw__table_out = gtk_table_new (4, 3, FALSE); gtk_widget_show (mw__table_out); gtk_box_pack_start (GTK_BOX (mw__vbox10), mw__table_out, TRUE, TRUE, 0); out_row = 0; /* the operating Mode label */ label = gtk_label_new (_("Mode:")); gtk_widget_show (label); lbl_array[lbl_idx] = label; lbl_idx++; gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0); gtk_table_attach (GTK_TABLE (mw__table_out), label, 0, 1, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* the multilayer checkbox (decide if extract writes to frames on disc or to one image) */ mw__checkbutton_multilayer = gtk_check_button_new_with_label (_("Create only one multilayer Image")); gtk_widget_show (mw__checkbutton_multilayer); gtk_table_attach (GTK_TABLE (mw__table_out), mw__checkbutton_multilayer, 1, 2, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (mw__checkbutton_multilayer , _("On: extracted frames are stored in one multilayer image\n" "Off: extracted frames are written to frame files on disc") , NULL); out_row++; /* the basename label */ mw__label_basename = gtk_label_new (_("Basename:")); gtk_widget_show (mw__label_basename); lbl_array[lbl_idx] = mw__label_basename; lbl_idx++; gtk_misc_set_alignment (GTK_MISC (mw__label_basename), 0.0, 0); gtk_table_attach (GTK_TABLE (mw__table_out), mw__label_basename, 0, 1, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* the basename entry */ mw__entry_basename = gtk_entry_new (); gtk_widget_show (mw__entry_basename); gtk_widget_set_size_request (mw__entry_basename, ENTRY_WIDTH_LARGE, -1); gtk_table_attach (GTK_TABLE (mw__table_out), mw__entry_basename, 1, 2, out_row, out_row+1, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (mw__entry_basename, _("Basename for extracted frames (framenr and extension is added)"), NULL); gtk_entry_set_text (GTK_ENTRY (mw__entry_basename), _("frame_")); /* the basename button (that invokes the fileselection dialog) */ mw__button_basename = gtk_button_new_with_label (_("...")); gtk_widget_show (mw__button_basename); wgt_array[wgt_idx] = mw__button_basename; wgt_idx++; gtk_table_attach (GTK_TABLE (mw__table_out), mw__button_basename, 2, 3, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (mw__button_basename, _("Use filebrowser to select basename for extracted frames"), NULL); out_row++; /* the framenumber digits label */ label = gtk_label_new (_("Digits:")); gtk_widget_show (label); lbl_array[lbl_idx] = label; lbl_idx++; gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0); gtk_table_attach (GTK_TABLE (mw__table_out), label, 0, 1, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* the framenumber digits spinbutton */ hbox2 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox2); gtk_table_attach (GTK_TABLE (mw__table_out), hbox2, 1, 2, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); mw__spinbutton_fn_digits_adj = gtk_adjustment_new (1, 1, GAP_LIB_MAX_DIGITS, 1, 10, 0); mw__spinbutton_fn_digits = gtk_spin_button_new (GTK_ADJUSTMENT (mw__spinbutton_fn_digits_adj), 1, 0); gtk_widget_show (mw__spinbutton_fn_digits); gtk_widget_set_size_request (mw__spinbutton_fn_digits, SPIN_WIDTH_SMALL, -1); gtk_box_pack_start (GTK_BOX (hbox2), mw__spinbutton_fn_digits, FALSE, FALSE, 0); gimp_help_set_help_data (mw__spinbutton_fn_digits, _("Digits to use for framenumber part in filenames (use 1 if you dont want leading zeroes)"), NULL); /* dummy label to fill up the hbox2 */ label = gtk_label_new (" "); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (hbox2), label, TRUE, TRUE, 0); /* the graymask checkbutton */ checkbutton = gtk_check_button_new_with_label (_("graymask")); gpp->mw__checkbutton_extract_alpha_as_gray_frames = checkbutton; gtk_widget_show (checkbutton); gtk_box_pack_start (GTK_BOX (hbox2), checkbutton, TRUE, TRUE, 0); gimp_help_set_help_data (checkbutton , _("On: extract grayscale mask (generated by bluebox)\n" "Off: extract color frames 1.1") , NULL); g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (on_mw__checkbutton_graymask_toggled), gpp); /* the layermask checkbutton */ checkbutton = gtk_check_button_new_with_label (_("layermask")); gpp->mw__checkbutton_extract_with_layermask = checkbutton; gtk_widget_show (checkbutton); gtk_box_pack_start (GTK_BOX (hbox2), checkbutton, TRUE, TRUE, 0); gimp_help_set_help_data (checkbutton , _("On: bluebox shall generate transparency as layermask\n" "Off: bluebox shall generate transparency as alpha channel") , NULL); g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (on_mw__checkbutton_layermask_toggled), gpp); /* the bluebox checkbutton */ checkbutton = gtk_check_button_new_with_label (_("bluebox")); gpp->mw__checkbutton_generate_alpha_via_bluebox = checkbutton; gtk_widget_show (checkbutton); gtk_table_attach (GTK_TABLE (mw__table_out), checkbutton, 2, 3, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (checkbutton , _("On: add trasparency for extracted frames via blubox filter" " (using values of last run in this session)\n" "Off: extract frames 1.1") , NULL); g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (on_mw__checkbutton_bluebox_toggled), gpp); out_row++; /* the extension label */ mw__label_extension = gtk_label_new (_("Extension:")); gtk_widget_show (mw__label_extension); lbl_array[lbl_idx] = mw__label_extension; lbl_idx++; gtk_misc_set_alignment (GTK_MISC (mw__label_extension), 0.0, 0); gtk_table_attach (GTK_TABLE (mw__table_out), mw__label_extension, 0, 1, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* the extension entry (fileextension for output frames) */ hbox2 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox2); gtk_table_attach (GTK_TABLE (mw__table_out), hbox2, 1, 2, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); mw__entry_extension = gtk_entry_new (); gtk_widget_show (mw__entry_extension); gtk_widget_set_size_request (mw__entry_extension, SPIN_WIDTH_LARGE, -1); gtk_box_pack_start (GTK_BOX (hbox2), mw__entry_extension, FALSE, FALSE, 0); gimp_help_set_help_data (mw__entry_extension, _("Extension of extracted frames (.xcf, .jpg, .ppm)"), NULL); gtk_entry_set_text (GTK_ENTRY (mw__entry_extension), _(".xcf")); /* dummy label to fill up the hbox2 */ label = gtk_label_new (" "); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (hbox2), label, TRUE, TRUE, 0); out_row++; /* the framenumber for 1st frame label */ label = gtk_label_new (_("Framenr 1:")); gtk_widget_show (label); lbl_array[lbl_idx] = label; lbl_idx++; gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0); gtk_table_attach (GTK_TABLE (mw__table_out), label, 0, 1, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* the basenum spinbutton (set framenumber for the 1st extracted frame) */ hbox2 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox2); gtk_table_attach (GTK_TABLE (mw__table_out), hbox2, 1, 2, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); mw__spinbutton_basenum_adj = gtk_adjustment_new (0, 0, 10000, 1, 10, 0); mw__spinbutton_basenum = gtk_spin_button_new (GTK_ADJUSTMENT (mw__spinbutton_basenum_adj), 1, 0); gtk_widget_show (mw__spinbutton_basenum); gtk_widget_set_size_request (mw__spinbutton_basenum, SPIN_WIDTH_LARGE, -1); gtk_box_pack_start (GTK_BOX (hbox2), mw__spinbutton_basenum, FALSE, FALSE, 0); gimp_help_set_help_data (mw__spinbutton_basenum, _("Framenumber for 1st extracted frame (use 0 for keeping original framenumbers)"), NULL); /* dummy label to fill up the hbox2 */ label = gtk_label_new (" "); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (hbox2), label, TRUE, TRUE, 0); out_row++; /* the deinterlace Mode label */ label = gtk_label_new (_("Deinterlace:")); gtk_widget_show (label); lbl_array[lbl_idx] = label; lbl_idx++; gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0); gtk_table_attach (GTK_TABLE (mw__table_out), label, 0, 1, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); hbox2 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox2); gtk_table_attach (GTK_TABLE (mw__table_out), hbox2, 1, 2, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* the deinterlace threshold spinbutton */ mw__spinbutton_delace_threshold_adj = gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0.0); mw__spinbutton_delace_threshold = gtk_spin_button_new (GTK_ADJUSTMENT (mw__spinbutton_delace_threshold_adj), 1, 2); gtk_widget_show (mw__spinbutton_delace_threshold); gtk_box_pack_start (GTK_BOX (hbox2), mw__spinbutton_delace_threshold, FALSE, FALSE, 0); gtk_widget_set_size_request (mw__spinbutton_delace_threshold, SPIN_WIDTH_LARGE, -1); gimp_help_set_help_data (mw__spinbutton_delace_threshold, _("0.0 .. no interpolation, 1.0 smooth interpolation at deinterlacing"), NULL); /* the deinterlace combo */ mw__combo_deinterlace = gimp_int_combo_box_new (_("no deinterlace"), GAP_VEX_DELACE_NONE, _("deinterlace (odd lines only)"), GAP_VEX_DELACE_ODD, _("deinterlace (even lines only)"), GAP_VEX_DELACE_EVEN, _("deinterlace frames x 2 (odd 1st)"), GAP_VEX_DELACE_ODD_X2, _("deinterlace frames x 2 (even 1st)"), GAP_VEX_DELACE_EVEN_X2, NULL); gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (mw__combo_deinterlace), GAP_VEX_DELACE_NONE, /* initial value */ G_CALLBACK (on_mw__combo_deinterlace), gpp); gtk_widget_show (mw__combo_deinterlace); gtk_box_pack_start (GTK_BOX (hbox2), mw__combo_deinterlace, TRUE, TRUE, 0); gimp_help_set_help_data (mw__combo_deinterlace, _("Deinterlace splits each extracted frame in 2 frames"), NULL); out_row++; /* the output audiofile label */ mw__label_audifile = gtk_label_new (_("Audiofile:")); gtk_widget_show (mw__label_audifile); lbl_array[lbl_idx] = mw__label_audifile; lbl_idx++; gtk_misc_set_alignment (GTK_MISC (mw__label_audifile), 0.0, 0); gtk_table_attach (GTK_TABLE (mw__table_out), mw__label_audifile, 0, 1, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* the output audiofile entry */ mw__entry_audiofile = gtk_entry_new (); gtk_widget_show (mw__entry_audiofile); gtk_widget_set_size_request (mw__entry_audiofile, ENTRY_WIDTH_LARGE, -1); gtk_table_attach (GTK_TABLE (mw__table_out), mw__entry_audiofile, 1, 2, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (mw__entry_audiofile, _("Name for extracted audio (audio is written in RIFF WAV format)"), NULL); gtk_entry_set_text (GTK_ENTRY (mw__entry_audiofile), _("frame.wav")); /* the output audiofile button (that invokes the fileselection dialog) */ mw__button_audiofile = gtk_button_new_with_label (_("...")); gtk_widget_show (mw__button_audiofile); wgt_array[wgt_idx] = mw__button_audiofile; wgt_idx++; gtk_table_attach (GTK_TABLE (mw__table_out), mw__button_audiofile, 2, 3, out_row, out_row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (mw__button_audiofile, _("Use filebrowser to select audiofilename"), NULL); mw__button_OK = NULL; if(mw__button_OK) { gimp_help_set_help_data (mw__button_OK, _("Start extraction"), NULL); } /* check for the max width of all labels in both frames * for "input Video selection" and "Output" */ p_align_widget_columns(lbl_array, lbl_idx); p_align_widget_columns(wgt_array, wgt_idx); g_signal_connect (G_OBJECT (mw__checkbutton_disable_mmx), "toggled", G_CALLBACK (on_mw__checkbutton_disable_mmx_toggled), gpp); g_signal_connect (G_OBJECT (mw__entry_video), "changed", G_CALLBACK (on_mw__entry_video_changed), gpp); g_signal_connect (G_OBJECT (mw__button_vrange_dialog), "button_press_event", G_CALLBACK (on_mw__button_vrange_dialog_clicked), gpp); g_signal_connect (G_OBJECT (mw__button_vrange_docked), "clicked", G_CALLBACK (on_mw__button_vrange_docked_clicked), gpp); g_signal_connect (G_OBJECT (mw__button_video), "clicked", G_CALLBACK (on_mw__button_video_clicked), gpp); g_signal_connect (G_OBJECT (mw__entry_preferred_decoder), "changed", G_CALLBACK (on_mw__entry_preferred_decoder_changed), gpp); g_signal_connect (G_OBJECT (mw__spinbutton_audiotrack), "value_changed", G_CALLBACK (on_mw__spinbutton_audiotrack_changed), gpp); g_signal_connect (G_OBJECT (mw__spinbutton_videotrack), "value_changed", G_CALLBACK (on_mw__spinbutton_videotrack_changed), gpp); g_signal_connect (G_OBJECT (mw__spinbutton_end_frame), "value_changed", G_CALLBACK (on_mw__spinbutton_end_frame_changed), gpp); g_signal_connect (G_OBJECT (mw__spinbutton_begin_frame), "value_changed", G_CALLBACK (on_mw__spinbutton_begin_frame_changed), gpp); g_signal_connect (G_OBJECT (mw__checkbutton_exact_seek), "toggled", G_CALLBACK (on_mw__checkbutton_exact_seek_toggled), gpp); g_signal_connect (G_OBJECT (mw__entry_basename), "changed", G_CALLBACK (on_mw__entry_basename_changed), gpp); g_signal_connect (G_OBJECT (mw__button_basename), "clicked", G_CALLBACK (on_mw__button_basename_clicked), gpp); g_signal_connect (G_OBJECT (mw__spinbutton_basenum), "value_changed", G_CALLBACK (on_mw__spinbutton_basenum_changed), gpp); g_signal_connect (G_OBJECT (mw__entry_audiofile), "changed", G_CALLBACK (on_mw__entry_audiofile_changed), gpp); g_signal_connect (G_OBJECT (mw__button_audiofile), "clicked", G_CALLBACK (on_mw__button_audiofile_clicked), gpp); g_signal_connect (G_OBJECT (mw__checkbutton_multilayer), "toggled", G_CALLBACK (on_mw__checkbutton_multilayer_toggled), gpp); g_signal_connect (G_OBJECT (mw__spinbutton_delace_threshold), "value_changed", G_CALLBACK (on_mw__spinbutton_delace_threshold_changed), gpp); g_signal_connect (G_OBJECT (mw__entry_extension), "changed", G_CALLBACK (on_mw__entry_extension_changed), gpp); g_signal_connect (G_OBJECT (mw__spinbutton_fn_digits), "value_changed", G_CALLBACK (on_mw__spinbutton_fn_digits_changed), gpp); /* copy widget pointers to global parameter * (for use in callbacks outside of this procedure) */ gpp->mw__checkbutton_disable_mmx = mw__checkbutton_disable_mmx; gpp->mw__entry_video = mw__entry_video; gpp->mw__button_vrange_dialog = mw__button_vrange_dialog; gpp->mw__button_vrange_docked = mw__button_vrange_docked; gpp->mw__button_video = mw__button_video; gpp->mw__combo_preferred_decoder = mw__combo_preferred_decoder; gpp->mw__label_active_decoder = mw__label_active_decoder; gpp->mw__label_aspect_ratio = mw__label_aspect_ratio; gpp->mw__entry_preferred_decoder = mw__entry_preferred_decoder; gpp->mw__spinbutton_audiotrack_adj = mw__spinbutton_audiotrack_adj; gpp->mw__spinbutton_audiotrack = mw__spinbutton_audiotrack; gpp->mw__spinbutton_videotrack_adj = mw__spinbutton_videotrack_adj; gpp->mw__spinbutton_videotrack = mw__spinbutton_videotrack; gpp->mw__spinbutton_end_frame_adj = mw__spinbutton_end_frame_adj; gpp->mw__spinbutton_end_frame = mw__spinbutton_end_frame; gpp->mw__spinbutton_begin_frame_adj = mw__spinbutton_begin_frame_adj; gpp->mw__spinbutton_begin_frame = mw__spinbutton_begin_frame; gpp->mw__checkbutton_exact_seek = mw__checkbutton_exact_seek; gpp->mw__entry_extension = mw__entry_extension; gpp->mw__entry_basename = mw__entry_basename; gpp->mw__button_basename = mw__button_basename; gpp->mw__spinbutton_basenum_adj = mw__spinbutton_basenum_adj; gpp->mw__spinbutton_basenum = mw__spinbutton_basenum; gpp->mw__entry_audiofile = mw__entry_audiofile; gpp->mw__button_audiofile = mw__button_audiofile; gpp->mw__checkbutton_multilayer = mw__checkbutton_multilayer; gpp->mw__combo_deinterlace = mw__combo_deinterlace; gpp->mw__spinbutton_delace_threshold_adj = mw__spinbutton_delace_threshold_adj; gpp->mw__spinbutton_delace_threshold = mw__spinbutton_delace_threshold; gpp->mw__spinbutton_fn_digits_adj = mw__spinbutton_fn_digits_adj; gpp->mw__spinbutton_fn_digits = mw__spinbutton_fn_digits; gpp->mw__button_OK = mw__button_OK; gpp->mw__player_frame = mw__player_frame; p_init_mw__main_window_widgets(gpp); /* endif GAP_ENABLE_VIDEOAPI_SUPPORT (2) */ #endif return mw__main_window; } /* end gap_vex_dlg_create_mw__main_window */ /* ---------------------------------- * gap_vex_dlg_main_dialog * ---------------------------------- */ void gap_vex_dlg_main_dialog (GapVexMainGlobalParams *gpp) { gimp_ui_init ("gap_video_extract", FALSE); gap_stock_init(); gpp->fsv__fileselection = NULL; gpp->fsb__fileselection = NULL; gpp->fsa__fileselection = NULL; gpp->mw__entry_preferred_decoder = NULL; gpp->mw__spinbutton_delace_threshold = NULL; gpp->mw__main_window = gap_vex_dlg_create_mw__main_window (gpp); gtk_widget_show (gpp->mw__main_window); gtk_main (); if(gap_debug) printf("A F T E R gtk_main\n"); } /* end gap_vex_dlg_main_dialog */ gimp-gap-2.6.0+dfsg.orig/gap/gap_decode_xanim.c0000644000175000017500000011177511212030253021142 0ustar thibautthibaut/* gap_decode_xanim.c * 1999.11.22 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * * GIMP/GAP-frontend interface for XANIM exporting edition from loki entertainmaint * Call xanim exporting edition (the loki version) * To split any xanim supported video into * video frames (single images on disk) * Audio can also be extracted. * * xanim exporting edition is available at: * Web: http://heroine.linuxbox.com/toys.html * http://www.lokigames.com/development/smjpeg.php3 * download: http://heroine.linuxbox.com/xanim_exporting_edition.tar.gz * http://www.lokigames.com/development/download/smjpeg/xanim2801-loki090899.tar.gz * Send comments or questions to smjpeg@lokigames.com. * * Warning: This Module needs UNIX environment to run. * It uses programs and commands that are NOT available * on other Operating Systems (Win95, NT, XP ...) * * - xanim 2.80 exporting edition with extensions from loki entertainment. * set environment GAP_XANIM_PROG to configure where to find xanim * (default: search xanim in your PATH) * - cd (UNIX command) * - grep (UNIX command) * - rm (UNIX command is used to delete by wildcard (expanded by /bin/sh) * and to delete a directory with all files */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history * gimp 2.1.0; 2004/12/06 hof: use g_file_test(dir, G_FILE_TEST_IS_DIR) to check for directory * gimp 1.3.26c; 2004/03/09 hof: bugfix (gimp_destroy_params) * gimp 1.3.20a; 2003/09/15 hof: should fix compile problems on WIN32 (#122220) * (but will not run at WIN OS) * gimp 1.3.17b; 2003/07/31 hof: message text fixes for translators (# 118392) * gimp 1.3.16a; 2003/06/25 hof: no textsplitting across multiple lables (for translation) * gimp 1.3.15a; 2003/06/21 hof: checked textspacing * gimp 1.3.12a; 2003/05/02 hof: merge into CVS-gimp-gap project, 6digit framenumbers * 1.3.4b 2002/03723 hof: merged in bugfix from stable branch 1.2.2c; 2002/03/19 xanim call fails if . not in PATH or no write permission for current dir * (reported by Guido Socher) * 1.1.29b; 2000/11/30 hof: used g_snprintf * 1.1.17b; 2000/02/26 hof: bugfixes * 1.1.14a; 1999/11/22 hof: fixed gcc warning (too many arguments for format) * 1.1.13a; 1999/11/22 hof: first release */ /* SYTEM (UNIX) includes */ #include #include #include #include #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "config.h" #include "gap-intl.h" #include "libgimp/gimp.h" #ifdef G_OS_WIN32 #include # ifndef S_ISDIR # define S_ISDIR(m) ((m) & _S_IFDIR) # endif # ifndef S_ISREG # define S_ISREG(m) ((m) & _S_IFREG) # endif #endif #define GAP_XANIM_HELP_ID "plug-in-gap-xanim-decode" /* GAP includes */ #include "gap_libgapbase.h" #include "gap_lib.h" #include "gap_arr_dialog.h" #include "gap_decode_xanim.h" extern int gap_debug; /* ==0 ... dont print debug infos */ static char *global_xanim_input_dir = NULL; static char *global_xanim_working_dir = NULL; static gchar global_xanim_prog[500]; static gchar *global_errlist = NULL; gint32 global_delete_number; /* fileformats supported by gap_decode_xanim */ typedef enum { XAENC_XCF /* no direct support by xanim, have to convert */ , XAENC_PPMRAW , XAENC_JPEG } GapXAnimFormats; /* ============================================================================ * p_xanim_info * ============================================================================ */ static int p_xanim_info(char *errlist) { GapArrArg argv[22]; GapArrButtonArg b_argv[2]; int l_idx; int l_rc; l_idx = 0; gap_arr_arg_init(&argv[l_idx], GAP_ARR_WGT_LABEL_LEFT); argv[l_idx].label_txt = _("Requirements to run the xanim based video split"); l_idx++; gap_arr_arg_init(&argv[l_idx], GAP_ARR_WGT_LABEL_LEFT); argv[l_idx].label_txt = ""; l_idx++; gap_arr_arg_init(&argv[l_idx], GAP_ARR_WGT_LABEL_LEFT); argv[l_idx].label_txt = "1.)"; l_idx++; gap_arr_arg_init(&argv[l_idx], GAP_ARR_WGT_LABEL_LEFT); argv[l_idx].label_txt = _("xanim 2.80.0 exporting edition (the loki version)\n" "must be installed somewhere in your PATH\n" "you can get xanim exporting edition at:\n" ); l_idx++; gap_arr_arg_init(&argv[l_idx], GAP_ARR_WGT_LABEL_LEFT); argv[l_idx].label_txt = "http://heroine.linuxbox.com/toys.html"; l_idx++; gap_arr_arg_init(&argv[l_idx], GAP_ARR_WGT_LABEL_LEFT); argv[l_idx].label_txt = "http://www.lokigames.com/development/download/smjpeg/xanim2801-loki090899.tar.gz"; l_idx++; gap_arr_arg_init(&argv[l_idx], GAP_ARR_WGT_LABEL_LEFT); argv[l_idx].label_txt = ""; l_idx++; gap_arr_arg_init(&argv[l_idx], GAP_ARR_WGT_LABEL_LEFT); argv[l_idx].label_txt = "2.)"; l_idx++; gap_arr_arg_init(&argv[l_idx], GAP_ARR_WGT_LABEL_LEFT); argv[l_idx].label_txt = _("if your xanim exporting edition is not in your PATH or is not named xanim\n" "you have to set environment variable GAP_XANIM_PROG\n" "to your xanim exporting program and restart gimp" ); l_idx++; gap_arr_arg_init(&argv[l_idx], GAP_ARR_WGT_LABEL_LEFT); argv[l_idx].label_txt = ""; l_idx++; gap_arr_arg_init(&argv[l_idx], GAP_ARR_WGT_LABEL_LEFT); argv[l_idx].label_txt = _("An error occurred while trying to call xanim:"); l_idx++; gap_arr_arg_init(&argv[l_idx], GAP_ARR_WGT_LABEL_LEFT); argv[l_idx].label_txt = "--------------------------------------------"; l_idx++; gap_arr_arg_init(&argv[l_idx], GAP_ARR_WGT_LABEL_LEFT); argv[l_idx].label_txt = errlist; l_idx++; /* the Action Button */ b_argv[0].but_txt = GTK_STOCK_CANCEL; b_argv[0].but_val = -1; b_argv[1].but_txt = GTK_STOCK_OK; b_argv[1].but_val = 0; l_rc = gap_arr_std_dialog(_("XANIM Information"), "", l_idx, argv, /* widget array */ 1, b_argv, /* button array */ -1); return (l_rc); } /* end p_xanim_info */ /* ============================================================================ * p_xanim_dialog * ============================================================================ */ static int p_xanim_dialog (gint32 *first_frame, gint32 *last_frame, char *filename, gint32 len_filename, char *basename, gint32 len_basename, GapXAnimFormats *Format, gint32 *extract_video, gint32 *extract_audio, gint32 *jpeg_quality, gint32 *autoload, gint32 *run_xanim_asynchron) { #define XADIALOG_NUM_ARGS 13 static GapArrArg argv[XADIALOG_NUM_ARGS]; static char *radio_args[3] = { "XCF", "PPM", "JPEG" }; gap_arr_arg_init(&argv[0], GAP_ARR_WGT_FILESEL); argv[0].label_txt = _("Video:"); argv[0].help_txt = _("Name of a videofile to read by xanim. " "Frames are extracted from the videofile " "and written to separate diskfiles. " "xanim exporting edition is required."); argv[0].text_buf_len = len_filename; argv[0].text_buf_ret = filename; argv[0].entry_width = 250; gap_arr_arg_init(&argv[1], GAP_ARR_WGT_INT_PAIR); argv[1].label_txt = _("From Frame:"); argv[1].help_txt = _("Framenumber of 1st frame to extract"); argv[1].constraint = FALSE; argv[1].int_min = 0; argv[1].int_max = 9999; argv[1].int_ret = 0; argv[1].umin = 0; argv[1].entry_width = 80; gap_arr_arg_init(&argv[2], GAP_ARR_WGT_INT_PAIR); argv[2].label_txt = _("To Frame:"); argv[2].help_txt = _("Framenumber of last frame to extract"); argv[2].constraint = FALSE; argv[2].int_min = 0; argv[2].int_max = 9999; argv[2].int_ret = 9999; argv[2].umin = 0; argv[2].entry_width = 80; gap_arr_arg_init(&argv[3], GAP_ARR_WGT_FILESEL); argv[3].label_txt = _("Framenames:"); argv[3].help_txt = _("Basename for the video frames to write on disk. " "Framenumber and extension is added."); argv[3].text_buf_len = len_basename; argv[3].text_buf_ret = basename; argv[3].entry_width = 250; gap_arr_arg_init(&argv[4], GAP_ARR_WGT_OPTIONMENU); argv[4].label_txt = _("Format"); argv[4].help_txt = _("Fileformat for the extracted video frames. " "(xcf is extracted as ppm and converted to xcf)"); argv[4].radio_argc = 3; argv[4].radio_argv = radio_args; argv[4].radio_ret = 0; gap_arr_arg_init(&argv[5], GAP_ARR_WGT_TOGGLE); argv[5].label_txt = _("Extract Frames"); argv[5].help_txt = _("Enable extraction of frames"); argv[5].int_ret = 1; gap_arr_arg_init(&argv[6], GAP_ARR_WGT_TOGGLE); argv[6].label_txt = _("Extract Audio"); argv[6].help_txt = _("Enable extraction of audio to raw audiofile. " "(frame range limits are ignored for audio)"); argv[6].int_ret = 0; gap_arr_arg_init(&argv[7], GAP_ARR_WGT_INT_PAIR); argv[7].label_txt = _("Jpeg Quality:"); argv[7].help_txt = _("Quality for resulting jpeg frames. " "(is ignored when other formats are used)"); argv[7].constraint = TRUE; argv[7].int_min = 0; argv[7].int_max = 100; argv[7].int_ret = 90; gap_arr_arg_init(&argv[8], GAP_ARR_WGT_LABEL); argv[8].label_txt = ""; gap_arr_arg_init(&argv[9], GAP_ARR_WGT_TOGGLE); argv[9].label_txt = _("Open"); argv[9].help_txt = _("Open the 1st one of the extracted frames"); argv[9].int_ret = 1; gap_arr_arg_init(&argv[10], GAP_ARR_WGT_TOGGLE); argv[10].label_txt = _("Run asynchronously"); argv[10].help_txt = _("Run xanim asynchronously and delete unwanted frames " "(out of the specified range) while xanim is still running"); argv[10].int_ret = 1; gap_arr_arg_init(&argv[11], GAP_ARR_WGT_LABEL_LEFT); argv[11].label_txt = _("\nWarning: xanim 2.80 is old unmaintained software\n" "and has only limited MPEG support.\n" "Most of the frames (type P and B) will be skipped."); gap_arr_arg_init(&argv[12], GAP_ARR_WGT_HELP_BUTTON); argv[12].help_id = GAP_XANIM_HELP_ID; if(TRUE == gap_arr_ok_cancel_dialog(_("Xanim based extraction (DEPRECATED)"), _("Select Frame Range"), XADIALOG_NUM_ARGS, argv)) { if(argv[1].int_ret < argv[2].int_ret ) { *first_frame = (long)(argv[1].int_ret); *last_frame = (long)(argv[2].int_ret); } else { *first_frame = (long)(argv[2].int_ret); *last_frame = (long)(argv[1].int_ret); } *Format = (GapXAnimFormats)(argv[4].int_ret); *extract_video = (long)(argv[5].int_ret); *extract_audio = (long)(argv[6].int_ret); *jpeg_quality = (long)(argv[7].int_ret); *autoload = (long)(argv[9].int_ret); *run_xanim_asynchron = (long)(argv[10].int_ret); return (0); /* OK */ } else { return -1; /* Cancel */ } } /* end p_xanim_dialog */ static gint p_overwrite_dialog(char *filename, gint overwrite_mode) { static GapArrButtonArg l_argv[3]; static GapArrArg argv[1]; if(gap_lib_file_exists(filename)) { if (overwrite_mode < 1) { l_argv[0].but_txt = _("Overwrite Frame"); l_argv[0].but_val = 0; l_argv[1].but_txt = _("Overwrite All"); l_argv[1].but_val = 1; l_argv[2].but_txt = GTK_STOCK_CANCEL; l_argv[2].but_val = -1; gap_arr_arg_init(&argv[0], GAP_ARR_WGT_LABEL); argv[0].label_txt = filename; return(gap_arr_std_dialog ( _("GAP Question"), _("File already exists"), 1, argv, 3, l_argv, -1)); } } return (overwrite_mode); } static void p_build_xanim_framename(char *framename, gint32 sizeof_framename, gint32 frame_nr, char *ext) { g_snprintf(framename, sizeof_framename, "%s%sframe%d.%s", global_xanim_input_dir, G_DIR_SEPARATOR_S, (int)frame_nr, ext); } static void p_build_gap_framename(char *framename, gint32 sizeof_framename, gint32 frame_nr, char *basename, char *ext) { g_snprintf(framename, sizeof_framename, "%s%06d.%s", basename, (int)frame_nr, ext); } static void p_dirname(char *fname) { int l_idx; l_idx = strlen(fname) -1; while(l_idx > 0) { if(fname[l_idx] == G_DIR_SEPARATOR) { fname[l_idx] = '\0'; return; } l_idx--; } *fname = '\0'; } static void p_init_xanim_global_name() { const gchar *l_env; gchar *l_ptr; l_env = g_getenv("GAP_XANIM_PROG"); /* use gimp_temp_name to find a writeable tempdir (used as xanim workingdir) */ if(global_xanim_working_dir) g_free(global_xanim_working_dir); /* cut off the filenamepart */ global_xanim_working_dir = gimp_temp_name(".txt"); for(l_ptr = global_xanim_working_dir + strlen(global_xanim_working_dir); l_ptr >= global_xanim_working_dir; l_ptr--) { if(*l_ptr == G_DIR_SEPARATOR) { *l_ptr = '\0'; break; } } if(global_xanim_input_dir) g_free(global_xanim_input_dir); global_xanim_input_dir = g_strdup_printf("%s%sinput", global_xanim_working_dir, G_DIR_SEPARATOR_S); if(l_env != NULL) { strcpy(global_xanim_prog, l_env); return; } strcpy(global_xanim_prog, "xanim"); /* default name */ } static int p_convert_frames(gint32 frame_from, gint32 frame_to, char *basename, char *ext, char *ext2) { GimpParam *return_vals; int nreturn_vals; gint32 l_tmp_image_id; char l_first_xa_frame[200]; int l_rc; l_rc = -1; /* load 1st one of those frames generated by xanim */ p_build_xanim_framename(l_first_xa_frame, sizeof(l_first_xa_frame), frame_from, ext); l_tmp_image_id = gap_lib_load_image(l_first_xa_frame); /* convert the xanim frames (from ppm) to xcf fileformat * (the gap module for range convert is not linked to the frontends * main program, therefore i call the convert procedure by PDB-interface) */ return_vals = gimp_run_procedure ("plug_in_gap_range_convert2", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, /* runmode */ GIMP_PDB_IMAGE, l_tmp_image_id, GIMP_PDB_DRAWABLE, 0, /* (unused) */ GIMP_PDB_INT32, frame_from, GIMP_PDB_INT32, frame_to, GIMP_PDB_INT32, 0, /* dont flatten */ GIMP_PDB_INT32, 4444, /* dest type (keep type) */ GIMP_PDB_INT32, 256, /* colors (unused) */ GIMP_PDB_INT32, 0, /* no dither (unused) */ GIMP_PDB_STRING, ext2, /* extension for dest. filetype */ GIMP_PDB_STRING, basename, /* basename for dest. filetype */ GIMP_PDB_INT32, 0, /* (unused) */ GIMP_PDB_INT32, 0, /* (unused) */ GIMP_PDB_INT32, 0, /* (unused) */ GIMP_PDB_STRING, "none", /* (unused) palettename */ GIMP_PDB_END); /* destroy the tmp image */ gimp_image_delete(l_tmp_image_id); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { l_rc = 0; /* OK */ } gimp_destroy_params (return_vals, nreturn_vals); return(l_rc); } static gint32 p_find_max_xanim_frame(gint32 from_nr, char *ext) { gint32 l_high; gint32 l_max_found; gint32 l_nr; gint32 l_delta; char l_frame[500]; l_nr = from_nr; l_max_found = 0; l_high = 100000; while(1 == 1) { p_build_xanim_framename(l_frame, sizeof(l_frame), l_nr, ext); if(gap_debug) printf("DEBUG find_MAX :%s\n", l_frame); if(gap_lib_file_exists(l_frame)) { l_max_found = l_nr; l_delta = (l_high - l_nr) / 2; if(l_delta == 0) { l_delta = 1; } l_nr = l_max_found + l_delta; } else { if(l_nr == from_nr) { return (-1); } /* no frames found */ if(l_nr < l_high) { l_high = l_nr; l_nr = l_max_found + 1; } else { return(l_max_found); } } } } /* end p_find_max_xanim_frame */ static int gap_lib_rename_frames(gint32 frame_from, gint32 frame_to, char *basename, char *ext) { gint32 l_use_mv; gint32 l_frame_nr; gint32 l_max_found; char l_src_frame[500]; char l_dst_frame[500]; gint l_overwrite_mode; if(gap_debug) printf("gap_lib_rename_frames:\n"); l_use_mv = TRUE; l_overwrite_mode = 0; l_max_found = p_find_max_xanim_frame (frame_from, ext); if(l_max_found < 0) { global_errlist = g_strdup_printf( _("can't find any extracted frames,\n%s\nmaybe xanim has failed or was cancelled"), l_src_frame); return(-1); } l_frame_nr = frame_from; while (l_frame_nr <= frame_to) { p_build_xanim_framename(l_src_frame, sizeof(l_src_frame), l_frame_nr, ext); p_build_gap_framename(l_dst_frame, sizeof(l_dst_frame), l_frame_nr, basename, ext); if(!gap_lib_file_exists(l_src_frame)) { break; /* srcfile not found, stop */ } if (strcmp(l_src_frame, l_dst_frame) != 0) { /* check overwrite if Destination frame already exsts */ l_overwrite_mode = p_overwrite_dialog(l_dst_frame, l_overwrite_mode); if (l_overwrite_mode < 0) { global_errlist = g_strdup_printf( _("frames are not extracted, because overwrite of %s was cancelled"), l_dst_frame); return(-1); } else { g_remove(l_dst_frame); if (gap_lib_file_exists(l_dst_frame)) { global_errlist = g_strdup_printf( _("failed to overwrite %s (check permissions ?)"), l_dst_frame); return(-1); } } if (l_use_mv) { g_rename(l_src_frame, l_dst_frame); } if (!gap_lib_file_exists(l_dst_frame)) { gap_lib_file_copy(l_src_frame, l_dst_frame); if (gap_lib_file_exists(l_dst_frame)) { l_use_mv = FALSE; /* if destination is on another device use copy-remove strategy */ g_remove(l_src_frame); } else { global_errlist = g_strdup_printf( _("failed to write %s (check permissions ?)"), l_dst_frame); return(-1); } } } l_frame_nr++; if(l_max_found > 0) gimp_progress_update ((gdouble)l_frame_nr / (gdouble)l_max_found); } return(0); } /* end gap_lib_rename_frames */ static void gap_lib_delete_frames(gint32 max_tries, gint32 frame_from, gint32 frame_to, char *ext) { /* this procedure is performed repeatedly while polling the xanim process * and after xanim process has (or was) terminated to clean up unwanted frames. */ gint32 l_tries; gint32 l_next_number; char l_framename[500]; if(gap_debug) printf("gap_lib_delete_frames: cleaning up unwanted frames (max=%d)\n", (int)max_tries); l_tries = 0; while ((global_delete_number < frame_from) && (l_tries < max_tries)) { l_next_number = global_delete_number + 1; p_build_xanim_framename(l_framename, sizeof(l_framename), l_next_number, ext); if (gap_lib_file_exists(l_framename)) { /* if xanim has already written the next frame * we can delete the previous (unwanted) frame now */ p_build_xanim_framename(l_framename, sizeof(l_framename), global_delete_number, ext); if(gap_debug) printf("delete frame: %s\n", l_framename); g_remove(l_framename); global_delete_number = l_next_number; } l_tries++; } } /* end gap_lib_delete_frames */ static void p_poll(pid_t xanim_pid, char *one_past_last_frame, gint32 frame_from, gint32 frame_to, char *ext) { /* loop as long as the Xanim Process is alive */ if(gap_debug) printf("poll started on xanim pid: %d\n", (int)xanim_pid); /* kill with signal 0 checks only if the process is alive (no signal is sent) * returns 0 if alive, 1 if no process with given pid found. */ while (0 == kill(xanim_pid, 0)) { usleep(100000); /* sleep 1 second, and let xanim write some frames */ if (gap_lib_file_exists(one_past_last_frame)) { /* if the last desired frame is written * we can stop (kill with signal 9) the xanim process. */ kill(xanim_pid, 9); break; } /* check for max unwanted frames and delete (upto 20 of them) */ gap_lib_delete_frames(20, frame_from, frame_to, ext); } if(gap_debug) printf("poll ended on xanim pid: %d\n", (int)xanim_pid); } /* end p_poll */ static int p_grep(char *pattern, char *file) { gint l_rc; gchar *l_cmd; l_cmd = g_strdup_printf("grep -c '%s' \"%s\" >/dev/null", pattern, file); l_rc = system(l_cmd); g_free(l_cmd); if (l_rc == 0) { return(0); /* pattern found */ } return(1); /* pattern NOT found */ } static gint p_check_xanim() { gint l_rc; gint l_grep_counter1; gint l_grep_counter2; gint l_grep_counter3; gchar *l_cmd; gchar *l_xanim_help_output; FILE *l_fp; l_xanim_help_output = gimp_temp_name(".xanim_help.stdout"); l_fp = g_fopen(l_xanim_help_output, "w+"); if (l_fp == NULL) { global_errlist = g_strdup_printf("no write permission for tempfile %s", l_xanim_help_output); return(10); } fprintf(l_fp, "dummy"); fclose(l_fp); /* execute xanim with -h option and * store its output in a file. */ l_cmd = g_strdup_printf("%s -h 2>&1 >>%s", global_xanim_prog, l_xanim_help_output); l_rc = system(l_cmd); if(gap_debug) printf("DEBUG: executed :%s\n Retcode: %d\n", l_cmd, (int)l_rc); g_free(l_cmd); if ((l_rc == 127) || (l_rc == (127 << 8))) { global_errlist = g_strdup_printf( _("could not execute %s (check if xanim is installed)"), global_xanim_prog ); return(10); } if(!gap_lib_file_exists(l_xanim_help_output)) { global_errlist = g_strdup_printf( _("%s does not look like xanim"), global_xanim_prog ); return(10); } /* check the help output of xanim (using grep) */ l_grep_counter1 = 0; /* l_grep_counter1 += p_grep("anim", l_xanim_help_output); */ /* check for the exporting options */ l_grep_counter2 = 0; l_grep_counter2 += p_grep("Ea", l_xanim_help_output); l_grep_counter2 += p_grep("Ee", l_xanim_help_output); l_grep_counter2 += p_grep("Eq", l_xanim_help_output); /* check for the loki version that is able to write single frames */ l_grep_counter3 = 0; l_grep_counter3 += p_grep("Write video to input/frameN.EXT", l_xanim_help_output); g_remove(l_xanim_help_output); g_free(l_xanim_help_output); if(l_grep_counter2 != 0) { global_errlist = g_strdup_printf( _("The xanim program on your system \"%s\"\ndoes not support the exporting options Ea, Ee, Eq"), global_xanim_prog ); return(10); } if(l_grep_counter3 != 0) { global_errlist = g_strdup_printf( _("The xanim program on your system \"%s\"\ndoes not support exporting of single frames"), global_xanim_prog ); return(10); } return (0); /* OK, xanim output looks like expected */ } /* end p_check_xanim */ static pid_t p_start_xanim_process(gint32 first_frame, gint32 last_frame, char *filename, GapXAnimFormats Format, gint32 extract_video, gint32 extract_audio, gint32 jpeg_quality , char *one_past_last_frame, gint32 run_xanim_asynchron) { gchar l_cmd[500]; gchar l_buf[40]; pid_t l_xanim_pid; int l_rc; FILE *l_fp; l_xanim_pid = -1; /* allocate and prepare args for the xanim call */ g_snprintf(l_cmd, sizeof(l_cmd), "cd %s;%s +f ", global_xanim_working_dir, global_xanim_prog); /* programname */ if (extract_audio) { strcat(l_cmd, "+Ea "); } if (extract_video) { strcat(l_cmd, "+v "); /* +v is verbose mode */ switch(Format) { case XAENC_PPMRAW: strcat(l_cmd, "+Ee "); break; case XAENC_JPEG: g_snprintf(l_buf, sizeof(l_buf), "+Eq%d ", (int)jpeg_quality); strcat(l_cmd, l_buf); break; default: strcat(l_cmd, "+Ee "); break; } /* additional option "Pause after N Frames" is used, * to stop xanim exporting frames beyond the requested limit */ if (run_xanim_asynchron) { g_snprintf(l_buf, sizeof(l_buf), "+Zp%d ", (int)(last_frame +1)); strcat(l_cmd, l_buf); } } /* add the videofilename as last parameter */ strcat(l_cmd, filename); if (run_xanim_asynchron) { gchar *l_xanim_startscript; gchar *l_xanim_pidfile; l_xanim_startscript = gimp_temp_name(".xanim_start.sh"); l_xanim_pidfile = gimp_temp_name(".xanim_pidfile.txt"); /* asynchron start */ g_remove(l_xanim_pidfile); /* generate a shellscript */ l_fp = g_fopen(l_xanim_startscript, "w+"); if (l_fp != NULL) { fprintf(l_fp, "#!/bin/sh\n"); /* fprintf(l_fp, "(%s ; touch %s) &\n" */ fprintf(l_fp, "%s & # ; touch %s) &\n" , l_cmd /* start xanim as background process */ , one_past_last_frame /* and create a dummy frame when xanim is done */ ); fprintf(l_fp, "XANIM_PID=$!\n"); fprintf(l_fp, "echo \"$XANIM_PID # XANIM_PID\"\n"); fprintf(l_fp, "echo \"$XANIM_PID # XANIM_PID\" > \"%s\"\n", l_xanim_pidfile); /* we pass the xanim pid in a file, * exitcodes are truncated to 8 bit * by the system call */ /* fprintf(l_fp, "exit $XANIM_PID\n"); */ fclose(l_fp); gap_file_chmod(l_xanim_startscript, GAP_FILE_MKDIR_MODE); } l_rc = system(l_xanim_startscript); l_fp = g_fopen(l_xanim_pidfile, "r"); if (l_fp != NULL) { fscanf(l_fp, "%d", &l_rc); fclose(l_fp); l_xanim_pid = (pid_t)l_rc; } g_remove(l_xanim_startscript); g_remove(l_xanim_pidfile); g_free(l_xanim_startscript); g_free(l_xanim_pidfile); if(gap_debug) printf("ASYNCHRON CALL: %s\nl_xanim_pid:%d\n", l_cmd, (int)l_xanim_pid); } else { /* synchron start (blocks until xanim process has finished */ l_rc = system(l_cmd); if ((l_rc & 0xff) == 0) l_xanim_pid = 0; else l_xanim_pid = -1; if(gap_debug) printf("SYNCHRON CALL: %s\nretcode:%d (%d)\n", l_cmd, (int)l_rc, (int)l_xanim_pid); } return(l_xanim_pid); } /* end p_start_xanim_process */ #ifdef THIS_IS_A_COMMENT_EXEC_DID_NOT_WORK_AND_LEAVES_A_ZOMBIE_PROCESS static pid_t p_start_xanim_process_exec(gint32 first_frame, gint32 last_frame, char *filename, GapXAnimFormats Format, gint32 extract_video, gint32 extract_audio, gint32 jpeg_quality ) { char *args[20]; char l_buf[40]; int l_idx; pid_t l_xanim_pid; /* allocate and prepare args for the xanim call */ l_idx = 0; args[l_idx] = g_strdup(global_xanim_prog); /* programname */ l_idx++; args[l_idx] = g_strdup("+f"); if (extract_audio) { l_idx++; args[l_idx] = g_strdup("+Ea"); } if (extract_video) { l_idx++; args[l_idx] = g_strdup("+v"); /* +v is verbose mode */ l_idx++; switch(Format) { case XAENC_PPMRAW: args[l_idx] = g_strdup("+Ee"); break; case XAENC_JPEG: g_snprintf(l_buf, sizeof(l_buf), "+Eq%d", (int)jpeg_quality); args[l_idx] = g_strdup(l_buf); break; default: args[l_idx] = g_strdup("+Ee"); break; } /* additional option "Pause after N Frames" is used, * to stop xanim exporting frames beyond the requested limit */ l_idx++; g_snprintf(l_buf, sizeof(l_buf), "+Zp%d", (int)(last_frame +1)); args[l_idx] = g_strdup(l_buf); } /* add the videofilename as last parameter */ l_idx++; args[l_idx] = g_strdup(filename); l_idx++; args[l_idx] = NULL; /* terminate args list with a NULL pointer */ l_xanim_pid = fork(); if(l_xanim_pid == 0) { /* here we are in the forked child process * execute xanim */ execvp(args[0], args); /* this point should never be reached */ _exit (1); } return(l_xanim_pid); } /* end p_start_xanim_process */ #endif /* ============================================================================ * gap_xanim_decode * ============================================================================ */ gint32 gap_xanim_decode(GimpRunMode run_mode) { gint32 l_rc; gint32 first_frame; gint32 last_frame; char filename[200]; char basename[200]; char extension[20]; char extension2[20]; GapXAnimFormats Format; gint32 extract_audio; gint32 extract_video; gint32 jpeg_quality; gint32 autoload; gint32 run_xanim_asynchron; char l_cmd[300]; char l_one_past_last_frame[200]; char l_first_to_laod[200]; char *l_dst_dir; pid_t l_xanim_pid; int l_input_dir_created_by_myself; l_rc = 0; l_input_dir_created_by_myself = FALSE; global_errlist = NULL; p_init_xanim_global_name(); filename[0] = '\0'; strcpy(&basename[0], "frame_"); l_rc = p_xanim_dialog (&first_frame, &last_frame, filename, sizeof(filename), basename, sizeof(basename), &Format, &extract_video, &extract_audio, &jpeg_quality, &autoload, &run_xanim_asynchron); if(l_rc != 0) { return(l_rc); } if(!gap_lib_file_exists(filename)) { global_errlist = g_strdup_printf( _("videofile %s not existent or empty\n"), filename); l_rc = 10; } else { l_rc = p_check_xanim(); } if (l_rc == 0) { switch(Format) { case XAENC_PPMRAW: strcpy(extension, "ppm"); strcpy(extension2, ".ppm"); break; case XAENC_JPEG: strcpy(extension, "jpg"); strcpy(extension2, ".jpg"); break; default: strcpy(extension, "ppm"); strcpy(extension2, ".xcf"); break; } p_build_xanim_framename(l_one_past_last_frame, sizeof(l_one_past_last_frame), last_frame +1 , extension); if (extract_video) { /* for the frames we need a directory named "input" */ if (g_file_test(global_xanim_input_dir, G_FILE_TEST_IS_DIR)) { /* the input directory already exists, * remove frames */ g_snprintf(l_cmd, sizeof(l_cmd), "rm -f %s%s*.%s", global_xanim_input_dir, G_DIR_SEPARATOR_S, extension); system(l_cmd); } else { /* create input directory (needed by xanim to store the frames) */ gap_file_mkdir(global_xanim_input_dir, GAP_FILE_MKDIR_MODE); if (g_file_test(global_xanim_input_dir, G_FILE_TEST_IS_DIR)) { l_input_dir_created_by_myself = TRUE; } else { global_errlist = g_strdup_printf( _("could not create %s directory\n" "(that is required for xanim frame export)"), global_xanim_input_dir); l_rc = 10; } } } } if(l_rc == 0) { gimp_progress_init (_("Extracting frames...")); gimp_progress_update (0.1); /* fake some progress */ /* note: * we can't show realistic progress for the extracting process * because we know nothing about videofileformat and how much frames * are realy stored in the videofile. * * one guess could assume, that xanim will write 0 upto last_frame * to disk, and check for the frames that the xanim process creates. * The periodically checking can be done in the poll procedure for asynchron * startmode only. */ l_xanim_pid = p_start_xanim_process(first_frame, last_frame, filename, Format, extract_video, extract_audio, jpeg_quality, l_one_past_last_frame, run_xanim_asynchron); if (l_xanim_pid == -1 ) { global_errlist = g_strdup_printf( _("could not start xanim process\n(program=%s)"), global_xanim_prog ); l_rc = -1; } } if(l_rc == 0) { if(run_xanim_asynchron) { p_poll(l_xanim_pid, l_one_past_last_frame, first_frame, last_frame, extension); } gap_lib_delete_frames(99999, first_frame, last_frame, extension); g_remove(l_one_past_last_frame); gimp_progress_update (1.0); if (p_find_max_xanim_frame (first_frame, extension) < first_frame) { global_errlist = g_strdup_printf( _("can't find any extracted frames,\n" "xanim has failed or was cancelled")); l_rc = -1; } else { /* if destination directorypart does not exist, try to create it */ l_dst_dir = g_strdup(basename); p_dirname(l_dst_dir); if (*l_dst_dir != '\0') { if ( !g_file_test(l_dst_dir, G_FILE_TEST_IS_DIR) ) { gap_file_mkdir (l_dst_dir, GAP_FILE_MKDIR_MODE); } } if(strcmp(extension, &extension2[1]) == 0) { gimp_progress_init (_("Renaming frames...")); l_rc = gap_lib_rename_frames(first_frame, last_frame, basename, extension); } else { gimp_progress_init (_("Converting frames...")); l_rc = p_convert_frames(first_frame, last_frame, basename, extension, extension2); } if (l_input_dir_created_by_myself) { if (strcmp(l_dst_dir, global_xanim_input_dir) != 0) { /* remove input dir with all files */ g_snprintf(l_cmd, sizeof(l_cmd), "rm -rf \"%s\"", global_xanim_input_dir); system(l_cmd); } } g_free(l_dst_dir); gimp_progress_update (1.0); } } if(l_rc != 0) { if(global_errlist == NULL) { p_xanim_info("ERROR: could not execute xanim"); } else { p_xanim_info(global_errlist); } l_rc = -1; } else { if(autoload) { /* load first frame and add a display */ p_build_gap_framename(l_first_to_laod, sizeof(l_first_to_laod), first_frame, basename, &extension2[1]); l_rc = gap_lib_load_image(l_first_to_laod); if(l_rc >= 0) gimp_display_new(l_rc); } } return(l_rc); } /* end gap_xanim_decode */ gimp-gap-2.6.0+dfsg.orig/gap/gap_stock.c0000644000175000017500000001426611212030253017643 0ustar thibautthibaut/* * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * * Copyright (C) 1997 Andy Thomas * 2003 Sven Neumann * * 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. */ /* revision history: * gimp 1.3.20d; 2003/10/06 hof: added new icon gap_grab_points * gimp 1.3.14c; 2003/06/09 hof: bugfix: gap_stock_init must set initialized = TRUE; to avoid double init problems * GAP_STOCK_PLAY_REVERSE, GAP_STOCK_PAUSE */ #include "config.h" #include #include "gap_stock.h" #include "gap-intl.h" #include "images/gap-stock-pixbufs.h" static GtkIconFactory *gap_icon_factory = NULL; static GtkStockItem gap_stock_items[] = { { GAP_STOCK_ADD_POINT , N_("Add Point"), 0, 0, NULL }, { GAP_STOCK_ANIM_PREVIEW , N_("Anim Preview"), 0, 0, NULL }, { GAP_STOCK_DELETE_ALL_POINTS , N_("Delete All Points"), 0, 0, NULL }, { GAP_STOCK_DELETE_POINT , N_("Delete Point"), 0, 0, NULL }, { GAP_STOCK_FIRST_POINT , N_("First Point"), 0, 0, NULL }, { GAP_STOCK_GRAB_POINTS , N_("Grab Path"), 0, 0, NULL }, { GAP_STOCK_INSERT_POINT , N_("Insert Point"), 0, 0, NULL }, { GAP_STOCK_LAST_POINT , N_("Last Point"), 0, 0, NULL }, { GAP_STOCK_NEXT_POINT , N_("Next Point"), 0, 0, NULL }, { GAP_STOCK_PAUSE , NULL, 0, 0, NULL }, { GAP_STOCK_PLAY , NULL, 0, 0, NULL }, { GAP_STOCK_PLAY_REVERSE , NULL, 0, 0, NULL }, { GAP_STOCK_PREV_POINT , N_("Prev Point"), 0, 0, NULL }, { GAP_STOCK_RESET_ALL_POINTS , N_("Reset All Points"), 0, 0, NULL }, { GAP_STOCK_RESET_POINT , N_("Reset Point"), 0, 0, NULL }, { GAP_STOCK_ROTATE_FOLLOW , N_("Rotate Follow"), 0, 0, NULL }, { GAP_STOCK_SOURCE_IMAGE , NULL, 0, 0, NULL }, { GAP_STOCK_STEPMODE , NULL, 0, 0, NULL }, { GAP_STOCK_UPDATE , NULL, 0, 0, NULL }, { GAP_STOCK_RANGE_END , NULL, 0, 0, NULL }, { GAP_STOCK_RANGE_START , NULL, 0, 0, NULL }, { GAP_STOCK_SET_RANGE_END , NULL, 0, 0, NULL }, { GAP_STOCK_SET_RANGE_START , NULL, 0, 0, NULL }, { GAP_STOCK_SPEED , NULL, 0, 0, NULL } }; static void add_stock_icon (const gchar *stock_id, GtkIconSize size, const guint8 *inline_data) { GtkIconSource *source; GtkIconSet *set; GdkPixbuf *pixbuf; source = gtk_icon_source_new (); gtk_icon_source_set_size (source, size); gtk_icon_source_set_size_wildcarded (source, FALSE); pixbuf = gdk_pixbuf_new_from_inline (-1, inline_data, FALSE, NULL); gtk_icon_source_set_pixbuf (source, pixbuf); g_object_unref (pixbuf); set = gtk_icon_set_new (); gtk_icon_set_add_source (set, source); gtk_icon_source_free (source); gtk_icon_factory_add (gap_icon_factory, stock_id, set); gtk_icon_set_unref (set); } void gap_stock_init (void) { static gboolean initialized = FALSE; if (initialized) return; gap_icon_factory = gtk_icon_factory_new (); add_stock_icon (GAP_STOCK_ADD_POINT , GTK_ICON_SIZE_BUTTON, gap_add_point); add_stock_icon (GAP_STOCK_ANIM_PREVIEW , GTK_ICON_SIZE_BUTTON, gap_anim_preview); add_stock_icon (GAP_STOCK_DELETE_ALL_POINTS , GTK_ICON_SIZE_BUTTON, gap_delete_all_points); add_stock_icon (GAP_STOCK_DELETE_POINT , GTK_ICON_SIZE_BUTTON, gap_delete_point); add_stock_icon (GAP_STOCK_FIRST_POINT , GTK_ICON_SIZE_BUTTON, gap_first_point); add_stock_icon (GAP_STOCK_GRAB_POINTS , GTK_ICON_SIZE_BUTTON, gap_grab_points); add_stock_icon (GAP_STOCK_INSERT_POINT , GTK_ICON_SIZE_BUTTON, gap_insert_point); add_stock_icon (GAP_STOCK_LAST_POINT , GTK_ICON_SIZE_BUTTON, gap_last_point); add_stock_icon (GAP_STOCK_NEXT_POINT , GTK_ICON_SIZE_BUTTON, gap_next_point); add_stock_icon (GAP_STOCK_PAUSE , GTK_ICON_SIZE_BUTTON, gap_pause); add_stock_icon (GAP_STOCK_PLAY , GTK_ICON_SIZE_BUTTON, gap_play); add_stock_icon (GAP_STOCK_PLAY_REVERSE , GTK_ICON_SIZE_BUTTON, gap_play_reverse); add_stock_icon (GAP_STOCK_PREV_POINT , GTK_ICON_SIZE_BUTTON, gap_prev_point); add_stock_icon (GAP_STOCK_RESET_ALL_POINTS , GTK_ICON_SIZE_BUTTON, gap_reset_all_points); add_stock_icon (GAP_STOCK_RESET_POINT , GTK_ICON_SIZE_BUTTON, gap_reset_point); add_stock_icon (GAP_STOCK_ROTATE_FOLLOW , GTK_ICON_SIZE_BUTTON, gap_rotate_follow); add_stock_icon (GAP_STOCK_SOURCE_IMAGE , GTK_ICON_SIZE_BUTTON, gap_source_image); add_stock_icon (GAP_STOCK_STEPMODE , GTK_ICON_SIZE_BUTTON, gap_stepmode); add_stock_icon (GAP_STOCK_UPDATE , GTK_ICON_SIZE_BUTTON, gap_update); add_stock_icon ( GAP_STOCK_RANGE_END , GTK_ICON_SIZE_BUTTON, gap_range_end); add_stock_icon ( GAP_STOCK_RANGE_START , GTK_ICON_SIZE_BUTTON, gap_range_start); add_stock_icon ( GAP_STOCK_SET_RANGE_END , GTK_ICON_SIZE_BUTTON, gap_set_range_end); add_stock_icon ( GAP_STOCK_SET_RANGE_START , GTK_ICON_SIZE_BUTTON, gap_set_range_start); add_stock_icon ( GAP_STOCK_SPEED , GTK_ICON_SIZE_BUTTON, gap_speed); gtk_icon_factory_add_default (gap_icon_factory); gtk_stock_add_static (gap_stock_items, G_N_ELEMENTS (gap_stock_items)); initialized = TRUE; } gimp-gap-2.6.0+dfsg.orig/gap/gap_timeconv.c0000644000175000017500000001036711212030253020342 0ustar thibautthibaut/* gap_timeconv.c * * This module handles conversions framenumber/Rate --> timestring (mm:ss:msec) */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.19a; 2003/09/06 hof: added more converter procedures for audio * version 1.3.14c; 2003/06/14 hof: created */ #include "config.h" #include #include "libgimp/gimp.h" #include "gap_timeconv.h" #include "gap-intl.h" /* ------------------------------- * gap_timeconv_msecs_to_timestr * ------------------------------- * convert Input milliseconds value * into time string formated as mm:ss:msec * (minutes:seconds:milliseconds) * * the caller must provide a pointer to txt buffer * where the output is written into at txt_size. * * the txt buffer size should be at last 12 bytes */ void gap_timeconv_msecs_to_timestr(gint32 tmsec, gchar *txt, gint txt_size) { gint32 tms; gint32 tsec; gint32 tmin; tms = tmsec % 1000; tsec = (tmsec / 1000) % 60; tmin = tmsec / 60000; g_snprintf(txt, txt_size,"%02d:%02d:%03d" , (int)tmin, (int)tsec, (int)tms); } /* end gap_timeconv_msecs_to_timestr */ /* ------------------------------- * gap_timeconv_framenr_to_timestr * ------------------------------- * convert Input framenumber and framerate unit frames/sec) * into time string formated as mm:ss:msec * (minutes:seconds:milliseconds) * * the caller must provide a pointer to txt buffer * where the output is written into at txt_size. * * the txt buffer size should be at last 12 bytes */ void gap_timeconv_framenr_to_timestr( gint32 framenr, gdouble framerate, gchar *txt, gint txt_size) { gdouble msec_per_frame; gint32 tmsec; if(framerate > 0) { msec_per_frame = 1000.0 / framerate; } else { msec_per_frame = 1000.0; } if(framenr >= 0) { tmsec = framenr * msec_per_frame; gap_timeconv_msecs_to_timestr (tmsec, txt, txt_size); } else { g_snprintf(txt, txt_size, "??:??:???"); } } /* end gap_timeconv_framenr_to_timestr */ /* ------------------------------- * gap_timeconv_samples_to_timestr * ------------------------------- * convert Input samples at given samplerate (unit is samples/sec) * into time string formated as mm:ss:msec * (minutes:seconds:milliseconds) * * the caller must provide a pointer to txt buffer * where the output is written into at txt_size. * * the txt buffer size should be at last 12 bytes */ void gap_timeconv_samples_to_timestr( gint32 samples, gdouble samplerate, gchar *txt, gint txt_size) { gdouble tmsec; if(samplerate > 0) { tmsec = (1000.0 * (gdouble)samples) / samplerate; } else { tmsec = (1000.0 * (gdouble)samples) / 44100; } gap_timeconv_msecs_to_timestr ((gint32)tmsec, txt, txt_size); } /* end gap_timeconv_samples_to_timestr */ /* ------------------------------- * gap_timeconv_samples_to_frames * ------------------------------- * convert Input samples at given samplerate (unit is samples/sec) * and given framerate unit frames/sec) * to audioframes. (== number of frames that have to be played at framerate * to get the same duration as samples played at samplerate) * returns the number of audioframes */ gdouble gap_timeconv_samples_to_frames( gint32 samples, gdouble samplerate, gdouble framerate) { gdouble secs; gdouble frames; if((samplerate < 1) || (framerate < 1)) { return (0); } secs = (gdouble)samples / samplerate; frames = secs * framerate; return(frames); } /* end gap_timeconv_samples_to_frames */ gimp-gap-2.6.0+dfsg.orig/gap/gap_decode_mplayer.h0000644000175000017500000000535411212030253021477 0ustar thibautthibaut/* gap_decode_mplayer.h * 2004.12.06 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * Call mplayer * To split any mplayer supported video into * video frames (single images on disk) * Audio Tracks can also be extracted. * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp-gap 2.1; 2004/12/06 hof: created */ #ifndef _GAP_MPLAYER_H #define _GAP_MPLAYER_H #include "libgimp/gimp.h" #define GAP_MPLAYER_HELP_ID "plug-in-gap-mplayer-decode" #define GAP_MPLAYER_PLUGIN_NAME "plug_in_gap_mplayer_decode" #define GAP_MPLAYER_PLUGIN_NAME_TOOLBOX "plug_in_gap_mplayer_decode_toolbox" typedef enum { MPENC_XCF /* no direct support by mplayer, have to convert */ , MPENC_PNG , MPENC_JPEG } GapMPlayerFormats; typedef struct GapMPlayerParams /* nick: gpp */ { GimpRunMode run_mode; gint32 start_hour; gint32 start_minute; gint32 start_second; gint32 number_of_frames; char video_filename[1024]; char audio_filename[1024]; char basename[1024]; GapMPlayerFormats img_format; gint32 vtrack; /* 0 no video, 1 upto n: track number */ gint32 atrack; /* 0 no audio, 1 upto n: track number */ gint32 jpg_quality; /* 0 upto 100 (100 is best) */ gint32 jpg_optimize; /* 0 upto 100 */ gint32 jpg_smooth; /* 0 upto 100 */ gboolean jpg_progressive; gboolean jpg_baseline; gint32 png_compression; /* 0 upto 9 (9 max_compression) */ gboolean silent; gboolean autoload; gboolean run_mplayer_asynchron; gchar *mplayer_prog; gchar *mplayer_working_dir; gboolean use_old_mplayer1_syntax; } GapMPlayerParams; gint32 gap_mplayer_decode(GapMPlayerParams *gpp); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_pview_da.h0000644000175000017500000001160511212030253020315 0ustar thibautthibaut/* gap_pview_da.h * * This module handles GAP preview rendering from thumbnail data buffer * used for video playback preview */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.26a; 2004/01/30 hof: added gap_pview_drop_repaint_buffers * version 1.3.25a; 2004/01/21 hof: added gap_pview_render_from_pixbuf * version 1.3.16a; 2003/06/27 hof: use aspect_frame instead of simple frame, added gap_pview_render_default_icon * version 1.3.14c; 2003/06/12 hof: created */ #ifndef _GAP_PVIEW_H #define _GAP_PVIEW_H #include #include #include /* flip_request bits */ #define GAP_STB_FLIP_NONE 0 #define GAP_STB_FLIP_HOR 1 #define GAP_STB_FLIP_VER 2 #define GAP_STB_FLIP_BOTH 3 typedef struct GapPView { GtkWidget *da_widget; /* the preview drawing_area */ GtkWidget *aspect_frame; gint *src_col; /* Pointer array[pv_width] used for width scaling */ gint src_width; /* width of last handled src buffer */ gint src_bpp; /* byte per pixel of last handled src buffer */ gint src_rowstride; gint pv_width; /* Preview Width in pixels */ gint pv_height; /* Preview Height in pixels */ gint pv_bpp; /* BPP of the preview currently always 3 */ gint pv_check_size; /* size of the cheks in pixels */ gint32 flip_status; gboolean use_pixbuf_repaint; gboolean use_pixmap_repaint; guchar *pv_area_data; /* buffer to hold RGB image in preview size */ GdkPixmap *pixmap; /* alternative pixmap buffer */ GdkPixbuf *pixbuf; /* alternative pixbuf buffer */ gboolean desaturate_request; /* TRUE: render gray, FALSE render in color */ guchar *pv_desaturated_area_data; /* buffer to hold gray copy of image in preview size */ } GapPView; void gap_pview_render_f_from_pixbuf (GapPView *pv_ptr, GdkPixbuf *src_pixbuf , gint32 flip_request , gint32 flip_status ); gboolean gap_pview_render_f_from_buf (GapPView *pv_ptr , guchar *src_data , gint src_width , gint src_height , gint src_bpp , gboolean allow_grab_src_data , gint32 flip_request , gint32 flip_status ); void gap_pview_render_f_from_image_duplicate (GapPView *pv_ptr, gint32 image_id , gint32 flip_request , gint32 flip_status ); void gap_pview_render_f_from_image (GapPView *pv_ptr, gint32 image_id , gint32 flip_request , gint32 flip_status ); void gap_pview_render_from_pixbuf (GapPView *pv_ptr, GdkPixbuf *src_pixbuf); gboolean gap_pview_render_from_buf (GapPView *pv_ptr , guchar *src_data , gint src_width , gint src_height , gint src_bpp , gboolean allow_grab_src_data ); void gap_pview_render_from_image_duplicate (GapPView *pv_ptr, gint32 image_id); void gap_pview_render_from_image (GapPView *pv_ptr, gint32 image_id); void gap_pview_repaint(GapPView *pv_ptr); GapPView *gap_pview_new(gint pv_width, gint pv_height, gint pv_check_size, GtkWidget *frame); void gap_pview_set_size(GapPView *pv_ptr, gint pv_width, gint pv_height, gint pv_check_size); void gap_pview_reset(GapPView *pv_ptr); void gap_pview_drop_repaint_buffers(GapPView *pv_ptr); void gap_pview_render_default_icon(GapPView *pv_ptr); GdkPixbuf *gap_pview_get_repaint_pixbuf(GapPView *pv_ptr); guchar * gap_pview_get_repaint_thdata(GapPView *pv_ptr /* IN */ , gint32 *th_size /* OUT */ , gint32 *th_width /* OUT */ , gint32 *th_height /* OUT */ , gint32 *th_bpp /* OUT */ , gboolean *th_has_alpha /* OUT */ ); #endif gimp-gap-2.6.0+dfsg.orig/gap/sel-to-anim-img.scm0000644000175000017500000001200311212030253021113 0ustar thibautthibaut; The GIMP -- an image manipulation program ; Copyright (C) 1995 Spencer Kimball and Peter Mattis ; ; Selection to AnimationImage ; This script requires plug-in-gap-layers-run-animfilter (that is part of ; the gap Plugin-collection, available in the plugin registry) ; ; - 26.5.1999 hof: adapted for GIMP 1.1 Plug-in Interfaces ; - Takes the Current selection and saves it n-times (as multiple layers) in one separate image. ; (base functions taken from Selection to Image ((c) by Adrian Likins adrian@gimp.org) ; - added number of copies and ; - optional { BG-FILL | TRANS-FILL } ; - if there was no selection at begin the selection is cleared at end ; - optional call of plug-in-gap-layers-run-animfilter ; (to create animation effects by applying any available PDB filter foreach copy ; (==layer) of the generated image ; with constant or varying values) ; - if we just copied some layers set the generated brush-image clean at end ; ; 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., 675 Mass Ave, Cambridge, MA 02139, USA. (define (script-fu-selection-to-anim-image image drawable copies bgfill filter-all) (let* ( (idx 0) (draw-type (car (gimp-drawable-type-with-alpha drawable))) (image-type (car (gimp-image-base-type image))) (old-bg (car (gimp-context-get-background))) (selection-bounds (gimp-selection-bounds image)) (select-offset-x (cadr selection-bounds)) (select-offset-y (caddr selection-bounds)) (selection-width (- (cadr (cddr selection-bounds)) select-offset-x)) (selection-height (- (caddr (cddr selection-bounds)) select-offset-y)) (active-selection 0) (from-selection 0) (brush-draw 0) (draw-name "") (brush-image 0) ) (gimp-image-undo-disable image) (if (= (car (gimp-selection-is-empty image)) TRUE) (begin ; if the layer has no alpha select all (if (= (car (gimp-drawable-has-alpha drawable)) FALSE) (begin (gimp-selection-all image) ) (begin (gimp-selection-layer-alpha drawable) ) ) (set! active-selection (car (gimp-selection-save image))) (set! from-selection FALSE) ) (begin (set! active-selection (car (gimp-selection-save image))) (set! from-selection TRUE) ) ) (gimp-edit-copy drawable) (set! brush-image (car (gimp-image-new selection-width selection-height image-type))) (while (< idx copies) (set! draw-name (string-append "frame_0" (number->string idx))) (set! brush-draw (car (gimp-layer-new brush-image selection-width selection-height draw-type draw-name 100 NORMAL))) (gimp-image-add-layer brush-image brush-draw 0) (if (= bgfill TRUE) (gimp-drawable-fill brush-draw BG-IMAGE-FILL) (gimp-drawable-fill brush-draw TRANS-IMAGE-FILL) ) (let ((floating-sel (car (gimp-edit-paste brush-draw FALSE)))) (gimp-floating-sel-anchor floating-sel) ) (set! idx (+ idx 1)) ) (if (= from-selection FALSE) (gimp-selection-none image) ) (gimp-context-set-background old-bg) (gimp-image-undo-enable image) (gimp-image-set-active-layer image drawable) (gimp-image-clean-all brush-image) (gimp-display-new brush-image) (gimp-displays-flush) (if (= filter-all TRUE) ; INTERACTIVE animated call of any other plugin ; (drawable and plugin name are dummy parameters ; the plug-in to run is selcted by the built in PDB-browserdialog ; of plug-in-gap-layers-run-animfilter) (plug-in-gap-layers-run-animfilter 0 brush-image brush-draw "plug-in-bend" 1) ) ) ) (script-fu-register "script-fu-selection-to-anim-image" _"/Script-Fu/Animators/Selection to AnimImage..." "Create a multilayer image from current selection and apply any PDB Filter to all layer-copies" "Wolfgang Hofer " "Wolfgang Hofer" "2006/05/01" "RGB RGBA GRAY GRAYA" SF-IMAGE "Image" 0 SF-DRAWABLE "Drawable" 0 SF-ADJUSTMENT _"Number of Copies" '(10 1 1024 1 10 0 1) SF-TOGGLE _"Fill with BG Color" TRUE SF-TOGGLE _"Anim-Filter for all Copies" TRUE) gimp-gap-2.6.0+dfsg.orig/gap/gap_audio_wav.c0000644000175000017500000004640011212030253020471 0ustar thibautthibaut/* gap_audio_wav.c * * GAP tool procedures * for RIFF WAVE format audiofile handling. * */ /* * 2004.04.10 hof - created * */ #include #include "sys/types.h" #include "sys/stat.h" #include "unistd.h" #include #include "stdlib.h" #include #include "gap_libgapbase.h" #include "libgimp/gimp.h" #include "gap-intl.h" #include "gap_audio_wav.h" extern int gap_debug; #define MAX_AUDIO_STREAMS 16 typedef enum t_Playlist_Check_Retcodes { IS_VALID_PLAYLIST ,IS_ANY_PLAYLIST ,IS_NO_PLAYLIST } t_Playlist_Check_Retcodes; /* if G_BYTE_ORDER == G_BIG_ENDIAN */ #if G_BYTE_ORDER == G_LITTLE_ENDIAN typedef union t_wav_16bit_int { gint16 value; guint16 uvalue; struct { guchar lsb; guchar msb; } bytes; } t_wav_16bit_int; typedef union t_wav_32bit_int { gint32 value; guint32 uvalue; struct { guchar b0; /* lsb */ guchar b1; guchar b2; guchar b3; /* msb */ } bytes; } t_wav_32bit_int; #else typedef union t_wav_16bit_int { gint16 value; struct { guchar msb; guchar lsb; } bytes; } t_wav_16bit_int; typedef union t_wav_32bit_int { gint32 value; struct { guchar b3; /* msb */ guchar b2; guchar b1; guchar b0; /* lsb */ } bytes; } t_wav_32bit_int; #endif void p_check_errno() { gint l_errno; l_errno = errno; if(l_errno != 0) { g_message(_("Problem while writing audiofile: %s") ,g_strerror (l_errno) ); printf("gap_audio_wav errno:%d %s\n", l_errno, g_strerror (l_errno)); exit (-1); } } void gap_audio_wav_write_gint16(FILE *fp, gint16 val) { t_wav_16bit_int l_val; l_val.value = val; errno = 0; /* write 16bit sample to file (filedata has always lsb first) */ fputc((int)l_val.bytes.lsb, fp); fputc((int)l_val.bytes.msb, fp); p_check_errno(); } void gap_audio_wav_write_gint32(FILE *fp, gint32 val) { t_wav_32bit_int l_val; l_val.value = val; errno = 0; /* write 32bit integer to file (lsb first) */ fputc((int)l_val.bytes.b0, fp); fputc((int)l_val.bytes.b1, fp); fputc((int)l_val.bytes.b2, fp); fputc((int)l_val.bytes.b3, fp); p_check_errno(); } /* --------------------------------- * gap_audio_wav_write_header * --------------------------------- */ void gap_audio_wav_write_header(FILE *fp , gint32 nsamples , gint32 channels , gint32 samplerate , gint32 bytes_per_sample , gint32 bits ) { gint32 l_total_len; /* is the total filesize - 8 bytes (for RIFF keyword and 4 bytes lengthfield) */ gint32 l_data_len; gint32 l_fmt_len; gint16 l_format_tag; gint32 l_avg_bytes_per_sec; errno = 0; if(gap_debug) { printf("gap_audio_wav_write_header: START fp:%d\n", (int)fp); } l_data_len = nsamples * bytes_per_sample; l_total_len = l_data_len + 36; l_fmt_len = 16; /* length of 'fmt ' chunk has fix length of 16 byte */ l_format_tag = 1; /* 1 is tag for PCM_WAVE_FORMAT */ l_avg_bytes_per_sec = samplerate * bytes_per_sample; /* 00 - 03 */ fprintf(fp, "RIFF"); /* 04 - 07 */ gap_audio_wav_write_gint32(fp, l_total_len); /* 08 - 15 */ fprintf(fp, "WAVEfmt "); /* 16 - 19 */ gap_audio_wav_write_gint32(fp, (gint32)l_fmt_len); /* 20 - 21 */ gap_audio_wav_write_gint16(fp, (gint16)l_format_tag); /* 22 - 23 */ gap_audio_wav_write_gint16(fp, (gint16)channels); /* 24 - 27 */ gap_audio_wav_write_gint32(fp, samplerate); /* 28 - 31 */ gap_audio_wav_write_gint32(fp, l_avg_bytes_per_sec); /* 32 - 33 */ gap_audio_wav_write_gint16(fp, (gint16)bytes_per_sample); /* 34 - 35 */ gap_audio_wav_write_gint16(fp, (gint16)bits); /* 36 - 39 */ fprintf(fp, "data"); /* 40 - 43 */ gap_audio_wav_write_gint32(fp, l_data_len); p_check_errno(); if(gap_debug) { printf("gap_audio_wav_write_header: DONE fp:%d\n", (int)fp); } } /* end gap_audio_wav_write_header */ /* ---------------------------- * p_wav_open_seek_data_private * ---------------------------- * Open a RIFF WAVE fmt file * check for RIFF WAVE header * and seek position to the 1.st data byte. * * return NULL on ERROR * FILE* filepointer to the opened audiofile */ static FILE * p_wav_open_seek_data_private(const char *filename, unsigned char *audata) { FILE *fp; struct stat l_stat_buf; size_t l_len_to_read; size_t l_len_read; /* get File Length */ if (0 != g_stat(filename, &l_stat_buf)) { if(gap_debug) { printf("p_wav_open_seek_data_private file:%s:\n file does not exist or size 0\n" , filename ); } /* stat error (file does not exist) */ return(NULL); } if (l_stat_buf.st_size < 48) { if(gap_debug) { printf("p_wav_open_seek_data_private file: %s\n file size < 48 byte\n" , filename ); } return(NULL); /* too short for WAVE file */ } fp = g_fopen(filename, "rb"); if(fp == NULL) { if(gap_debug) { printf("p_wav_open_seek_data_private file: %s\n open read binary failed\n" , filename ); } return(NULL); } l_len_to_read = 44; l_len_read = fread(&audata[0], 1, l_len_to_read, fp); if((audata[0] == 'R') /* check for RIFF identifier */ && (audata[1] == 'I') && (audata[2] == 'F') && (audata[3] == 'F') && (audata[8] == 'W') /* check for "WAVEfmt " chunk identifier */ && (audata[9] == 'A') && (audata[10] == 'V') && (audata[11] == 'E') && (audata[12] == 'f') && (audata[13] == 'm') && (audata[14] == 't') && (audata[15] == ' ')) { if((audata[36] == 'd') && (audata[37] == 'a') && (audata[38] == 't') && (audata[39] == 'a')) { /* OK, standard header is immedate followed by data chunk * no further searches needed anymore */ return(fp); } } else { if(gap_debug) { printf("check failed on file: %s\n The RIFFWAVEfmt header string was not found\n" , filename ); } fclose (fp); return(NULL); } /* searching for data chunk */ while (l_len_to_read == l_len_read) { if(gap_debug) { printf("chunkID: %c%c%c%c\n", audata[36], audata[37], audata[38], audata[39]); printf("chunkID(hex): %x %x %x %x\n", audata[36], audata[37], audata[38], audata[39]); } if((audata[36] == 'd') && (audata[37] == 'a') && (audata[38] == 't') && (audata[39] == 'a')) { return(fp); /* data chunk found, stop searching */ } /* skip unknown chunk(s) */ l_len_to_read = audata[40] + (256 * (long)audata[41]) + (65536 * (long)audata[42]) + (16777216 * (long)audata[43]); if(gap_debug) printf("skip length: %d\n", (int)l_len_to_read); if(l_len_to_read <= 0 || l_len_to_read > (size_t)l_stat_buf.st_size) { if(gap_debug) { printf("p_wav_open_seek_data_private file: %s\n l_len_to_read: %d not plausible\n" , filename , (int)l_len_to_read ); } break; /* chunk length contains nonsens, give up searching for data chunk */ } fseek(fp, l_len_to_read, SEEK_CUR); /* read next chunk header and length (4+4 bytes) */ l_len_to_read = 8; l_len_read = fread(&audata[36], 1, l_len_to_read, fp); } fclose(fp); return(NULL); } /* end p_wav_open_seek_data_private */ /* ---------------------------- * gap_audio_wav_open_seek_data * ---------------------------- */ FILE * gap_audio_wav_open_seek_data(const char *filename) { FILE *fp; unsigned char audata[60]; fp = p_wav_open_seek_data_private(filename, &audata[0]); return(fp); } /* end gap_audio_wav_open_seek_data */ /* ----------------------- * gap_audio_wav_file_check * ----------------------- * check file if it is a RIFF WAVE fmt file * and obtain the header informatains * return -1 on ERROR * 0 if OK */ int gap_audio_wav_file_check(const char *audfile, long *sample_rate, long *channels , long *bytes_per_sample, long *bits, long *samples) { /* note: this code is a quick hack and was inspired by a look at some * .wav files. It will work on many .wav files. * but it also may fail to identify some .wav files. */ FILE *fp; unsigned char audata[60]; long l_data_len; int l_rc; l_rc = -1; /* prepare retcode NOT OK */ /* open and check for RIFFWAVEfmt header chunk and for data chunk */ fp = p_wav_open_seek_data_private(audfile, &audata[0]); if(fp == NULL) { if(gap_debug) { printf ("p_audio_wav_file_check: open read or HDR and data chunk test failed on '%s'\n" , audfile ); } return(l_rc); } fclose(fp); /* get informations from the header chunk * (fetch was done in p_wav_open_seek_data_private) */ *sample_rate = audata[24] + (256 * (long)audata[25])+ (65536 * (long)audata[26]) + (16777216 * (long)audata[27]); *channels = audata[22] + (256 * (long)audata[23]); *bytes_per_sample = audata[32] + (256 * (long)audata[33]); *bits = audata[34] + (256 * (long)audata[35]); l_data_len = audata[40] + (256 * (long)audata[41]) + (65536 * (long)audata[42]) + (16777216 * (long)audata[43]); *samples = l_data_len / (*bits / 8); l_rc = 0; /* OK seems to be a WAVE file */ if(gap_debug) { printf ("p_audio_wav_file_check: WAVE FILE: %s\n", audfile); printf (" sample_rate: %d\n", (int)*sample_rate ); printf (" channels: %d\n", (int)*channels); printf (" bytes_per_sample: %d\n", (int)*bytes_per_sample ); printf (" bits: %d\n", (int) *bits); printf (" summary samples (all channels): %d\n", (int)*samples); printf (" l_data_len: %d\n", (int)l_data_len); } return l_rc; } /* end gap_audio_wav_file_check */ /* ----------------------- * gap_audio_wav_16bit_save * ----------------------- * check file if it is a RIFF WAVE fmt file * and obtain the header informatains * return -1 on ERROR * 0 if OK */ int gap_audio_wav_16bit_save(const char *wavfile , int channels , unsigned short *left_ptr , unsigned short *right_ptr , int samplerate , long total_samples ) { FILE *fp; gint32 l_bytes_per_sample; gint32 l_ii; if(channels == 1) { l_bytes_per_sample = 2;} /* mono */ else { l_bytes_per_sample = 4; channels = 2; } /* stereo */ fp = g_fopen(wavfile, "wb"); if (fp) { /* write the header */ gap_audio_wav_write_header(fp , (gint32)total_samples , channels /* cannels 1 or 2 */ , samplerate , l_bytes_per_sample , 16 /* 16 bit sample resolution */ ); /* write 16 bit wave datasamples * sequence mono: (lo, hi) * sequence stereo: (lo_left, hi_left, lo_right, hi_right) */ for(l_ii=0; l_ii < total_samples; l_ii++) { gap_audio_wav_write_gint16(fp, *left_ptr); left_ptr++; if(channels > 1) { gap_audio_wav_write_gint16(fp, *right_ptr); right_ptr++; } } fclose(fp); } return(0); /* OK */ } /* end gap_audio_wav_16bit_save */ /* -------------------------------- * p_check_for_valid_playlist * -------------------------------- * check if the file specified via audfile * is a valid audio playlist. Valis playlists are textfiles * containing filenames of RIFF WAVE formated audiofiles * of desired sample rate and 16 bits per channel. * playlist syntax is: * - one filename per line, without leading blanks * - empty lines are allowd * - lines starting with '#' are commentlines that are ignored */ static t_Playlist_Check_Retcodes p_check_for_valid_playlist(const char *audfile, long *sample_rate, long *channels , long *bytes_per_sample, long *bits, long *samples , long *all_playlist_references , long *valid_playlist_references , long desired_samplerate ) { t_Playlist_Check_Retcodes l_retval; long l_bytes_per_sample = 4; long l_sample_rate = 22050; long l_channels = 2; long l_bits = 16; long l_samples = 0; FILE *l_fp; char l_buf[4000]; char *referred_wavfile; gint ii; l_retval = IS_NO_PLAYLIST; referred_wavfile = NULL; l_channels = 0; *all_playlist_references = 0; /* check if audfile * is a playlist referring to more than one inputfile * and try to open those input wavefiles * (but limited upto MAX_AUDIO_STREAMS input wavefiles) */ if(gap_debug) { printf("p_check_for_valid_playlist: START checking file: %s\n", audfile); } ii = 0; l_fp = g_fopen(audfile, "r"); if(l_fp) { while(NULL != fgets(l_buf, sizeof(l_buf)-1, l_fp)) { if((l_buf[0] == '#') || (l_buf[0] == '\n') || (l_buf[0] == '\0')) { continue; /* skip comment lines, and empty lines */ } l_buf[sizeof(l_buf) -1] = '\0'; /* make sure we have a terminated string */ gap_file_chop_trailingspace_and_nl(&l_buf[0]); if(ii < MAX_AUDIO_STREAMS) { int l_rc; if(referred_wavfile) { g_free(referred_wavfile); } referred_wavfile = gap_file_make_abspath_filename(&l_buf[0], audfile); if(gap_debug) { printf("p_check_for_valid_playlist: checking reference file: %s\n", referred_wavfile); } l_rc = gap_audio_wav_file_check(referred_wavfile , &l_sample_rate , &l_channels , &l_bytes_per_sample , &l_bits , &l_samples ); if(gap_debug) { printf("REF-file: %s bits:%d (expected:%d) samplerate:%d (expected: %d) l_rc: %d\n" ,referred_wavfile ,(int)l_bits ,(int)16 ,(int)l_sample_rate ,(int)desired_samplerate ,(int)l_rc ); } if(l_rc == 0) { (*all_playlist_references)++; /* use audio informations from the 1.st valid referenced file for output * (or pick information of any other referenced audiofile * if we have no matching audio file reference) */ if(ii == 0) { *sample_rate = l_sample_rate; *channels = l_channels; *bytes_per_sample = l_bytes_per_sample; *bits = l_bits; *samples = l_samples; } if((l_bits == 16) && (l_sample_rate == desired_samplerate)) { /* we have found at least one reference to an audiofile * with matching bits and samplerate * therefore we consider audfile as valid playlist file */ ii++; l_retval = IS_VALID_PLAYLIST; } else { /* the file seems to be a play list * but the referenced file does not match desired parameters */ if(l_retval != IS_VALID_PLAYLIST) { l_retval = IS_ANY_PLAYLIST; } break; } } else { /* report unexpected content as warning, but only when * we have already identified that file as playlist * (otherwise checks on audiofiles would also * report such a warning that would confusing) */ if(ii > 0) { g_message(_("The file: %s\n" "has unexpect content that will be ignored.\n" "You should specify an audio file in RIFF WAVE fileformat,\n" "or a textfile containing filenames of such audio files") , audfile ); } break; } } else { g_message(_("The file: %s\n" "contains too many audio-input tracks\n" "(only %d tracks are used, the rest are ignored).") , audfile , (int) MAX_AUDIO_STREAMS ); break; } l_buf[0] = '\0'; } fclose(l_fp); } if(l_retval == IS_ANY_PLAYLIST) { g_message(_("The file: %s\n" "is an audio playlist, but contains references to audiofiles that\n" "do not match the desired sample rate of %d Hz\n" "or do not have 16 bits per sample") , audfile , (int)desired_samplerate ); } if(referred_wavfile) { g_free(referred_wavfile); } *valid_playlist_references = ii; return (l_retval); } /* end p_check_for_valid_playlist */ /* --------------------------------- * gap_audio_playlist_wav_file_check * --------------------------------- * check file if it is a RIFF WAVE fmt file * and obtain the header informatains * return -1 on ERROR (file is neither valid wavfile nor valid audio playlist) * return -2 ERROR, File is an audio playlist, but not usable (non matching bits or samplerate) * 0 if OK (valid WAV file or valid playlist) */ int gap_audio_playlist_wav_file_check(const char *audfile, long *sample_rate, long *channels , long *bytes_per_sample, long *bits, long *samples , long *all_playlist_references , long *valid_playlist_references , long desired_samplerate ) { int l_rc; /* check for WAV file, and get audio informations */ l_rc = gap_audio_wav_file_check(audfile , sample_rate , channels , bytes_per_sample , bits , samples ); if (l_rc ==0) { return 0; /* OK, audfile is a RIFF wavefile */ } else { t_Playlist_Check_Retcodes l_rc_playlistcheck; l_rc_playlistcheck = p_check_for_valid_playlist(audfile , sample_rate , channels , bytes_per_sample , bits , samples , all_playlist_references , valid_playlist_references , desired_samplerate ); switch(l_rc_playlistcheck) { case IS_VALID_PLAYLIST: if(gap_debug) { printf(": The file %s is a valid playlist\n", audfile); } return 0; break; case IS_ANY_PLAYLIST: if(gap_debug) { printf(": The file %s is a non matching playlist\n", audfile); } return -2; break; default: if(gap_debug) { printf(": The file %s is not a playlist\n", audfile); } break; } } return -1; } /* end gap_audio_playlist_wav_file_check */ gimp-gap-2.6.0+dfsg.orig/gap/TESTPROT_iter_ALT0000644000175000017500000002360311212030253020452 0ustar thibautthibautHere is a result List of the "Animated Filtercall" Tests. I tested all the listed PDB-Procedures that can be selected via the GAP's DB-Browser and the corresponding _iter_ALT Procedures on a 4-Layer Testimage with Menu. /Filter/Filter All Layers using "Apply Varying" Button --------------------------------------------------- Testresults -------------------------------------------------- 2009.01.18 TODO: check for new plug ins that were added to gimp-2.6 (and that are not yet in this List) Test with PDB-Procedures (Plugins) that came with gimp release 2.6.4 Test also includes PDB-Procedures provided by GIMP-GAP itself State: (Column1 test 2007.12.01, Column2 older testresult with gimp-2.2.x and old GIMP-GAP version) + ... Full Supported, and passed simple "Apply Varying" Test OK (78 procedures) # ... Partly Supported, Apply constant OK, but Apply Varying not possible or does not make sense (18 procedures) - ... NOT supported (Failed Test) : ... Not supported (support would make no sense) . ... not tested State Procedure/Iterator_ALT ame Testnotes --------------------------------------------------------------------------- ++ plug-in-alienmap2-iter-ALT : plug-in-align-layers : plug-in-animationoptimize : plug-in-animationoptimize-diff : plug-in-animationplay : plug-in-animationunoptimize ++ plug-in-apply-canvas-iter-ALT Uses wrong name "plug-in-struc" to store LAST_VAL's ++ plug-in-applylens-iter-ALT : plug-in-autocrop - plug-in-autocrop-layer constant apply would make sense, but did not work # plug-in-autostretch-hsv ++ plug-in-blinds-iter-ALT ++ plug-in-bluebox ## plug-in-blur has no dialog but works fine with defaults. o+ plug-in-borderaverage-iter-ALT (?) runs, but produces no effect on the processed layers ++ plug-in-bump-map-iter-ALT : plug-in-bump-map-tiled ## plug-in-c-astretch ++ plug-in-cartoon-iter-ALT : plug-in-ccanalyze ++ plug-in-checkerboard-iter-ALT ++ plug-in-cml-explorer-iter-ALT ## plug-in-color-adjust ## plug-in-color-enhance oo plug-in-color-map-iter-ALT ++ plug-in-colorify-iter-ALT ++ plug-in-colors-channel-mixer ++ plug-in-colortoalpha-iter-ALT : plug-in-compose ++ plug-in-convmatrix-iter-ALT ++ plug-in-cubism-iter-ALT ++ plug-in-curve-bend (curve-bend:8380): Gtk-WARNING **: GtkSpinButton: setting an adjustment with non-zero page size is deprecated : plug-in-decompose ## plug-in-deinterlace disabled the Iter_ALT proc (only const apply makes sense) ++ plug-in-depth-merge-iter-ALT (gimp-2.6:8143): GLib-GObject-CRITICAL **: g_value_get_enum: assertion `G_VALUE_HOLDS_ENUM (value)' failed ++ plug-in-despeckle-iter-ALT ++ plug-in-destripe-iter-ALT ++ plug-in-diffraction-iter-ALT ## plug-in-dilate (?) noninteractive variante of plug_in_vpropagate ++ plug-in-displace-iter-ALT ++ plug-in-dog : plug-in-drawable-compose ++ plug-in-edge-iter-ALT ++ plug-in-emboss-iter-ALT ++ plug-in-engrave-iter-ALT ## plug-in-erode (?) noninteractive variante of plug_in_vpropagate with default values ++ plug-in-exchange-iter-ALT : plug-in-film ## plug-in-filter-macro : plug-in-filter-pack makes no sense because opens Dialog even in run_mode: GIMP_RUN_WITH_LAST_VALS ++ plug-in-flame-iter-ALT (?) runs, but all layer were transparent when finished ++ plug-in-flarefx-iter-ALT ++ plug-in-fractal-trace-iter-ALT . plug-in-fractalexplorer ++ plug-in-gauss-iter-ALT : plug-in-gauss-iir2 makes no sense (no dialog), use plug_in_gauss instead : plug-in-gauss-iir makes no sense (no dialog), use plug_in_gauss instead : plug-in-gauss-rle2 makes no sense (no dialog), use plug_in_gauss instead : plug-in-gauss-rle makes no sense (no dialog), use plug_in_gauss instead : plug-in-gfig makes no sense (is INTERACTIVE only and creates layer) ++ plug-in-gflare-iter-ALT ++ plug-in-gimpressionist ++ plug-in-glasstile-iter-ALT ## plug-in-gradmap ++ plug-in-grid-iter-ALT : plug-in-guillotine ## plug-in-hot : plug-in-ifs-compose ++ plug-in-illusion-iter-ALT : plug-in-imagemap makes no sense (needs INTERACTIVE mode) : plug-in-iwarp makes no sense (needs INTERACTIVE mode, has its own animate option where layers are created) ++ plug-in-jigsaw-iter-ALT ## plug-in-laplace ++ plug-in-lic-iter-ALT ++ plug-in-lighting-iter-ALT : plug-in-mail-image ## plug-in-make-seamless HAS no dialog and no LAST_VAL Buffer ++ plug-in-map-object-iter-ALT ## plug-in-max-rgb-iter-ALT ++ plug-in-maze-iter-ALT ++ plug-in-mblur-iter-ALT ++ plug-in-mosaic-iter-ALT ++ plug-in-name2layer ++ plug-in-neon ++ plug-in-newsprint-iter-ALT ++ plug-in-nlfilt-iter-ALT (?) runs, but did not see any effect -- plug-in-noisify-iter-ALT noisify has 2 names and uses the 2.nd name "plug-in-rgb-noise" "plug_in_scatter_rgb" to store is values. (runs but does not open 2nd dialog even when varying requested ?) -o plug-in-hsv-noise register 2 names (old name plug-in-scatter-hsv) (runs but does not open 2nd dialog even when varying requested ?) ## plug-in-normalize has no dialog, constant apply makes sense ++ plug-in-nova-iter-ALT ++ plug-in-oilify-iter-ALT : plug-in-onionskin-create-or-replace : plug-in-onionskin-del : plug-in-onionskin-toggle-visibility (1) plug-in-pagecurl-iter-ALT ERROR: creates a new layer -o plug-in-papertile-iter-ALT FAILED with floating point exception ++ plug-in-photocopy ++ plug-in-pixelize-iter-ALT ## plug-in-pixelize2 ++ plug-in-plasma-iter-ALT ++ plug-in-polar-coords-iter-ALT ## plug-in-qbist ++ plug-in-randomize-hurl-iter-ALT ++ plug-in-randomize-pick-iter-ALT ++ plug-in-randomize-slur-iter-ALT ++ plug-in-retinex ++ plug-in-ripple-iter-ALT - plug-in-rotate-iter-ALT does not make sense (has no dialog where to specify rotation angle) : plug-in-rotate-colormap makes no sense, because opens Dialog even in run_mode: GIMP_RUN_WITH_LAST_VALS - plug-in-sample-colorize-iter-ALT (?) iter size ok, but does not work for GIMP_RUN_WITH_LAST_VALS calls ++ plug-in-sel-gauss-iter-ALT : plug-in-sel2path : plug-in-sel2path-advanced : plug-in-semiflatten makes no sense ++ plug-in-sharpen-iter-ALT ++ plug-in-shift-iter-ALT ++ plug-in-sinus-iter-ALT ++ plug-in-small-tiles-iter-ALT Uses wrong name "plug_in_tileit" to store LAST_VAL's : plug-in-smooth-palette makes no sense (creates palette) ++ plug-in-sobel-iter-ALT OK, but only constant apply makes sense ++ plug-in-softglow ++ plug-in-solid-noise-iter-ALT ++ plug-in-sparkle-iter-ALT : plug-in-spheredesigner ++ plug-in-spread-iter-ALT ++ plug-in-unsharp-mask-iter-ALT ## plug-in-video-iter-ALT varying values does not make sense, but keep iterator to get into gap_dbbrowser selection ## plug-in-vinvert-iter-ALT ++ plug-in-vpropagate-iter-ALT ++ plug-in-warp-iter-ALT ++ plug-in-waves-iter-ALT ++ plug-in-whirl-pinch-iter-ALT ++ plug-in-wind-iter-ALT ++ plug-in-wr-color-levels ++(2) plug-in-wr-curves - curves files are not compatible with gimp2.4 curves file ++ plug-in-wr-huesat ++ plug-in-wr-set-opacity : plug-in-zealouscrop Additional notes: (1) the pagecurl plugin fails when called via /Filters/Filter all Layers because it adds an extra layer for the curl to the image. pagecurl can be used as filter when called via /Video/Frames Modify when Function: "Apply filter on layers" is selected as action. From my point of view it does not make much sense in animations, because this plugin works with fixed curling amount. (2) This plugin works with curves files of the old fileformat (written by GIMP 1.2 up to 2.4) and now also accepts the new fileformat introduced with GIMP curves tool settings of the GIMP-2.6 release. The GIMP curves tool of the 2.6 release supports reading both formats. The parser in the GIMP-GAP specific wrapper was updated to support both fileformats too. plug_in_map_object old Testreport: (did not verfy that at the latest test) - The MapObject has an implicite feature: If the handled layer has NO ALPHA Channel (as backgrounds often do) and the "Transparent background" is ON it forces the creation of a new image. (regardless if the "Create new image" option is on or not) It took me hours to find out about that feature that looks more like a bug to me. I would prefere to add the alpha channel in such a case. If you want to do animated calls to MapObject ("Apply Varying" Button) please make sure that the background layer has an Alphachannel (Open Layers & Channels dialog, and "Add Apha Channel" to the bg layer) - If you call MapObject a 2nd time in the same gimp session gimp reports errors if one of the drawables (that were used in the 1.st call) has become invalid. gimp-gap-2.6.0+dfsg.orig/gap/gap_frame_fetcher.h0000644000175000017500000001150711212030253021312 0ustar thibautthibaut/* 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 * * * 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" #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 gimp-gap-2.6.0+dfsg.orig/gap/Makefile.in0000644000175000017500000014211511212030534017567 0ustar thibautthibaut# Makefile.in generated by automake 1.10.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = gap_bluebox$(EXEEXT) gap_plugins$(EXEEXT) \ gap_filter$(EXEEXT) gap_fmac$(EXEEXT) \ gap_fmac_varying$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2) \ gap_morph$(EXEEXT) gap_name2layer$(EXEEXT) \ gap_navigator_dialog$(EXEEXT) gap_player$(EXEEXT) \ gap_onion$(EXEEXT) gap_storyboard$(EXEEXT) $(am__EXEEXT_3) \ $(am__EXEEXT_4) gap_wr_color_curve$(EXEEXT) \ gap_wr_color_levels$(EXEEXT) gap_wr_color_huesat$(EXEEXT) \ gap_wr_trans$(EXEEXT) gap_wr_resynth$(EXEEXT) \ gap_wr_opacity$(EXEEXT) subdir = gap DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = LIBRARIES = $(noinst_LIBRARIES) AR = ar ARFLAGS = cru libgapstory_a_AR = $(AR) $(ARFLAGS) libgapstory_a_LIBADD = am__objects_1 = gap_arr_dialog.$(OBJEXT) gap_audio_util.$(OBJEXT) \ gap_audio_wav.$(OBJEXT) gap_image.$(OBJEXT) \ gap_layer_copy.$(OBJEXT) gap_lib.$(OBJEXT) gap_lock.$(OBJEXT) \ gap_navi_activtable.$(OBJEXT) gap_match.$(OBJEXT) \ gap_onion_base.$(OBJEXT) gap_pdb_calls.$(OBJEXT) \ gap_pview_da.$(OBJEXT) gap_thumbnail.$(OBJEXT) \ gap_timeconv.$(OBJEXT) gap_stock.$(OBJEXT) gap_vin.$(OBJEXT) am_libgapstory_a_OBJECTS = $(am__objects_1) \ gap_frame_fetcher.$(OBJEXT) gap_fmac_name.$(OBJEXT) \ gap_fmac_context.$(OBJEXT) gap_story_file.$(OBJEXT) \ gap_story_render_processor.$(OBJEXT) \ gap_story_render_audio.$(OBJEXT) gap_story_sox.$(OBJEXT) \ gap_story_syntax.$(OBJEXT) libgapstory_a_OBJECTS = $(am_libgapstory_a_OBJECTS) libgimpgap_a_AR = $(AR) $(ARFLAGS) libgimpgap_a_LIBADD = am_libgimpgap_a_OBJECTS = $(am__objects_1) libgimpgap_a_OBJECTS = $(am_libgimpgap_a_OBJECTS) @GAP_UNIX_FRONTENDS_TRUE@am__EXEEXT_1 = gap_frontends$(EXEEXT) am__EXEEXT_2 = gap_decode_mplayer$(EXEEXT) @GAP_VIDEOAPI_SUPPORT_TRUE@am__EXEEXT_3 = gap_video_extract$(EXEEXT) @GAP_VIDEOAPI_SUPPORT_TRUE@am__EXEEXT_4 = gap_video_index$(EXEEXT) am__installdirs = "$(DESTDIR)$(libexecdir)" \ "$(DESTDIR)$(scriptdatadir)" libexecPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(libexec_PROGRAMS) am_gap_bluebox_OBJECTS = gap_lastvaldesc.$(OBJEXT) \ gap_bluebox_main.$(OBJEXT) gap_bluebox.$(OBJEXT) gap_bluebox_OBJECTS = $(am_gap_bluebox_OBJECTS) am__DEPENDENCIES_1 = gap_bluebox_DEPENDENCIES = $(LIBGIMPGAP) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) am_gap_decode_mplayer_OBJECTS = gap_decode_mplayer_main.$(OBJEXT) \ gap_decode_mplayer.$(OBJEXT) gap_decode_mplayer_OBJECTS = $(am_gap_decode_mplayer_OBJECTS) gap_decode_mplayer_DEPENDENCIES = $(LIBGIMPGAP) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) am_gap_filter_OBJECTS = gap_dbbrowser_utils.$(OBJEXT) \ gap_filter_codegen.$(OBJEXT) gap_filter_foreach.$(OBJEXT) \ gap_filter_iterators.$(OBJEXT) gap_filter_main.$(OBJEXT) \ gap_filter_pdb.$(OBJEXT) gap_drawable_vref_parasite.$(OBJEXT) \ gap_fmac_context.$(OBJEXT) gap_frame_fetcher.$(OBJEXT) \ gap_lastvaldesc.$(OBJEXT) gap_filter_OBJECTS = $(am_gap_filter_OBJECTS) @GAP_VIDEOAPI_SUPPORT_TRUE@am__DEPENDENCIES_2 = $(top_builddir)/libgapvidapi/libgapvidapi.a \ @GAP_VIDEOAPI_SUPPORT_TRUE@ $(am__DEPENDENCIES_1) gap_filter_DEPENDENCIES = $(am__DEPENDENCIES_2) $(LIBGIMPGAP) \ $(LIBGAPBASE) $(am__DEPENDENCIES_1) am_gap_fmac_OBJECTS = gap_dbbrowser_utils.$(OBJEXT) \ gap_filter_codegen.$(OBJEXT) gap_filter_foreach.$(OBJEXT) \ gap_filter_iterators.$(OBJEXT) \ gap_drawable_vref_parasite.$(OBJEXT) gap_fmac_main.$(OBJEXT) \ gap_filter_pdb.$(OBJEXT) gap_frame_fetcher.$(OBJEXT) \ gap_fmac_name.$(OBJEXT) gap_fmac_context.$(OBJEXT) \ gap_fmac_base.$(OBJEXT) gap_lastvaldesc.$(OBJEXT) gap_fmac_OBJECTS = $(am_gap_fmac_OBJECTS) gap_fmac_DEPENDENCIES = $(am__DEPENDENCIES_2) $(LIBGIMPGAP) \ $(LIBGAPBASE) $(am__DEPENDENCIES_1) am_gap_fmac_varying_OBJECTS = gap_filter_iterators.$(OBJEXT) \ gap_drawable_vref_parasite.$(OBJEXT) \ gap_fmac_varying_main.$(OBJEXT) gap_filter_pdb.$(OBJEXT) \ gap_frame_fetcher.$(OBJEXT) gap_fmac_name.$(OBJEXT) \ gap_fmac_context.$(OBJEXT) gap_fmac_base.$(OBJEXT) \ gap_lastvaldesc.$(OBJEXT) gap_fmac_varying_OBJECTS = $(am_gap_fmac_varying_OBJECTS) gap_fmac_varying_DEPENDENCIES = $(am__DEPENDENCIES_2) $(LIBGIMPGAP) \ $(LIBGAPBASE) $(am__DEPENDENCIES_1) am_gap_frontends_OBJECTS = gap_decode_xanim.$(OBJEXT) \ gap_frontends_main.$(OBJEXT) gap_mpege.$(OBJEXT) gap_frontends_OBJECTS = $(am_gap_frontends_OBJECTS) gap_frontends_DEPENDENCIES = $(LIBGIMPGAP) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) am_gap_morph_OBJECTS = gap_morph_main.$(OBJEXT) \ gap_morph_exec.$(OBJEXT) gap_morph_dialog.$(OBJEXT) \ gap_morph_tween_dialog.$(OBJEXT) gap_morph_OBJECTS = $(am_gap_morph_OBJECTS) gap_morph_DEPENDENCIES = $(LIBGIMPGAP) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) am_gap_name2layer_OBJECTS = gap_lastvaldesc.$(OBJEXT) \ gap_name2layer_main.$(OBJEXT) gap_name2layer_OBJECTS = $(am_gap_name2layer_OBJECTS) gap_name2layer_DEPENDENCIES = $(LIBGIMPGAP) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) am_gap_navigator_dialog_OBJECTS = gap_navi_activtable.$(OBJEXT) \ gap_navigator_dialog.$(OBJEXT) gap_navigator_dialog_OBJECTS = $(am_gap_navigator_dialog_OBJECTS) gap_navigator_dialog_DEPENDENCIES = $(LIBGIMPGAP) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) am_gap_onion_OBJECTS = gap_onion_main.$(OBJEXT) \ gap_onion_dialog.$(OBJEXT) gap_onion_worker.$(OBJEXT) gap_onion_OBJECTS = $(am_gap_onion_OBJECTS) gap_onion_DEPENDENCIES = $(LIBGIMPGAP) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) am_gap_player_OBJECTS = gap_player_main.$(OBJEXT) \ gap_player_dialog.$(OBJEXT) gap_player_cache.$(OBJEXT) \ gap_audio_extract.$(OBJEXT) \ gap_drawable_vref_parasite.$(OBJEXT) gap_player_OBJECTS = $(am_gap_player_OBJECTS) gap_player_DEPENDENCIES = $(am__DEPENDENCIES_2) $(WAVPLAYCLIENT) \ $(LIBGAPSTORY) $(LIBGAPBASE) $(am__DEPENDENCIES_1) am_gap_plugins_OBJECTS = gap_base_ops.$(OBJEXT) gap_bluebox.$(OBJEXT) \ gap_dbbrowser_utils.$(OBJEXT) gap_filter_codegen.$(OBJEXT) \ gap_filter_pdb.$(OBJEXT) gap_lastvaldesc.$(OBJEXT) \ gap_main.$(OBJEXT) gap_mod_layer.$(OBJEXT) \ gap_mod_layer_dialog.$(OBJEXT) gap_mov_dialog.$(OBJEXT) \ gap_mov_exec.$(OBJEXT) gap_mov_render.$(OBJEXT) \ gap_navi_activtable.$(OBJEXT) gap_range_ops.$(OBJEXT) \ gap_resi_dialog.$(OBJEXT) gap_split.$(OBJEXT) gap_plugins_OBJECTS = $(am_gap_plugins_OBJECTS) gap_plugins_DEPENDENCIES = $(LIBGIMPGAP) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) am_gap_storyboard_OBJECTS = gap_story_main.$(OBJEXT) \ gap_story_dialog.$(OBJEXT) gap_story_undo.$(OBJEXT) \ gap_story_vthumb.$(OBJEXT) \ gap_story_section_properties.$(OBJEXT) \ gap_story_properties.$(OBJEXT) \ gap_story_att_trans_dlg.$(OBJEXT) gap_audio_extract.$(OBJEXT) \ gap_player_dialog.$(OBJEXT) gap_player_cache.$(OBJEXT) \ gap_drawable_vref_parasite.$(OBJEXT) gap_storyboard_OBJECTS = $(am_gap_storyboard_OBJECTS) gap_storyboard_DEPENDENCIES = $(am__DEPENDENCIES_2) $(WAVPLAYCLIENT) \ $(LIBGAPSTORY) $(LIBGAPBASE) $(am__DEPENDENCIES_1) am_gap_video_extract_OBJECTS = gap_bluebox.$(OBJEXT) \ gap_vex_main.$(OBJEXT) gap_vex_exec.$(OBJEXT) \ gap_vex_dialog.$(OBJEXT) gap_audio_extract.$(OBJEXT) \ gap_player_dialog.$(OBJEXT) gap_player_cache.$(OBJEXT) \ gap_drawable_vref_parasite.$(OBJEXT) gap_video_extract_OBJECTS = $(am_gap_video_extract_OBJECTS) gap_video_extract_DEPENDENCIES = $(am__DEPENDENCIES_2) \ $(WAVPLAYCLIENT) $(LIBGAPSTORY) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) am_gap_video_index_OBJECTS = gap_video_index_creator.$(OBJEXT) gap_video_index_OBJECTS = $(am_gap_video_index_OBJECTS) gap_video_index_DEPENDENCIES = $(am__DEPENDENCIES_2) $(LIBGAPSTORY) \ $(LIBGAPBASE) $(am__DEPENDENCIES_1) am_gap_wr_color_curve_OBJECTS = gap_wr_color_curve.$(OBJEXT) gap_wr_color_curve_OBJECTS = $(am_gap_wr_color_curve_OBJECTS) gap_wr_color_curve_DEPENDENCIES = $(LIBGIMPGAP) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) am_gap_wr_color_huesat_OBJECTS = gap_wr_color_huesat.$(OBJEXT) gap_wr_color_huesat_OBJECTS = $(am_gap_wr_color_huesat_OBJECTS) gap_wr_color_huesat_DEPENDENCIES = $(LIBGIMPGAP) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) am_gap_wr_color_levels_OBJECTS = gap_wr_color_levels.$(OBJEXT) gap_wr_color_levels_OBJECTS = $(am_gap_wr_color_levels_OBJECTS) gap_wr_color_levels_DEPENDENCIES = $(LIBGIMPGAP) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) am_gap_wr_opacity_OBJECTS = gap_lastvaldesc.$(OBJEXT) \ gap_wr_opacity.$(OBJEXT) gap_wr_opacity_OBJECTS = $(am_gap_wr_opacity_OBJECTS) gap_wr_opacity_DEPENDENCIES = $(LIBGIMPGAP) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) am_gap_wr_resynth_OBJECTS = gap_wr_resynth.$(OBJEXT) \ gap_lastvaldesc.$(OBJEXT) gap_wr_resynth_OBJECTS = $(am_gap_wr_resynth_OBJECTS) gap_wr_resynth_DEPENDENCIES = $(LIBGIMPGAP) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) am_gap_wr_trans_OBJECTS = gap_lastvaldesc.$(OBJEXT) \ gap_wr_trans.$(OBJEXT) gap_wr_trans_OBJECTS = $(am_gap_wr_trans_OBJECTS) gap_wr_trans_DEPENDENCIES = $(LIBGIMPGAP) $(LIBGAPBASE) \ $(am__DEPENDENCIES_1) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libgapstory_a_SOURCES) $(libgimpgap_a_SOURCES) \ $(gap_bluebox_SOURCES) $(gap_decode_mplayer_SOURCES) \ $(gap_filter_SOURCES) $(gap_fmac_SOURCES) \ $(gap_fmac_varying_SOURCES) $(gap_frontends_SOURCES) \ $(gap_morph_SOURCES) $(gap_name2layer_SOURCES) \ $(gap_navigator_dialog_SOURCES) $(gap_onion_SOURCES) \ $(gap_player_SOURCES) $(gap_plugins_SOURCES) \ $(gap_storyboard_SOURCES) $(gap_video_extract_SOURCES) \ $(gap_video_index_SOURCES) $(gap_wr_color_curve_SOURCES) \ $(gap_wr_color_huesat_SOURCES) $(gap_wr_color_levels_SOURCES) \ $(gap_wr_opacity_SOURCES) $(gap_wr_resynth_SOURCES) \ $(gap_wr_trans_SOURCES) DIST_SOURCES = $(libgapstory_a_SOURCES) $(libgimpgap_a_SOURCES) \ $(gap_bluebox_SOURCES) $(gap_decode_mplayer_SOURCES) \ $(gap_filter_SOURCES) $(gap_fmac_SOURCES) \ $(gap_fmac_varying_SOURCES) $(gap_frontends_SOURCES) \ $(gap_morph_SOURCES) $(gap_name2layer_SOURCES) \ $(gap_navigator_dialog_SOURCES) $(gap_onion_SOURCES) \ $(gap_player_SOURCES) $(gap_plugins_SOURCES) \ $(gap_storyboard_SOURCES) $(gap_video_extract_SOURCES) \ $(gap_video_index_SOURCES) $(gap_wr_color_curve_SOURCES) \ $(gap_wr_color_huesat_SOURCES) $(gap_wr_color_levels_SOURCES) \ $(gap_wr_opacity_SOURCES) $(gap_wr_resynth_SOURCES) \ $(gap_wr_trans_SOURCES) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; scriptdataDATA_INSTALL = $(INSTALL_DATA) DATA = $(scriptdata_DATA) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BUILD_FFMPEG_LIBS = @BUILD_FFMPEG_LIBS@ BUILD_LIBMPEG3_LIB = @BUILD_LIBMPEG3_LIB@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXGMAKE = @EXGMAKE@ FFMPEG_DIR = @FFMPEG_DIR@ FFMPEG_LIBAVCODEC_A = @FFMPEG_LIBAVCODEC_A@ FFMPEG_LIBAVFORMAT_A = @FFMPEG_LIBAVFORMAT_A@ FFMPEG_LIBAVUTIL_A = @FFMPEG_LIBAVUTIL_A@ GAPLIBDIR = @GAPLIBDIR@ GAPVIDEOAPI_EXTINCS = @GAPVIDEOAPI_EXTINCS@ GAPVIDEOAPI_EXTLIBS = @GAPVIDEOAPI_EXTLIBS@ GAP_MAJOR_VERSION = @GAP_MAJOR_VERSION@ GAP_MICRO_VERSION = @GAP_MICRO_VERSION@ GAP_MINOR_VERSION = @GAP_MINOR_VERSION@ GAP_PTHREAD_LIB = @GAP_PTHREAD_LIB@ GAP_VERSION = @GAP_VERSION@ GAP_VERSION_WITH_DATE = @GAP_VERSION_WITH_DATE@ GAP_VINCS_FFMPEG = @GAP_VINCS_FFMPEG@ GAP_VINCS_MPEG3 = @GAP_VINCS_MPEG3@ GAP_VINCS_XVIDCORE = @GAP_VINCS_XVIDCORE@ GAP_VLIBS_FFMPEG = @GAP_VLIBS_FFMPEG@ GAP_VLIBS_MPEG3 = @GAP_VLIBS_MPEG3@ GAP_VLIBS_XVIDCORE = @GAP_VLIBS_XVIDCORE@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GIMP_CFLAGS = @GIMP_CFLAGS@ GIMP_DATA_DIR = @GIMP_DATA_DIR@ GIMP_LIBS = @GIMP_LIBS@ GIMP_PLUGIN_DIR = @GIMP_PLUGIN_DIR@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMAKE_AVAILABLE = @GMAKE_AVAILABLE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_NASM_ASSEMBLER = @HAVE_NASM_ASSEMBLER@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ INTLTOOL_MERGE = @INTLTOOL_MERGE@ INTLTOOL_PERL = @INTLTOOL_PERL@ INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBPREF = @LIBPREF@ LIBS = @LIBS@ LIBSUF = @LIBSUF@ LMPEG3_A = @LMPEG3_A@ LMPEG3_DIR = @LMPEG3_DIR@ LOCALEDIR = @LOCALEDIR@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ MSGMERGE = @MSGMERGE@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATHSEP = @PATHSEP@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WAVPLAY_SERVER = @WAVPLAY_SERVER@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = $(GIMP_PLUGIN_DIR)/plug-ins localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ scriptdatadir = $(GIMP_DATA_DIR)/scripts scriptdata_DATA = sel-to-anim-img.scm gap-dup-continue.scm @GAP_UNIX_FRONTENDS_TRUE@GAP_FRONTENDS = gap_frontends GAP_DECODE_MPLAYER_FRONTEND = gap_decode_mplayer @GAP_AUDIO_SUPPORT_TRUE@WAVPLAYCLIENT = $(top_builddir)/libwavplayclient/libwavplayclient.a @GAP_VIDEOAPI_SUPPORT_TRUE@GAPVIDEOAPI = $(top_builddir)/libgapvidapi/libgapvidapi.a $(GAPVIDEOAPI_EXTLIBS) @GAP_VIDEOAPI_SUPPORT_TRUE@INC_GAPVIDEOAPI = -I$(top_srcdir)/libgapvidapi $(GAPVIDEOAPI_EXTINCS) @GAP_VIDEOAPI_SUPPORT_TRUE@GAP_VIDEO_EXTRACT = gap_video_extract @GAP_VIDEOAPI_SUPPORT_TRUE@GAP_VIDEO_INDEX = gap_video_index LIBGAPBASE = $(top_builddir)/libgapbase/libgapbase.a INC_LIBGAPBASE = -I$(top_srcdir)/libgapbase LIBGIMPGAP = libgimpgap.a LIBGAPSTORY = libgapstory.a noinst_LIBRARIES = $(LIBGIMPGAP) $(LIBGAPSTORY) BASE_SOURCES = \ gap-intl.h \ gap_arr_dialog.c \ gap_arr_dialog.h \ gap_audio_util.c \ gap_audio_util.h \ gap_audio_wav.c \ gap_audio_wav.h \ gap_image.c \ gap_image.h \ gap_layer_copy.c \ gap_layer_copy.h \ gap_lib.c \ gap_lib.h \ gap_lib_common_defs.h \ gap_lock.c \ gap_lock.h \ gap_navi_activtable.c \ gap_navi_activtable.h \ gap_match.c \ gap_match.h \ gap_onion_base.c \ gap_onion_base.h \ gap_pdb_calls.c \ gap_pdb_calls.h \ gap_pview_da.c \ gap_pview_da.h \ gap_thumbnail.c \ gap_thumbnail.h \ gap_timeconv.c \ gap_timeconv.h \ gap_stock.c \ gap_stock.h \ gap_vin.c \ gap_vin.h libgimpgap_a_SOURCES = $(BASE_SOURCES) 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 \ gap_story_render_processor.h \ gap_story_render_processor.c \ gap_story_render_audio.h \ gap_story_render_audio.c \ gap_story_sox.h \ gap_story_sox.c \ gap_story_syntax.h \ gap_story_syntax.c gap_bluebox_SOURCES = \ gap_lastvaldesc.c \ gap_lastvaldesc.h \ gap_bluebox_main.c \ gap_bluebox.c \ gap_bluebox.h \ gap_libgimpgap.h gap_plugins_SOURCES = \ gap_base_ops.c \ gap_base_ops.h \ gap_bluebox.c \ gap_bluebox.h \ gap_dbbrowser_utils.c \ gap_dbbrowser_utils.h \ gap_filter_codegen.c \ gap_filter_pdb.c \ gap_filter_pdb.h \ gap_lastvaldesc.c \ gap_lastvaldesc.h \ gap_main.c \ gap_mod_layer.c \ gap_mod_layer.h \ gap_mod_layer_dialog.c \ gap_mod_layer_dialog.h \ gap_mov_dialog.c \ gap_mov_dialog.h \ gap_mov_exec.c \ gap_mov_exec.h \ gap_mov_render.c \ gap_mov_render.h \ gap_navi_activtable.c \ gap_navi_activtable.h \ gap_range_ops.c \ gap_range_ops.h \ gap_resi_dialog.c \ gap_resi_dialog.h \ gap_split.c \ gap_split.h \ gap_libgimpgap.h gap_filter_SOURCES = \ gap_dbbrowser_utils.c \ gap_dbbrowser_utils.h \ gap_filter.h \ gap_filter_codegen.c \ gap_filter_foreach.c \ gap_filter_iterators.c \ gap_filter_iterators.h \ 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 gap_fmac_SOURCES = \ gap_dbbrowser_utils.c \ gap_dbbrowser_utils.h \ gap_filter.h \ gap_filter_codegen.c \ 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 \ gap_lastvaldesc.h \ gap_libgimpgap.h gap_fmac_varying_SOURCES = \ 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 \ gap_lastvaldesc.h \ gap_libgimpgap.h gap_frontends_SOURCES = \ gap_decode_xanim.c \ gap_decode_xanim.h \ gap_frontends_main.c \ gap_mpege.c \ gap_mpege.h \ gap_libgimpgap.h gap_decode_mplayer_SOURCES = \ gap_decode_mplayer_main.c \ gap_decode_mplayer.c \ gap_decode_mplayer.h \ gap_libgimpgap.h # gap_morph_SOURCES: gap_mov_exec.h should be removed when finished coding gap_morph_SOURCES = \ gap_morph_main.c \ gap_morph_main.h \ gap_morph_exec.c \ gap_morph_exec.h \ gap_morph_dialog.c \ gap_morph_dialog.h \ gap_morph_tween_dialog.c \ gap_morph_tween_dialog.h \ gap_mov_dialog.h \ gap_mov_exec.h \ gap_libgimpgap.h gap_name2layer_SOURCES = \ gap_lastvaldesc.c \ gap_lastvaldesc.h \ gap_name2layer_main.c \ gap_libgimpgap.h gap_navigator_dialog_SOURCES = \ gap_navi_activtable.c \ gap_navi_activtable.h \ gap_navigator_dialog.c \ gap_libgimpgap.h gap_player_SOURCES = \ gap_player_main.c \ gap_player_main.h \ gap_player_dialog.c \ gap_player_dialog.h \ gap_player_cache.c \ 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 gap_onion_SOURCES = \ gap_onion_main.c \ gap_onion_main.h \ gap_onion_dialog.c \ gap_onion_dialog.h \ gap_onion_worker.c \ gap_onion_worker.h \ gap_libgimpgap.h gap_storyboard_SOURCES = \ gap_story_main.c \ gap_story_main.h \ gap_story_dialog.c \ gap_story_dialog.h \ gap_story_undo.c \ gap_story_undo.h \ gap_story_undo_types.h \ gap_story_vthumb.c \ gap_story_vthumb.h \ gap_story_section_properties.c \ gap_story_section_properties.h \ gap_story_properties.c \ gap_story_properties.h \ gap_story_att_trans_dlg.c \ gap_story_att_trans_dlg.h \ gap_audio_extract.c \ gap_audio_extract.h \ gap_player_main.h \ gap_player_dialog.c \ 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 gap_video_extract_SOURCES = \ gap_bluebox.c \ gap_bluebox.h \ gap_vex_main.c \ gap_vex_main.h \ gap_vex_exec.c \ gap_vex_exec.h \ gap_vex_dialog.c \ gap_vex_dialog.h \ gap_audio_extract.c \ gap_audio_extract.h \ gap_player_main.h \ gap_player_dialog.c \ 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 gap_video_index_SOURCES = \ gap_video_index_creator.c \ gap_libgapstory.h \ gap_libgimpgap.h gap_wr_opacity_SOURCES = \ gap_lastvaldesc.c \ gap_lastvaldesc.h \ gap_wr_opacity.c \ gap_libgimpgap.h gap_wr_trans_SOURCES = \ gap_lastvaldesc.c \ gap_lastvaldesc.h \ gap_wr_trans.c \ gap_libgimpgap.h gap_wr_color_curve_SOURCES = \ gap_wr_color_curve.c \ gap_libgimpgap.h gap_wr_color_levels_SOURCES = \ gap_wr_color_levels.c \ gap_libgimpgap.h gap_wr_color_huesat_SOURCES = \ gap_wr_color_huesat.c \ gap_libgimpgap.h gap_wr_resynth_SOURCES = \ gap_wr_resynth.c \ gap_lastvaldesc.c \ gap_lastvaldesc.h \ gap_libgimpgap.h @OS_WIN32_TRUE@mwindows = -mwindows AM_CPPFLAGS = \ -DGAPLIBDIR=\""$(GAPLIBDIR)"\" \ -DLOCALEDIR=\""$(LOCALEDIR)"\" INCLUDES = \ -I$(top_srcdir) \ -I$(top_srcdir)/libwavplayclient \ $(INC_LIBGAPBASE) \ $(INC_GAPVIDEOAPI) \ $(GIMP_CFLAGS) \ -I$(includedir) AM_LDFLAGS = $(mwindows) LDADD = $(GIMP_LIBS) gap_plugins_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_bluebox_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_decode_mplayer_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_morph_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_name2layer_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_navigator_dialog_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_player_LDADD = $(GAPVIDEOAPI) $(WAVPLAYCLIENT) ${LIBGAPSTORY} $(LIBGAPBASE) $(GIMP_LIBS) gap_onion_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_storyboard_LDADD = $(GAPVIDEOAPI) $(WAVPLAYCLIENT) ${LIBGAPSTORY} $(LIBGAPBASE) $(GIMP_LIBS) gap_video_extract_LDADD = $(GAPVIDEOAPI) $(WAVPLAYCLIENT) ${LIBGAPSTORY} $(LIBGAPBASE) $(GIMP_LIBS) gap_video_index_LDADD = $(GAPVIDEOAPI) $(LIBGAPSTORY) $(LIBGAPBASE) $(GIMP_LIBS) gap_wr_opacity_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_wr_trans_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_wr_color_curve_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_wr_color_levels_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_wr_color_huesat_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) gap_wr_resynth_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) EXTRA_DIST = \ README \ README_developers \ TESTPROT_iter_ALT \ gimplastvaldesc.c \ gimplastvaldesc.h \ gap_story_render_lossless.c \ iter_ALT/README_iter_subdirs \ iter_ALT/gen/plug_in_CML_explorer_iter_ALT.inc \ iter_ALT/gen/plug_in_alpha2color_iter_ALT.inc \ iter_ALT/gen/plug_in_blinds_iter_ALT.inc \ iter_ALT/gen/plug_in_borderaverage_iter_ALT.inc \ iter_ALT/gen/plug_in_checkerboard_iter_ALT.inc \ iter_ALT/gen/plug_in_color_map_iter_ALT.inc \ iter_ALT/gen/plug_in_colorify_iter_ALT.inc \ iter_ALT/gen/plug_in_cubism_iter_ALT.inc \ iter_ALT/gen/plug_in_destripe_iter_ALT.inc \ iter_ALT/gen/plug_in_diffraction_iter_ALT.inc \ iter_ALT/gen/plug_in_displace_iter_ALT.inc \ iter_ALT/gen/plug_in_edge_iter_ALT.inc \ iter_ALT/gen/plug_in_engrave_iter_ALT.inc \ iter_ALT/gen/plug_in_flarefx_iter_ALT.inc \ iter_ALT/gen/plug_in_fractal_trace_iter_ALT.inc \ iter_ALT/gen/plug_in_gfig_iter_ALT.inc \ iter_ALT/gen/plug_in_glasstile_iter_ALT.inc \ iter_ALT/gen/plug_in_grid_iter_ALT.inc \ iter_ALT/gen/plug_in_jigsaw_iter_ALT.inc \ iter_ALT/gen/plug_in_mblur_iter_ALT.inc \ iter_ALT/gen/plug_in_mosaic_iter_ALT.inc \ iter_ALT/gen/plug_in_newsprint_iter_ALT.inc \ iter_ALT/gen/plug_in_noisify_iter_ALT.inc \ iter_ALT/gen/plug_in_pixelize_iter_ALT.inc \ iter_ALT/gen/plug_in_randomize_hurl_iter_ALT.inc \ iter_ALT/gen/plug_in_randomize_pick_iter_ALT.inc \ iter_ALT/gen/plug_in_randomize_slur_iter_ALT.inc \ iter_ALT/gen/plug_in_ripple_iter_ALT.inc \ iter_ALT/gen/plug_in_scatter_hsv_iter_ALT.inc \ iter_ALT/gen/plug_in_sharpen_iter_ALT.inc \ iter_ALT/gen/plug_in_shift_iter_ALT.inc \ iter_ALT/gen/plug_in_spread_iter_ALT.inc \ iter_ALT/gen/plug_in_video_iter_ALT.inc \ iter_ALT/gen/plug_in_vpropagate_iter_ALT.inc \ iter_ALT/gen/plug_in_waves_iter_ALT.inc \ iter_ALT/gen/plug_in_whirl_pinch_iter_ALT.inc \ iter_ALT/gen/plug_in_wind_iter_ALT.inc \ iter_ALT/mod/plug_in_Twist_iter_ALT.inc \ iter_ALT/mod/plug_in_alienmap_iter_ALT.inc \ iter_ALT/mod/plug_in_applylens_iter_ALT.inc \ iter_ALT/mod/plug_in_bump_map_iter_ALT.inc \ iter_ALT/mod/plug_in_cartoon_iter_ALT.inc \ iter_ALT/mod/plug_in_colors_channel_mixer_iter_ALT.inc \ iter_ALT/mod/plug_in_convmatrix_iter_ALT.inc \ iter_ALT/mod/plug_in_depth_merge_iter_ALT.inc \ iter_ALT/mod/plug_in_despeckle_iter_ALT.inc \ iter_ALT/mod/plug_in_dog_iter_ALT.inc \ iter_ALT/mod/plug_in_emboss_iter_ALT.inc \ iter_ALT/mod/plug_in_exchange_iter_ALT.inc \ iter_ALT/mod/plug_in_flame_iter_ALT.inc \ iter_ALT/mod/plug_in_gauss_iter_ALT.inc \ iter_ALT/mod/plug_in_gimpressionist_iter_ALT.inc \ iter_ALT/mod/plug_in_lighting_iter_ALT.inc \ iter_ALT/mod/plug_in_map_object_iter_ALT.inc \ iter_ALT/mod/plug_in_maze_iter_ALT.inc \ iter_ALT/mod/plug_in_neon_iter_ALT.inc \ iter_ALT/mod/plug_in_nlfilt_iter_ALT.inc \ iter_ALT/mod/plug_in_nova_iter_ALT.inc \ iter_ALT/mod/plug_in_oilify_iter_ALT.inc \ iter_ALT/mod/plug_in_pagecurl_iter_ALT.inc \ iter_ALT/mod/plug_in_papertile_iter_ALT.inc \ iter_ALT/mod/plug_in_photocopy_iter_ALT.inc \ iter_ALT/mod/plug_in_plasma_iter_ALT.inc \ iter_ALT/mod/plug_in_polar_coords_iter_ALT.inc \ iter_ALT/mod/plug_in_retinex_iter_ALT.inc \ iter_ALT/mod/plug_in_sample_colorize_iter_ALT.inc \ iter_ALT/mod/plug_in_sinus_iter_ALT.inc \ iter_ALT/mod/plug_in_softglow_iter_ALT.inc \ iter_ALT/mod/plug_in_solid_noise_iter_ALT.inc \ iter_ALT/mod/plug_in_sparkle_iter_ALT.inc \ iter_ALT/mod/plug_in_alienmap2_iter_ALT.inc \ iter_ALT/mod/plug_in_apply_canvas_iter_ALT.inc \ iter_ALT/mod/plug_in_colortoalpha_iter_ALT.inc \ iter_ALT/mod/plug_in_deinterlace_iter_ALT.inc \ iter_ALT/mod/plug_in_illusion_iter_ALT.inc \ iter_ALT/mod/plug_in_lic_iter_ALT.inc \ iter_ALT/mod/plug_in_sel_gauss_iter_ALT.inc \ iter_ALT/mod/plug_in_small_tiles_iter_ALT.inc \ iter_ALT/mod/plug_in_sobel_iter_ALT.inc \ iter_ALT/mod/plug_in_unsharp_mask_iter_ALT.inc \ iter_ALT/old/plug_in_CentralReflection_iter_ALT.inc \ iter_ALT/old/plug_in_anamorphose_iter_ALT.inc \ iter_ALT/old/plug_in_blur2_iter_ALT.inc \ iter_ALT/old/plug_in_colorify_iter_ALT.inc \ iter_ALT/old/plug_in_encript_iter_ALT.inc \ iter_ALT/old/plug_in_figures_iter_ALT.inc \ iter_ALT/old/plug_in_gflare_iter_ALT.inc \ iter_ALT/old/plug_in_holes_iter_ALT.inc \ iter_ALT/old/plug_in_julia_iter_ALT.inc \ iter_ALT/old/plug_in_magic_eye_iter_ALT.inc \ iter_ALT/old/plug_in_mandelbrot_iter_ALT.inc \ iter_ALT/old/plug_in_randomize_iter_ALT.inc \ iter_ALT/old/plug_in_refract_iter_ALT.inc \ iter_ALT/old/plug_in_struc_iter_ALT.inc \ iter_ALT/old/plug_in_tileit_iter_ALT.inc \ iter_ALT/old/plug_in_universal_filter_iter_ALT.inc \ iter_ALT/old/plug_in_warp_iter_ALT.inc \ $(scriptdata_DATA) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu gap/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu gap/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libgapstory.a: $(libgapstory_a_OBJECTS) $(libgapstory_a_DEPENDENCIES) -rm -f libgapstory.a $(libgapstory_a_AR) libgapstory.a $(libgapstory_a_OBJECTS) $(libgapstory_a_LIBADD) $(RANLIB) libgapstory.a libgimpgap.a: $(libgimpgap_a_OBJECTS) $(libgimpgap_a_DEPENDENCIES) -rm -f libgimpgap.a $(libgimpgap_a_AR) libgimpgap.a $(libgimpgap_a_OBJECTS) $(libgimpgap_a_LIBADD) $(RANLIB) libgimpgap.a install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(libexecdir)" || $(MKDIR_P) "$(DESTDIR)$(libexecdir)" @list='$(libexec_PROGRAMS)'; for p in $$list; do \ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ if test -f $$p \ ; then \ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ echo " $(INSTALL_PROGRAM_ENV) $(libexecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(libexecdir)/$$f'"; \ $(INSTALL_PROGRAM_ENV) $(libexecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(libexecdir)/$$f" || exit 1; \ else :; fi; \ done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; for p in $$list; do \ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ echo " rm -f '$(DESTDIR)$(libexecdir)/$$f'"; \ rm -f "$(DESTDIR)$(libexecdir)/$$f"; \ done clean-libexecPROGRAMS: -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) gap_bluebox$(EXEEXT): $(gap_bluebox_OBJECTS) $(gap_bluebox_DEPENDENCIES) @rm -f gap_bluebox$(EXEEXT) $(LINK) $(gap_bluebox_OBJECTS) $(gap_bluebox_LDADD) $(LIBS) gap_decode_mplayer$(EXEEXT): $(gap_decode_mplayer_OBJECTS) $(gap_decode_mplayer_DEPENDENCIES) @rm -f gap_decode_mplayer$(EXEEXT) $(LINK) $(gap_decode_mplayer_OBJECTS) $(gap_decode_mplayer_LDADD) $(LIBS) gap_filter$(EXEEXT): $(gap_filter_OBJECTS) $(gap_filter_DEPENDENCIES) @rm -f gap_filter$(EXEEXT) $(LINK) $(gap_filter_OBJECTS) $(gap_filter_LDADD) $(LIBS) gap_fmac$(EXEEXT): $(gap_fmac_OBJECTS) $(gap_fmac_DEPENDENCIES) @rm -f gap_fmac$(EXEEXT) $(LINK) $(gap_fmac_OBJECTS) $(gap_fmac_LDADD) $(LIBS) gap_fmac_varying$(EXEEXT): $(gap_fmac_varying_OBJECTS) $(gap_fmac_varying_DEPENDENCIES) @rm -f gap_fmac_varying$(EXEEXT) $(LINK) $(gap_fmac_varying_OBJECTS) $(gap_fmac_varying_LDADD) $(LIBS) gap_frontends$(EXEEXT): $(gap_frontends_OBJECTS) $(gap_frontends_DEPENDENCIES) @rm -f gap_frontends$(EXEEXT) $(LINK) $(gap_frontends_OBJECTS) $(gap_frontends_LDADD) $(LIBS) gap_morph$(EXEEXT): $(gap_morph_OBJECTS) $(gap_morph_DEPENDENCIES) @rm -f gap_morph$(EXEEXT) $(LINK) $(gap_morph_OBJECTS) $(gap_morph_LDADD) $(LIBS) gap_name2layer$(EXEEXT): $(gap_name2layer_OBJECTS) $(gap_name2layer_DEPENDENCIES) @rm -f gap_name2layer$(EXEEXT) $(LINK) $(gap_name2layer_OBJECTS) $(gap_name2layer_LDADD) $(LIBS) gap_navigator_dialog$(EXEEXT): $(gap_navigator_dialog_OBJECTS) $(gap_navigator_dialog_DEPENDENCIES) @rm -f gap_navigator_dialog$(EXEEXT) $(LINK) $(gap_navigator_dialog_OBJECTS) $(gap_navigator_dialog_LDADD) $(LIBS) gap_onion$(EXEEXT): $(gap_onion_OBJECTS) $(gap_onion_DEPENDENCIES) @rm -f gap_onion$(EXEEXT) $(LINK) $(gap_onion_OBJECTS) $(gap_onion_LDADD) $(LIBS) gap_player$(EXEEXT): $(gap_player_OBJECTS) $(gap_player_DEPENDENCIES) @rm -f gap_player$(EXEEXT) $(LINK) $(gap_player_OBJECTS) $(gap_player_LDADD) $(LIBS) gap_plugins$(EXEEXT): $(gap_plugins_OBJECTS) $(gap_plugins_DEPENDENCIES) @rm -f gap_plugins$(EXEEXT) $(LINK) $(gap_plugins_OBJECTS) $(gap_plugins_LDADD) $(LIBS) gap_storyboard$(EXEEXT): $(gap_storyboard_OBJECTS) $(gap_storyboard_DEPENDENCIES) @rm -f gap_storyboard$(EXEEXT) $(LINK) $(gap_storyboard_OBJECTS) $(gap_storyboard_LDADD) $(LIBS) gap_video_extract$(EXEEXT): $(gap_video_extract_OBJECTS) $(gap_video_extract_DEPENDENCIES) @rm -f gap_video_extract$(EXEEXT) $(LINK) $(gap_video_extract_OBJECTS) $(gap_video_extract_LDADD) $(LIBS) gap_video_index$(EXEEXT): $(gap_video_index_OBJECTS) $(gap_video_index_DEPENDENCIES) @rm -f gap_video_index$(EXEEXT) $(LINK) $(gap_video_index_OBJECTS) $(gap_video_index_LDADD) $(LIBS) gap_wr_color_curve$(EXEEXT): $(gap_wr_color_curve_OBJECTS) $(gap_wr_color_curve_DEPENDENCIES) @rm -f gap_wr_color_curve$(EXEEXT) $(LINK) $(gap_wr_color_curve_OBJECTS) $(gap_wr_color_curve_LDADD) $(LIBS) gap_wr_color_huesat$(EXEEXT): $(gap_wr_color_huesat_OBJECTS) $(gap_wr_color_huesat_DEPENDENCIES) @rm -f gap_wr_color_huesat$(EXEEXT) $(LINK) $(gap_wr_color_huesat_OBJECTS) $(gap_wr_color_huesat_LDADD) $(LIBS) gap_wr_color_levels$(EXEEXT): $(gap_wr_color_levels_OBJECTS) $(gap_wr_color_levels_DEPENDENCIES) @rm -f gap_wr_color_levels$(EXEEXT) $(LINK) $(gap_wr_color_levels_OBJECTS) $(gap_wr_color_levels_LDADD) $(LIBS) gap_wr_opacity$(EXEEXT): $(gap_wr_opacity_OBJECTS) $(gap_wr_opacity_DEPENDENCIES) @rm -f gap_wr_opacity$(EXEEXT) $(LINK) $(gap_wr_opacity_OBJECTS) $(gap_wr_opacity_LDADD) $(LIBS) gap_wr_resynth$(EXEEXT): $(gap_wr_resynth_OBJECTS) $(gap_wr_resynth_DEPENDENCIES) @rm -f gap_wr_resynth$(EXEEXT) $(LINK) $(gap_wr_resynth_OBJECTS) $(gap_wr_resynth_LDADD) $(LIBS) gap_wr_trans$(EXEEXT): $(gap_wr_trans_OBJECTS) $(gap_wr_trans_DEPENDENCIES) @rm -f gap_wr_trans$(EXEEXT) $(LINK) $(gap_wr_trans_OBJECTS) $(gap_wr_trans_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_arr_dialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_audio_extract.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_audio_util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_audio_wav.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_base_ops.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_bluebox.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_bluebox_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_dbbrowser_utils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_decode_mplayer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_decode_mplayer_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_decode_xanim.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_drawable_vref_parasite.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_filter_codegen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_filter_foreach.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_filter_iterators.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_filter_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_filter_pdb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_fmac_base.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_fmac_context.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_fmac_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_fmac_name.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_fmac_varying_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_frame_fetcher.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_frontends_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_image.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_lastvaldesc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_layer_copy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_lib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_lock.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_match.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_mod_layer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_mod_layer_dialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_morph_dialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_morph_exec.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_morph_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_morph_tween_dialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_mov_dialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_mov_exec.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_mov_render.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_mpege.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_name2layer_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_navi_activtable.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_navigator_dialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_onion_base.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_onion_dialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_onion_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_onion_worker.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_pdb_calls.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_player_cache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_player_dialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_player_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_pview_da.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_range_ops.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_resi_dialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_split.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_stock.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_story_att_trans_dlg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_story_dialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_story_file.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_story_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_story_properties.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_story_render_audio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_story_render_processor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_story_section_properties.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_story_sox.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_story_syntax.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_story_undo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_story_vthumb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_thumbnail.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_timeconv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_vex_dialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_vex_exec.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_vex_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_video_index_creator.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_vin.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_wr_color_curve.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_wr_color_huesat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_wr_color_levels.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_wr_opacity.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_wr_resynth.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gap_wr_trans.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` install-scriptdataDATA: $(scriptdata_DATA) @$(NORMAL_INSTALL) test -z "$(scriptdatadir)" || $(MKDIR_P) "$(DESTDIR)$(scriptdatadir)" @list='$(scriptdata_DATA)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(scriptdataDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(scriptdatadir)/$$f'"; \ $(scriptdataDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(scriptdatadir)/$$f"; \ done uninstall-scriptdataDATA: @$(NORMAL_UNINSTALL) @list='$(scriptdata_DATA)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(scriptdatadir)/$$f'"; \ rm -f "$(DESTDIR)$(scriptdatadir)/$$f"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) installdirs: for dir in "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(scriptdatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-scriptdataDATA install-dvi: install-dvi-am install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-info: install-info-am install-man: install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS uninstall-scriptdataDATA .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libexecPROGRAMS clean-noinstLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libexecPROGRAMS \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-scriptdataDATA install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-libexecPROGRAMS \ uninstall-scriptdataDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gimp-gap-2.6.0+dfsg.orig/gap/gap_story_render_types.h0000644000175000017500000003026311212030253022463 0ustar thibautthibaut/* gap_story_render_types.h * * types for the GAP storyboard rendering processor. * */ /* * 2006.06.25 hof - created (moved stuff from the former gap_gve_story modules to this new module) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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_STORY_RENDER_TYPES_H #define GAP_STORY_RENDER_TYPES_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 #include "gap_story_file.h" #include "gap_lib_common_defs.h" #define GAP_STB_MAX_VID_TRACKS 20 #define GAP_STB_MAX_AUD_TRACKS 99 #define GAP_STB_MAX_VID_INTERNAL_TRACKS (GAP_STB_MAX_VID_TRACKS * 2) #define GAP_STB_MASK_TRACK_NUMBER 0 /* the hidden mask track is reserved for internal use * (implicite copy of corresponding mask definitions * use this track number) */ #define GAP_STB_HIDDEN_MASK_TRACK_NUMBER -777 typedef enum { GAP_MSK_ANCHOR_CLIP ,GAP_MSK_ANCHOR_MASTER } GapStoryMaskAnchormode; typedef enum { GAP_FRN_SILENCE ,GAP_FRN_COLOR ,GAP_FRN_IMAGE ,GAP_FRN_ANIMIMAGE ,GAP_FRN_FRAMES ,GAP_FRN_MOVIE ,GAP_FRN_SECTION } GapStoryRenderFrameType; typedef enum { GAP_AUT_SILENCE ,GAP_AUT_AUDIOFILE ,GAP_AUT_MOVIE } GapStoryRenderAudioType; typedef struct GapStoryRenderImageCacheElem { gint32 image_id; char *filename; void *next; } GapStoryRenderImageCacheElem; typedef struct GapStoryRenderImageCache { GapStoryRenderImageCacheElem *ic_list; gint32 max_img_cache; /* number of images to hold in the cache */ } GapStoryRenderImageCache; typedef struct GapStoryRenderAudioCacheElem { gint32 audio_id; char *filename; guchar *aud_data; /* full audiodata (including header) loaded in memory */ gint32 aud_bytelength; gint32 segment_startoffset; gint32 segment_bytelength; void *next; } GapStoryRenderAudioCacheElem; typedef struct GapStoryRenderAudioCache { GapStoryRenderAudioCacheElem *ac_list; gint32 nextval_audio_id; gint32 max_aud_cache; /* number of images to hold in the cache */ } GapStoryRenderAudioCache; /* forward declaration for GapStoryRenderMaskDefElem */ struct GapStoryRenderMaskDefElem; /* nick: maskdef_elem */ typedef struct GapStoryRenderFrameRangeElem /* nick: frn_elem */ { GapStoryRenderFrameType frn_type; gint32 track; gint32 last_master_frame_access; char *basename; char *ext; t_GVA_Handle *gvahand; /* API handle for videofile (for GAP_FRN_MOVIE) */ gint32 seltrack; /* selected videotrack in a videofile (for GAP_FRN_MOVIE) */ gint32 exact_seek; /* 0 fast seek, 1 exact seek (for GAP_FRN_MOVIE) */ gdouble delace; /* 0.0 no deinterlace, 1.0-1.99 odd 2.0-2.99 even rows (for GAP_FRN_MOVIE) */ char *filtermacro_file; char *filtermacro_file_to; /* additional macro with 2nd parameterset(s) for varying apply */ gint32 fmac_total_steps; /* total steps for varying filtermacro apply */ gdouble frame_from; /* internal frame number that is 1.st of range (float due to internal clip splitting) */ gdouble frame_to; /* internal frame number that is the last handled frame of the range */ gint32 frames_to_handle; gint32 delta; /* +1 or -1 */ gdouble step_density; /* 1==normal stepsize 1:1 0.5 == each frame twice, 2.0 only every 2nd frame */ gdouble red_f; gdouble green_f; gdouble blue_f; gdouble alpha_f; gboolean keep_proportions; gboolean fit_width; gboolean fit_height; gdouble mask_framecount; /* 1 or progress offset for splitted elements */ gint32 flip_request; /* 0 none, 1 flip horizontal, 2 flip vertical, 3 flip both */ char *mask_name; /* optional reference to a layer mask */ gdouble mask_stepsize; GapStoryMaskAnchormode mask_anchor; gdouble wait_untiltime_sec; gint32 wait_untilframes; gdouble opacity_from; /* 0.0 upto 1.0 */ gdouble opacity_to; /* 0.0 upto 1.0 */ gint32 opacity_dur; /* number of frames to change from -> to value */ gdouble scale_x_from; /* 0.0 upto 10.0 where 1.0 is fit video size */ gdouble scale_x_to; /* 0.0 upto 10.0 where 1.0 is fit video size */ gint32 scale_x_dur; /* number of frames to change from -> to value */ gdouble scale_y_from; /* 0.0 upto 10.0 where 1.0 is fit video size */ gdouble scale_y_to; /* 0.0 upto 10.0 where 1.0 is fit video size */ gint32 scale_y_dur; /* number of frames to change from -> to value */ gdouble move_x_from; /* -1.0 upto 1.0 where 0 is center and -1.0 left outside */ gdouble move_x_to; /* -1.0 upto 1.0 where 0 is center and -1.0 left outside */ gint32 move_x_dur; /* number of frames to change from -> to value */ gdouble move_y_from; /* -1.0 upto 1.0 where 0 is center and -1.0 up outside */ gdouble move_y_to; /* -1.0 upto 1.0 where 0 is center and -1.0 up outside */ gint32 move_y_dur; /* number of frames to change from -> to value */ void *next; } GapStoryRenderFrameRangeElem; /* used for storyboard processing */ typedef struct GapStoryRenderAudioRangeElem { GapStoryRenderAudioType aud_type; gint32 track; char *audiofile; char *tmp_audiofile; t_GVA_Handle *gvahand; /* API handle for videofile (for GAP_AUT_MOVIE) */ gint32 seltrack; /* selected audiotrack in a videofile (for GAP_AUT_MOVIE) */ gint32 samplerate; /* samples per sec */ gint32 channels; /* 1 mono, 2 stereo */ gint32 bytes_per_sample; gint32 samples; gdouble max_playtime_sec; gdouble wait_untiltime_sec; gint32 wait_until_samples; gdouble range_playtime_sec; gdouble play_from_sec; gdouble play_to_sec; gdouble volume_start; gdouble volume; gdouble volume_end; gdouble fade_in_sec; gdouble fade_out_sec; gint32 audio_id; /* audio cache id */ GapStoryRenderAudioCacheElem *ac_elem; guchar *aud_data; gint32 aud_bytelength; gint32 range_samples; /* number of samples in the selected range (sample has upto 4 bytes) */ gint32 fade_in_samples; gint32 fade_out_samples; gint32 byteoffset_rangestart; gint32 byteoffset_data; void *next; } GapStoryRenderAudioRangeElem; /* used for storyboard processing */ typedef struct GapStoryRenderVTrackAttrElem { gint32 frame_count; /* current total number of frames (until now) in this track */ gint32 overlap_count; /* how much frames to overlap (ignored in shadow tracks) */ gdouble mask_framecount; /* local mask frame progress. reset to 1 for each new clip * that is added via input from storyboard file parsing * but not for internally generated splitted elements */ gboolean keep_proportions; gboolean fit_width; gboolean fit_height; gdouble opacity_from; /* 0.0 upto 1.0 */ gdouble opacity_to; /* 0.0 upto 1.0 */ gint32 opacity_dur; /* number of frames to change from -> to value */ gdouble scale_x_from; /* 0.0 upto 10.0 where 1.0 is fit video size */ gdouble scale_x_to; /* 0.0 upto 10.0 where 1.0 is fit video size */ gint32 scale_x_dur; /* number of frames to change from -> to value */ gdouble scale_y_from; /* 0.0 upto 10.0 where 1.0 is fit video size */ gdouble scale_y_to; /* 0.0 upto 10.0 where 1.0 is fit video size */ gint32 scale_y_dur; /* number of frames to change from -> to value */ gdouble move_x_from; /* -1.0 upto 1.0 where 0 is center and -1.0 left outside */ gdouble move_x_to; /* -1.0 upto 1.0 where 0 is center and -1.0 left outside */ gint32 move_x_dur; /* number of frames to change from -> to value */ gdouble move_y_from; /* -1.0 upto 1.0 where 0 is center and -1.0 up outside */ gdouble move_y_to; /* -1.0 upto 1.0 where 0 is center and -1.0 up outside */ gint32 move_y_dur; /* number of frames to change from -> to value */ } GapStoryRenderVTrackAttrElem; /* Video track attributes used for storyboard processing */ typedef struct GapStoryRenderVTrackArray { GapStoryRenderVTrackAttrElem attr[GAP_STB_MAX_VID_INTERNAL_TRACKS]; gint32 max_tracknum; } GapStoryRenderVTrackArray; /* used for storyboard processing */ typedef struct GapStoryRenderErrors { char *errtext; /* NULL==no error */ char *errline; /* NULL, or copy of the line that has the 1. error */ gint32 errline_nr; /* line number where 1.st error occurred */ char *warntext; /* NULL==no error */ char *warnline; /* NULL, or copy of the line that has the 1. error */ gint32 warnline_nr; /* line number where 1.st error occurred */ gint32 curr_nr; /* current line nr while parsing */ char *currline; /* pointer to currently parsed line (do not free this) */ } GapStoryRenderErrors; /* used for storyboard processing */ typedef struct GapStoryRenderSection { GapStoryRenderFrameRangeElem *frn_list; GapStoryRenderAudioRangeElem *aud_list; gchar *section_name; /* null refers to the main section */ void *next; } GapStoryRenderSection; typedef struct GapStoryRenderVidHandle { GapStoryRenderSection *section_list; GapStoryRenderSection *parsing_section; GapStoryRenderFrameRangeElem *frn_list; GapStoryRenderAudioRangeElem *aud_list; GapStoryRenderErrors *sterr; char *preferred_decoder; char *master_insert_area_format; /* Format for logo replacement */ gboolean master_insert_area_format_has_videobasename; gboolean master_insert_area_format_has_framenumber; /* master video settings found in the storyboard file */ gdouble master_framerate; gint32 master_width; gint32 master_height; gint32 master_samplerate; gdouble master_volume; char *util_sox; char *util_sox_options; gboolean ignore_audio; gboolean ignore_video; gboolean create_audio_tmp_files; gboolean cancel_operation; /* not supported yet */ gdouble *progress; gdouble dummy_progress; /* progress points to dummy_progress if no * external progress_ptr was specified at * opening of the video handle. */ gboolean do_gimp_progress; /* pass this to GVA gvahand->do_gimp_progress (to show video seek progress) */ gchar *status_msg; gint32 status_msg_len; struct GapStoryRenderMaskDefElem *maskdef_elem; /* list of mask definitions */ gboolean is_mask_handle; gint32 ffetch_user_id; } GapStoryRenderVidHandle; /* used for storyboard processing */ /* wrapper struct for mask element definitions * adds video handle for mask access */ typedef struct GapStoryRenderMaskDefElem /* nick: maskdef_elem */ { char *mask_name; /* identifier key string */ gint32 record_type; gint32 frame_count; gint32 flip_request; /* 0 none, 1 flip horizontal, 2 flip vertical, 3 flip both */ GapStoryRenderVidHandle *mask_vidhand; struct GapStoryRenderMaskDefElem *next; } GapStoryRenderMaskDefElem; #endif /* GAP_STORY_RENDER_TYPES_H */ gimp-gap-2.6.0+dfsg.orig/gap/gap_lastvaldesc.c0000644000175000017500000000275711212030253021027 0ustar thibautthibaut/* gap_lastvaldesc.c * * GAP ... Gimp Animation Plugins * * This Module contains: * Procedures to register a plugin's LAST_VALUES buffer description * (needed for animated filtercalls using a common iterator procedure) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 2002/09/21 hof: created. */ /* gimplastvaldesc should become part of libgimp in the future. * if this will come true, HAVE_LASTVALDESC_H will also become DEFINED. * for now GAP Sources include a private version of gimplastvaldesc.c * and must include them explicite because HAVE_LASTVALDESC_H is not defined * (i dont know, if gimplastvaldesc will be a part of libgimp someday -- hof) */ #include "gimplastvaldesc.c" gimp-gap-2.6.0+dfsg.orig/gap/gap_story_section_properties.h0000644000175000017500000000250011212030253023671 0ustar thibautthibaut/* gap_story_section_properties.h * * This module handles GAP storyboard dialog section properties window. */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.26a; 2004/02/18 hof: created */ #ifndef _GAP_STORY_SECTION_PROPERTIES_H #define _GAP_STORY_SECTION_PROPERTIES_H #include "libgimp/gimp.h" #include "gap_story_main.h" void gap_story_spw_properties_dialog (GapStoryBoard *stb, GapStbTabWidgets *tabw); void gap_story_spw_switch_to_section(GapStbSecpropWidget *spw, GapStoryBoard *stb_dst); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_arr_dialog.c0000644000175000017500000020763311212030253020625 0ustar thibautthibaut/* gap_arr_dialog.c * 1998.June.29 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This is the common GTK Dialog for most of the GAP Functions. * (it replaces the older gap_sld_dialog module) * * - gap_arr_ok_cancel_dialog Dialog Window with one or more rows * each row can contain one of the following GAP widgets: * - float pair widget * (horizontal slidebar combined with a float input field) * - int pair widget * (horizontal slidebar combined with a int input field) * - Toggle Button widget * - Textentry widget * - Float entry widget * - Int entry widget * * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 2.1.0a; 2005/01/15 hof: replaced global data (global_arrint) by dynamic allocated data * to enable 2 or more simultan opened gap_arr_dialog based pop-up dialogs * gimp 2.1.0a; 2004/11/11 hof: added GAP_ARR_WGT_HELP_BUTTON * gimp 2.1.0a; 2004/11/05 hof: replaced deprecated option_menu by gimp_int_combo_box * gimp 2.1.0a; 2004/10/09 hof: bugfix GAP_ARR_WGT_OPT_ENTRY (entry height was set to 0) * gimp 2.1.0a; 2004/09/25 hof: gap_arr_create_vindex_permission * gimp 1.3.20d; 2003/10/04 hof: bugfix: added missing implementation for GAP_ARR_WGT_RADIO defaults * gimp 1.3.20a; 2003/09/29 hof: gap_arr_overwrite_file_dialog * gimp 1.3.20a; 2003/09/14 hof: extended function of GAP_ARR_WGT_LABEL GAP_ARR_WGT_LABEL_LEFT GAP_ARR_WGT_LABEL_RIGHT * (caller can provide additional Text via text_buf_ret, * to create 2 Labels) * gimp 1.3.18a; 2003/08/23 hof: gap_arr_slider_dialog increased entry_width from 45 to 80 (to show 6 digits) * gimp 1.3.17b; 2003/07/31 hof: message text fixes for translators (# 118392) * gimp 1.3.17a; 2003/07/28 hof: gimp_interactive_selection_font was renamed to: gimp_font_select_new * gimp 1.3.16c; 2003/07/12 hof: new gap_arr_confirm_dialog * gimp 1.3.15a; 2003/06/21 hof: textspacing * gimp 1.3.14b; 2003/06/03 hof: added gap_stock_init * gimp 1.3.14a; 2003/05/19 hof: GUI standard (OK ist rightmost button) * changed GAP_ARR_WGT_INT, and GAP_ARR_WGT_FLT from entry to spinbutton * added GAP_ARR_WGT_FONTSEL * gimp 1.3.12a; 2003/05/03 hof: merge into CVS-gimp-gap project, replace gimp_help_init by _gimp_help_init * gimp 1.3.11a; 2003/01/18 hof: merged in changes of the gap_vid_enc project * - added GAP_ARR_WGT_OPT_ENTRY (entry comined with Optionmenu) and GAP_ARR_WGT_DEFAULT_BUTTON * gimp 1.3.4a; 2002/03/12 hof: ported to gtk+-2.0.0 * radio_create_value (prevent fire callback to early, needed in new gtk) * bugfix: optionmenu_create_value active menu entry now can have any position * (dont change menuorder any longer, where active item was placed 1st) * gimp 1.1.17b; 2000/01/26 hof: bugfix gimp_help_init * use gimp_scale_entry_new for GAP_ARR_WGT_FLT_PAIR, GAP_ARR_WGT_INT_PAIR * gimp 1.1.17a; 2000/02/20 hof: use gimp_help_set_help_data for tooltips * gimp 1.1.13b; 1999/12/04 hof: some cosmetic gtk fixes * changed border_width spacing and Buttons in action area * to same style as used in dialogs of the gimp 1.1.13 main dialogs * gimp 1.1.11b; 1999/11/20 hof: some cosmetic gtk fixes: * - allow X-expansion (useful for the scale widgets) * - use a hbox on GAP_ARR_WGT_INT_PAIR and GAP_ARR_WGT_FLT_PAIR * (reduces the waste of horizontal space * when used together with other widget types in the table) * gimp 1.1.5.1; 1999/05/08 hof: call fileselect in gtk+1.2 style * version 0.96.03; 1998/08/15 hof: p_arr_gtk_init * version 0.96.01; 1998/07/09 hof: Bugfix: gtk_init should be called only * once in a plugin process * version 0.96.00; 1998/07/09 hof: 1.st release * (re-implementation of gap_sld_dialog.c) */ #include "config.h" #include #include #include #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" #include "libgimp/gimpui.h" /* private includes */ #include "gap_libgapbase.h" #include "gap_arr_dialog.h" #include "gap_stock.h" #include "gap-intl.h" /* default alignment for labels 0.0 == left, 1.0 == right */ #define LABEL_DEFAULT_ALIGN_X 0.0 #define LABEL_DEFAULT_ALIGN_Y 0.5 #define GAP_ARR_INTERFACE_PTR "gap_arr_interface_ptr" typedef void (*t_entry_cb_func) (GtkWidget *widget, GapArrArg *arr_ptr); typedef struct { GapArrArg *arr_ptr; gint radio_index; GtkWidget *radio_button; void *first; void *next; } t_radio_arg; typedef struct { GtkWidget *dlg; gint run; } t_arr_interface; typedef struct { GapArrArg *argv; gint argc; } t_all_arr_args; extern int gap_debug; /* ==0 ... dont print debug infos */ /* Declare local functions. */ static void arr_close_callback (GtkWidget *widget, gpointer data); static void but_array_callback (GtkWidget *widget, gpointer data); static void arr_help_callback (GtkWidget *widget, GapArrArg *arr_ptr); static void entry_create_value (char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr, t_entry_cb_func entry_update_cb, char *init_txt); static void label_create_value (char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr, gfloat align); static void text_entry_update_cb (GtkWidget *widget, GapArrArg *arr_ptr); static void text_create_value (char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr); static void filesel_close_cb (GtkWidget *widget, GapArrArg *arr_ptr); static void filesel_ok_cb (GtkWidget *widget, GapArrArg *arr_ptr); static void filesel_open_cb (GtkWidget *widget, GapArrArg *arr_ptr); static void filesel_create_value (char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr); static void int_create_value (char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr); static void flt_create_value (char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr); static void toggle_update_cb (GtkWidget *widget, GapArrArg *arr_ptr); static void toggle_create_value (char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr); static void combo_update_cb (GtkWidget *widget, GapArrArg *arr_ptr); static void radio_update_cb (GtkWidget *widget, t_radio_arg *radio_ptr); static void radio_create_value (char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr); static void combo_create_value (char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr); static void pair_int_create_value (gchar *title, GtkTable *table, gint row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr); static void pair_flt_create_value (gchar *title, GtkTable *table, gint row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr); static void default_button_cb (GtkWidget *widget, t_all_arr_args *arr_all); static void default_button_create_value (char *title, GtkWidget *hbox, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr, t_all_arr_args *arr_all); static void arr_close_callback (GtkWidget *widget, gpointer data) { t_arr_interface *arrint_ptr; GtkWidget *dlg; arrint_ptr = NULL; dlg = NULL; if(widget) { arrint_ptr = (t_arr_interface *) g_object_get_data (G_OBJECT (widget) , GAP_ARR_INTERFACE_PTR ); } if(arrint_ptr) { dlg = arrint_ptr->dlg; arrint_ptr->dlg = NULL; } if(dlg) { gtk_widget_destroy (GTK_WIDGET (dlg)); /* close & destroy dialog window */ gtk_main_quit (); } } static void arr_help_callback (GtkWidget *widget, GapArrArg *arr_ptr) { t_arr_interface *arrint_ptr; arrint_ptr = NULL; if(widget) { arrint_ptr = (t_arr_interface *) g_object_get_data (G_OBJECT (widget) , GAP_ARR_INTERFACE_PTR ); } if((arr_ptr) && (arrint_ptr)) { if(arr_ptr->help_id) { if(arr_ptr->help_func) { /* call user help function */ arr_ptr->help_func (arr_ptr->help_id, arrint_ptr->dlg); } else { /* call gimp standard help function */ gimp_standard_help_func(arr_ptr->help_id, arrint_ptr->dlg); } } } } static void but_array_callback (GtkWidget *widget, gpointer data) { t_arr_interface *arrint_ptr; arrint_ptr = (t_arr_interface *) g_object_get_data (G_OBJECT (widget), GAP_ARR_INTERFACE_PTR); if(arrint_ptr) { arrint_ptr->run = *((gint *)data); /* set returnvalue according to button */ arr_close_callback(arrint_ptr->dlg, NULL); return; } else { arr_close_callback(widget, NULL); } } static void entry_create_value(char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr, t_entry_cb_func entry_update_cb, char *init_txt) { GtkWidget *entry; GtkWidget *label; label = gtk_label_new(title); gtk_misc_set_alignment(GTK_MISC(label), LABEL_DEFAULT_ALIGN_X, LABEL_DEFAULT_ALIGN_Y); gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); entry = gtk_entry_new(); g_object_set_data (G_OBJECT (entry), GAP_ARR_INTERFACE_PTR, (gpointer)arrint_ptr); gtk_widget_set_size_request(entry, arr_ptr->entry_width, -1); gtk_entry_set_text(GTK_ENTRY(entry), init_txt); gtk_table_attach(GTK_TABLE(table), entry, 1, 2, row, row + 1, GTK_FILL, GTK_FILL | GTK_EXPAND, 4, 0); if(arr_ptr->help_txt != NULL) { gimp_help_set_help_data(entry, arr_ptr->help_txt,NULL); } gtk_widget_show(entry); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK (entry_update_cb), arr_ptr); arr_ptr->text_entry = entry; } /* -------------------------- * LABEL * -------------------------- */ static void label_create_value(char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr, gfloat align) { GtkWidget *label; GtkWidget *hbox; gint from_col; from_col = 0; if(arr_ptr->text_buf_ret) { /* the caller provided both label and text * in this case 2 Labels are shown */ label = gtk_label_new(title); gtk_misc_set_alignment(GTK_MISC(label), LABEL_DEFAULT_ALIGN_X, LABEL_DEFAULT_ALIGN_Y); gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); from_col = 1; label = gtk_label_new(arr_ptr->text_buf_ret); } else { /* the caller provided just the Label * in this case we show the label (spread accross all columns) */ from_col = 0; label = gtk_label_new(title); } gtk_misc_set_alignment(GTK_MISC(label), align, LABEL_DEFAULT_ALIGN_Y); if(align != 0.5) { hbox = gtk_hbox_new (FALSE, 2); gtk_widget_show (hbox); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0); gtk_table_attach(table, hbox, from_col, 3, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); } else { gtk_table_attach(table, label, from_col, 3, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); } gtk_widget_show(label); } /* -------------------------- * DEFAULT_BUTTON * -------------------------- */ static void default_button_create_value(char *title, GtkWidget *hbox, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr, t_all_arr_args *arr_all) { GtkWidget *button; button = gtk_button_new_from_stock (GIMP_STOCK_RESET); /*button = gtk_button_new_with_label (title);*/ g_object_set_data (G_OBJECT (button), GAP_ARR_INTERFACE_PTR, (gpointer)arrint_ptr); gtk_widget_show(button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK(default_button_cb), arr_all); gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); /* gtk_table_attach(table, button, 0, 3, row, row + 1, GTK_FILL, 0, 0, 0); */ if(arr_ptr->help_txt != NULL) { gimp_help_set_help_data(button, arr_ptr->help_txt,NULL); } } /* end default_button_create_value */ static void default_button_cb(GtkWidget *widget, t_all_arr_args *arr_all) { gint l_idx; GapArrArg *arr_ptr; char *buf; char *fmt; if(arr_all == NULL) { return; } for(l_idx = 0; l_idx < arr_all->argc; l_idx++) { arr_ptr = &arr_all->argv[l_idx]; buf = NULL; if(!arr_ptr->has_default) { continue; } switch(arr_ptr->widget_type) { case GAP_ARR_WGT_TEXT: case GAP_ARR_WGT_FONTSEL: case GAP_ARR_WGT_OPT_ENTRY: if((arr_ptr->text_buf_ret != NULL) && (arr_ptr->text_buf_default)) { strncpy(arr_ptr->text_buf_ret, arr_ptr->text_buf_default, arr_ptr->text_buf_len -1); buf = g_strdup(arr_ptr->text_buf_default); } if(arr_ptr->widget_type == GAP_ARR_WGT_OPT_ENTRY) { arr_ptr->radio_ret = arr_ptr->radio_default; gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (arr_ptr->combo), arr_ptr->radio_ret); } break; case GAP_ARR_WGT_FLT_PAIR: case GAP_ARR_WGT_FLT: arr_ptr->flt_ret = arr_ptr->flt_default; fmt = g_strdup_printf("%%.%df", arr_ptr->flt_digits); buf = g_strdup_printf(fmt, arr_ptr->flt_ret); g_free(fmt); if(arr_ptr->adjustment) { gtk_adjustment_set_value (GTK_ADJUSTMENT (arr_ptr->adjustment), (gfloat)arr_ptr->flt_default); } break; case GAP_ARR_WGT_INT_PAIR: case GAP_ARR_WGT_INT: arr_ptr->int_ret = arr_ptr->int_default; buf = g_strdup_printf("%d", arr_ptr->int_ret); if(arr_ptr->adjustment) { gtk_adjustment_set_value (GTK_ADJUSTMENT (arr_ptr->adjustment), (gfloat)arr_ptr->int_default); } break; case GAP_ARR_WGT_TOGGLE: arr_ptr->int_ret = arr_ptr->int_default; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (arr_ptr->check_button), arr_ptr->int_default); break; case GAP_ARR_WGT_RADIO: arr_ptr->radio_ret = arr_ptr->radio_default; { t_radio_arg *rgp_list; for(rgp_list = (t_radio_arg *)arr_ptr->radiogroup ;rgp_list != NULL ;rgp_list = (t_radio_arg *)rgp_list->next) { if(rgp_list->radio_index == arr_ptr->radio_ret) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (rgp_list->radio_button) , TRUE); break; } } } break; case GAP_ARR_WGT_OPTIONMENU: arr_ptr->radio_ret = arr_ptr->radio_default; gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (arr_ptr->combo), arr_ptr->radio_ret); break; default : break; } /* end switch */ if(buf != NULL) { if(arr_ptr->text_entry != NULL) { gtk_entry_set_text(GTK_ENTRY(arr_ptr->text_entry), buf); } g_free(buf); } } /* end for */ } /* end default_button_cb */ /* -------------------------- * FONTSEL * -------------------------- */ static void p_font_callback (gchar *name ,gboolean dialog_closing ,gpointer user_data) { GapArrArg *arr_ptr; if(gap_debug) printf("p_font_callback: %s closing:%d\n", name, (int)dialog_closing); arr_ptr = (GapArrArg *)user_data; if(arr_ptr) { g_snprintf(arr_ptr->text_buf_ret, arr_ptr->text_buf_len, "%s", name); gtk_entry_set_text(GTK_ENTRY(arr_ptr->text_entry), arr_ptr->text_buf_ret); } if(dialog_closing) { arr_ptr->text_fontsel = NULL; } } static void fontsel_open_cb(GtkWidget *widget, GapArrArg *arr_ptr) { const gchar *fontsel; if(arr_ptr->text_fontsel != NULL) return; /* fontsel is already open */ fontsel = gimp_font_select_new (arr_ptr->label_txt /* *dialogname */ , arr_ptr->text_buf_ret /* *font_name */ , (GimpRunFontCallback) p_font_callback , arr_ptr /* gpointer data */ ); arr_ptr->text_fontsel = fontsel; } static void fontsel_create_value(char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr) { GtkWidget *button; entry_create_value(title, table, row, arr_ptr, arrint_ptr, text_entry_update_cb, arr_ptr->text_buf_ret); gtk_widget_set_sensitive(arr_ptr->text_entry ,FALSE); arr_ptr->text_fontsel = NULL; /* Button to invoke fontbrowser */ button = gtk_button_new_with_label ( _("Font Browser")); gtk_table_attach( GTK_TABLE(table), button, 2, 3, row, row +1, 0, 0, 0, 0 ); if(arr_ptr->help_txt != NULL) { gimp_help_set_help_data(button, arr_ptr->help_txt,NULL); } gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (fontsel_open_cb), arr_ptr); } /* -------------------------- * FILESEL * -------------------------- */ static void filesel_close_cb(GtkWidget *widget, GapArrArg *arr_ptr) { if(arr_ptr->text_filesel == NULL) return; /* filesel is already closed */ gtk_widget_destroy(GTK_WIDGET(arr_ptr->text_filesel)); arr_ptr->text_filesel = NULL; } static void filesel_ok_cb(GtkWidget *widget, GapArrArg *arr_ptr) { const gchar *filename; if(arr_ptr->text_filesel == NULL) return; /* filesel is already closed */ filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (arr_ptr->text_filesel)); strncpy(arr_ptr->text_buf_ret, filename, arr_ptr->text_buf_len -1); gtk_entry_set_text(GTK_ENTRY(arr_ptr->text_entry), filename); filesel_close_cb(widget, arr_ptr); } static void filesel_open_cb(GtkWidget *widget, GapArrArg *arr_ptr) { GtkWidget *filesel; if(arr_ptr->text_filesel != NULL) { gtk_window_present(GTK_WINDOW(arr_ptr->text_filesel)); return; /* filesel is already open */ } filesel = gtk_file_selection_new (arr_ptr->label_txt); arr_ptr->text_filesel = filesel; gtk_window_set_position (GTK_WINDOW (filesel), GTK_WIN_POS_MOUSE); gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), arr_ptr->text_buf_ret); gtk_widget_show (filesel); g_signal_connect (G_OBJECT (filesel), "destroy", G_CALLBACK (filesel_close_cb), arr_ptr); g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button), "clicked", G_CALLBACK (filesel_ok_cb), arr_ptr); g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button), "clicked", G_CALLBACK (filesel_close_cb), arr_ptr); } static void filesel_create_value(char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr) { GtkWidget *button; entry_create_value(title, table, row, arr_ptr, arrint_ptr, text_entry_update_cb, arr_ptr->text_buf_ret); arr_ptr->text_filesel = NULL; /* Button to invoke filebrowser */ button = gtk_button_new_with_label ( "..." ); g_object_set_data (G_OBJECT (button), GAP_ARR_INTERFACE_PTR, (gpointer)arrint_ptr); gtk_table_attach( GTK_TABLE(table), button, 2, 3, row, row +1, 0, 0, 0, 0 ); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (filesel_open_cb), arr_ptr); } /* -------------------------- * TEXT * -------------------------- */ static void text_entry_update_cb(GtkWidget *widget, GapArrArg *arr_ptr) { if((arr_ptr->widget_type != GAP_ARR_WGT_TEXT) && (arr_ptr->widget_type != GAP_ARR_WGT_OPT_ENTRY) && (arr_ptr->widget_type != GAP_ARR_WGT_FONTSEL) && (arr_ptr->widget_type != GAP_ARR_WGT_FILESEL)) { return; } strncpy(arr_ptr->text_buf_ret, gtk_entry_get_text(GTK_ENTRY(widget)), arr_ptr->text_buf_len -1); arr_ptr->text_buf_ret[arr_ptr->text_buf_len -1] = '\0'; } static void text_create_value(char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr) { entry_create_value(title, table, row, arr_ptr, arrint_ptr, text_entry_update_cb, arr_ptr->text_buf_ret); } /* -------------------------- * SPIN (INT and FLT) * -------------------------- */ static void spin_create_value(char *title, GtkTable *table, int row , GapArrArg *arr_ptr, t_arr_interface *arrint_ptr , gboolean int_flag , gdouble un_min , gdouble un_max ) { GtkWidget *label; GtkWidget *spinbutton; GtkObject *adj; GtkWidget *hbox1; GtkWidget *label2; gdouble umin, umax; gdouble sstep; gdouble initial_val; gint l_digits; label = gtk_label_new(title); gtk_misc_set_alignment(GTK_MISC(label), LABEL_DEFAULT_ALIGN_X, LABEL_DEFAULT_ALIGN_Y); gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); if(int_flag) { sstep = arr_ptr->int_step; initial_val = (gdouble) arr_ptr->int_ret; l_digits = 0; } else { sstep = arr_ptr->flt_step; initial_val = (gdouble) arr_ptr->flt_ret; l_digits = arr_ptr->flt_digits; } if(arr_ptr->constraint) { umin = un_min; umax = un_max; } else { umin = arr_ptr->umin; umax = arr_ptr->umax; } hbox1 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox1); spinbutton = gimp_spin_button_new (&adj, /* return value */ initial_val, umin, umax, sstep, (gdouble) arr_ptr->pagestep, 0.0, /* page_size */ 1.0, /* climb_rate */ l_digits /* digits */ ); g_object_set_data (G_OBJECT (spinbutton), GAP_ARR_INTERFACE_PTR, (gpointer)arrint_ptr); gtk_widget_set_size_request(spinbutton, arr_ptr->entry_width, -1); gtk_widget_show (spinbutton); label2 = gtk_label_new(" "); gtk_widget_show(label2); gtk_box_pack_start (GTK_BOX (hbox1), spinbutton, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox1), label2, TRUE, TRUE, 0); gtk_table_attach(GTK_TABLE(table), hbox1, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); if(arr_ptr->help_txt != NULL) { gimp_help_set_help_data(spinbutton, arr_ptr->help_txt,NULL); } gtk_widget_show(spinbutton); if(int_flag) { g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (gimp_int_adjustment_update), &arr_ptr->int_ret); } else { g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (gimp_double_adjustment_update), &arr_ptr->flt_ret); } arr_ptr->adjustment = adj; } /* end spin_create_value */ /* -------------------------- * INT * -------------------------- */ static void int_create_value(char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr) { spin_create_value(title, table, row, arr_ptr, arrint_ptr , TRUE /* int_flag */ , (gdouble) arr_ptr->int_min , (gdouble) arr_ptr->int_max ); } /* -------------------------- * FLOAT * -------------------------- */ static void flt_create_value(char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr) { spin_create_value(title, table, row, arr_ptr, arrint_ptr , FALSE /* int_flag */ , (gdouble) arr_ptr->flt_min , (gdouble) arr_ptr->flt_max ); } /* -------------------------- * TOGGLE * -------------------------- */ static void toggle_update_cb (GtkWidget *widget, GapArrArg *arr_ptr) { if(arr_ptr->widget_type !=GAP_ARR_WGT_TOGGLE) return; if (GTK_TOGGLE_BUTTON (widget)->active) { arr_ptr->int_ret = 1; } else { arr_ptr->int_ret = 0; } } static void toggle_create_value(char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr) { GtkWidget *check_button; GtkWidget *label; char *l_togg_txt; label = gtk_label_new(title); gtk_misc_set_alignment(GTK_MISC(label), LABEL_DEFAULT_ALIGN_X, LABEL_DEFAULT_ALIGN_Y); gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); /* (make sure there is only 0 or 1) */ if(arr_ptr->int_ret != 0) arr_ptr->int_ret = 1; if(arr_ptr->togg_label == NULL) l_togg_txt = " "; else l_togg_txt = arr_ptr->togg_label; /* check button */ check_button = gtk_check_button_new_with_label (l_togg_txt); g_object_set_data (G_OBJECT (check_button), GAP_ARR_INTERFACE_PTR, (gpointer)arrint_ptr); gtk_table_attach ( GTK_TABLE (table), check_button, 1, 3, row, row+1, GTK_FILL, 0, 0, 0); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), arr_ptr->int_ret); if(arr_ptr->help_txt != NULL) { gimp_help_set_help_data(check_button, arr_ptr->help_txt,NULL); } gtk_widget_show (check_button); arr_ptr->check_button = check_button; g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (toggle_update_cb), arr_ptr); } /* -------------------------- * COMBO * -------------------------- */ static void combo_update_cb (GtkWidget *widget, GapArrArg *arr_ptr) { gint value; gint radio_index; gint l_idy; if(arr_ptr == NULL) return; if(arr_ptr->widget_locked) return; if((arr_ptr->widget_type != GAP_ARR_WGT_OPTIONMENU) && (arr_ptr->widget_type != GAP_ARR_WGT_OPT_ENTRY)) { return; } radio_index = 0; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value); arr_ptr->int_ret = value; arr_ptr->radio_ret = value; if(gap_debug) printf("radio_update_cb: radio_ret %d\n", (int)value); if((arr_ptr->widget_type == GAP_ARR_WGT_OPT_ENTRY) && (arr_ptr->radio_argv != NULL)) { /* get the radio_index for the selected in value */ for(l_idy=0; l_idy < arr_ptr->radio_argc; l_idy++) { if(value == l_idy) { radio_index = l_idy; break; } } gtk_entry_set_text(GTK_ENTRY(arr_ptr->text_entry), arr_ptr->radio_argv[radio_index]); strncpy(arr_ptr->text_buf_ret, arr_ptr->radio_argv[radio_index], arr_ptr->text_buf_len -1); arr_ptr->text_buf_ret[arr_ptr->text_buf_len -1] = '\0'; } } /* -------------------------- * RADIO * -------------------------- */ static void radio_update_cb (GtkWidget *widget, t_radio_arg *radio_ptr) { if(radio_ptr->arr_ptr == NULL) return; if(radio_ptr->arr_ptr->widget_locked) return; if(radio_ptr->arr_ptr->widget_type != GAP_ARR_WGT_RADIO) { return; } radio_ptr->arr_ptr->int_ret = radio_ptr->radio_index; radio_ptr->arr_ptr->radio_ret = radio_ptr->radio_index; if(gap_debug) printf("radio_update_cb: radio_ret %d\n", (int)radio_ptr->arr_ptr->radio_ret ); } static void radio_create_value(char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr) { GtkWidget *label; GtkWidget *radio_table; GtkWidget *radio_button; GSList *radio_group = NULL; gint l_idy; char *l_radio_txt; const char *l_radio_help_txt; gint l_radio_pressed; gint l_int_ret_initial_value; t_radio_arg *radio_ptr; t_radio_arg *radio_list_root; t_radio_arg *radio_list_prev; l_int_ret_initial_value = arr_ptr->radio_ret; label = gtk_label_new(title); gtk_misc_set_alignment(GTK_MISC(label), LABEL_DEFAULT_ALIGN_X, LABEL_DEFAULT_ALIGN_Y); gtk_table_attach( GTK_TABLE (table), label, 0, 1, row, row+1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); /* radio_table */ radio_table = gtk_table_new (arr_ptr->radio_argc, 2, FALSE); radio_list_root = NULL; radio_list_prev = NULL; for(l_idy=0; l_idy < arr_ptr->radio_argc; l_idy++) { radio_ptr = g_malloc0(sizeof(t_radio_arg)); radio_ptr->arr_ptr = arr_ptr; radio_ptr->radio_index = l_idy; radio_ptr->next = NULL; if(l_idy==0) { radio_list_root = radio_ptr; } if(radio_list_prev) { radio_list_prev->next = radio_ptr; } radio_list_prev = radio_ptr; radio_ptr->first = radio_list_root; arr_ptr->radiogroup = (gpointer)radio_list_root; if(arr_ptr->radio_ret == l_idy) l_radio_pressed = TRUE; else l_radio_pressed = FALSE; l_radio_txt = "null"; if (arr_ptr->radio_argv != NULL) { if (arr_ptr->radio_argv[l_idy] != NULL) l_radio_txt = arr_ptr->radio_argv[l_idy]; } l_radio_help_txt = arr_ptr->help_txt; if (arr_ptr->radio_help_argv != NULL) { if (arr_ptr->radio_help_argv[l_idy] != NULL) l_radio_help_txt = arr_ptr->radio_help_argv[l_idy]; } if(gap_debug) printf("radio_create_value: %02d %s\n", l_idy, l_radio_txt); radio_button = gtk_radio_button_new_with_label ( radio_group, l_radio_txt ); g_object_set_data (G_OBJECT (radio_button), GAP_ARR_INTERFACE_PTR, (gpointer)arrint_ptr); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach ( GTK_TABLE (radio_table), radio_button, 0, 2, l_idy, l_idy+1, GTK_FILL | GTK_EXPAND, 0, 0, 0); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); if(l_radio_help_txt != NULL) { gimp_help_set_help_data(radio_button, l_radio_help_txt, NULL); } gtk_widget_show (radio_button); radio_ptr->radio_button = radio_button; g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (radio_update_cb), radio_ptr); } /* attach radio_table */ gtk_table_attach ( GTK_TABLE (table), radio_table, 1, 3, row, row+1, GTK_FILL | GTK_EXPAND, 0, 0, 0); gtk_widget_show (radio_table); /* the new gtk always calls the callback procedure of the 1st radio item, * if the 1.st item (with index 0) is not the selected one, * and the user makes no further selection * 0 would be returned as result (but this is wrong and not the expected value) * WORKAROUND: * copy initial value to int_ret */ arr_ptr->int_ret = l_int_ret_initial_value; arr_ptr->radio_ret = l_int_ret_initial_value; } /* ---------------------------------------------- * COMBO BOX (replaces the deprecated OPTIONMENU) * ---------------------------------------------- */ /* combo boxes share data structure with GAP_ARR_WGT_RADIO */ static void combo_create_value(char *title, GtkTable *table, int row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr) { GtkWidget *label; GtkWidget *entry; GtkWidget *combo; gint l_idx; gint l_idy; char *l_radio_txt; gint l_col; /* label */ l_col = 0; label = gtk_label_new(title); gtk_misc_set_alignment(GTK_MISC(label), LABEL_DEFAULT_ALIGN_X, LABEL_DEFAULT_ALIGN_Y); gtk_table_attach( GTK_TABLE (table), label, l_col, l_col+1, row, row+1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); /* entry */ if(arr_ptr->widget_type == GAP_ARR_WGT_OPT_ENTRY) { l_col++; entry = gtk_entry_new(); g_object_set_data (G_OBJECT (entry), GAP_ARR_INTERFACE_PTR, (gpointer)arrint_ptr); gtk_widget_set_size_request(entry, arr_ptr->entry_width, -1); gtk_entry_set_text(GTK_ENTRY(entry), arr_ptr->text_buf_ret); gtk_table_attach(GTK_TABLE(table), entry, l_col, l_col+1, row, row + 1, GTK_FILL, GTK_FILL | GTK_EXPAND, 4, 0); if(arr_ptr->help_txt != NULL) { gimp_help_set_help_data(entry, arr_ptr->help_txt,NULL); } gtk_widget_show(entry); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(text_entry_update_cb), arr_ptr); arr_ptr->text_entry = entry; } /* create an empty combo box */ l_col++; combo = g_object_new (GIMP_TYPE_INT_COMBO_BOX, NULL); g_object_set_data (G_OBJECT (combo), GAP_ARR_INTERFACE_PTR, (gpointer)arrint_ptr); g_signal_connect (combo, "changed", G_CALLBACK (combo_update_cb), arr_ptr); gtk_table_attach(GTK_TABLE(table), combo, l_col, l_col+1, row, row +1, GTK_FILL, GTK_FILL, 0, 0); if(arr_ptr->help_txt != NULL) { gimp_help_set_help_data(combo, arr_ptr->help_txt, NULL); } /* fill the combo box liststore with value/label */ l_idx=0; for(l_idy=0; l_idy < arr_ptr->radio_argc; l_idy++) { if(arr_ptr->radio_ret == l_idy) { l_idx = l_idy; } l_radio_txt = "null"; if (arr_ptr->radio_argv != NULL) { if (arr_ptr->radio_argv[l_idy] != NULL) l_radio_txt = arr_ptr->radio_argv[l_idy]; } gimp_int_combo_box_append (GIMP_INT_COMBO_BOX (combo), GIMP_INT_STORE_VALUE, l_idy, GIMP_INT_STORE_LABEL, l_radio_txt, -1); } gtk_widget_show(combo); gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), l_idx); arr_ptr->combo = combo; } /* -------------------------- * FLT_PAIR * -------------------------- */ static void pair_flt_create_value(gchar *title, GtkTable *table, gint row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr) { GtkObject *adj; gfloat umin, umax; if(arr_ptr->constraint) { umin = arr_ptr->flt_min; umax = arr_ptr->flt_max; } else { umin = arr_ptr->umin; umax = arr_ptr->umax; } adj = gimp_scale_entry_new( GTK_TABLE (table), 0, row, /* table col, row */ title, /* label text */ arr_ptr->scale_width, /* scalesize */ arr_ptr->entry_width, /* entrysize */ (gfloat)arr_ptr->flt_ret, /* init value */ (gfloat)arr_ptr->flt_min, /* lower, */ (gfloat)arr_ptr->flt_max, /* upper */ arr_ptr->flt_step, /* step */ arr_ptr->pagestep, /* pagestep */ arr_ptr->flt_digits, /* digits */ arr_ptr->constraint, /* constrain */ umin, umax, /* lower, upper (unconstrained) */ arr_ptr->help_txt, /* tooltip */ NULL); /* privatetip */ g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (gimp_double_adjustment_update), &arr_ptr->flt_ret); arr_ptr->adjustment = adj; } /* -------------------------- * INT_PAIR * -------------------------- */ static void pair_int_create_value(gchar *title, GtkTable *table, gint row, GapArrArg *arr_ptr, t_arr_interface *arrint_ptr) { GtkObject *adj; gfloat umin, umax; if(arr_ptr->constraint) { umin = (gfloat)arr_ptr->int_min; umax = (gfloat)arr_ptr->int_max; } else { umin = arr_ptr->umin; umax = arr_ptr->umax; } adj = gimp_scale_entry_new( GTK_TABLE (table), 0, row, /* table col, row */ title, /* label text */ arr_ptr->scale_width, /* scalesize */ arr_ptr->entry_width, /* entrysize */ (gfloat)arr_ptr->int_ret, /* init value */ (gfloat)arr_ptr->int_min, /* lower, */ (gfloat)arr_ptr->int_max, /* upper */ arr_ptr->int_step, /* step */ arr_ptr->pagestep, /* pagestep */ 0, /* digits */ arr_ptr->constraint, /* constrain */ umin, umax, /* lower, upper (unconstrained) */ arr_ptr->help_txt, /* tooltip */ NULL); /* privatetip */ g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (gimp_int_adjustment_update), &arr_ptr->int_ret); arr_ptr->adjustment = adj; } /* ============================================================================ * gap_arr_std_dialog * * GTK dialog window that has argc rows. * each row contains the widget(s) as defined in argv[row] * * The Dialog has an Action Area with OK and CANCEL Buttons. * ============================================================================ */ gint gap_arr_std_dialog(const char *title_txt, const char *frame_txt, int argc, GapArrArg argv[], int b_argc, GapArrButtonArg b_argv[], gint b_def_val) { GtkWidget *hbbox; GtkWidget *button; GtkWidget *frame; GtkWidget *table; gint l_idx; gint l_ok_value; char *l_label_txt; GapArrArg *arr_ptr; GapArrArg *arr_help_ptr; GapArrArg *arr_def_ptr; t_arr_interface arrint_struct; t_arr_interface *arrint_ptr; arr_def_ptr = NULL; arrint_ptr = &arrint_struct; arrint_ptr->run = b_def_val; /* prepare default retcode (if window is closed without button) */ l_ok_value = 0; table = NULL; arr_help_ptr = NULL; if((argc > 0) && (argv == NULL)) { printf("gap_arr_std_dialog: calling error (widget array == NULL)\n"); return (arrint_ptr->run); } if((b_argc > 0) && (b_argv == NULL)) { printf("gap_arr_std_dialog: calling error (button array == NULL)\n"); return (arrint_ptr->run); } gimp_ui_init ("gap_std_dialog", FALSE); gap_stock_init(); /* dialog */ arrint_ptr->dlg = gtk_dialog_new (); g_object_set_data (G_OBJECT (arrint_ptr->dlg), GAP_ARR_INTERFACE_PTR, (gpointer)arrint_ptr); gtk_window_set_title (GTK_WINDOW (arrint_ptr->dlg), title_txt); // hof: on my Gnome windowmanger (openSUSE 11.11) pop ups created with gtk_dialog_new // often open BEHIND other windows. // // As workaround i commented out placing the pop up on mouse position // (because this would completeley hide the popup behind the other window // when the popup is smaller) // gtk_window_set_position (GTK_WINDOW (arrint_ptr->dlg), GTK_WIN_POS_MOUSE); g_signal_connect (G_OBJECT (arrint_ptr->dlg), "destroy", G_CALLBACK (arr_close_callback), NULL); gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (arrint_ptr->dlg)->action_area), 2); gtk_box_set_homogeneous (GTK_BOX (GTK_DIALOG (arrint_ptr->dlg)->action_area), FALSE); hbbox = GTK_WIDGET(GTK_DIALOG (arrint_ptr->dlg)->action_area); /* parameter settings */ if (frame_txt == NULL) frame = gimp_frame_new ( _("Enter Values")); else frame = gimp_frame_new (frame_txt); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_set_border_width (GTK_CONTAINER (frame), 6); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (arrint_ptr->dlg)->vbox), frame, TRUE, TRUE, 0); if(argc > 0) { /* table (one row per argv) */ table = gtk_table_new (argc +1, 3, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_container_set_border_width (GTK_CONTAINER (table), 4); gtk_container_add (GTK_CONTAINER (frame), table); for(l_idx = 0; l_idx < argc; l_idx++) { arr_ptr = &argv[l_idx]; arr_ptr->widget_locked = TRUE; if(arr_ptr->label_txt == NULL) l_label_txt = g_strdup(_("Value:")); else l_label_txt = g_strdup(arr_ptr->label_txt); switch(arr_ptr->widget_type) { case GAP_ARR_WGT_FLT_PAIR: pair_flt_create_value(l_label_txt, GTK_TABLE(table), (l_idx + 1), arr_ptr, arrint_ptr); break; case GAP_ARR_WGT_INT_PAIR: pair_int_create_value(l_label_txt, GTK_TABLE(table), (l_idx + 1), arr_ptr, arrint_ptr); break; case GAP_ARR_WGT_TOGGLE: toggle_create_value(l_label_txt, GTK_TABLE(table), (l_idx + 1), arr_ptr, arrint_ptr); break; case GAP_ARR_WGT_RADIO: radio_create_value(l_label_txt, GTK_TABLE(table), (l_idx + 1), arr_ptr, arrint_ptr); break; case GAP_ARR_WGT_OPTIONMENU: case GAP_ARR_WGT_OPT_ENTRY: combo_create_value(l_label_txt, GTK_TABLE(table), (l_idx + 1), arr_ptr, arrint_ptr); break; case GAP_ARR_WGT_FILESEL: filesel_create_value(l_label_txt, GTK_TABLE(table), (l_idx + 1), arr_ptr, arrint_ptr); break; case GAP_ARR_WGT_FONTSEL: fontsel_create_value(l_label_txt, GTK_TABLE(table), (l_idx + 1), arr_ptr, arrint_ptr); break; case GAP_ARR_WGT_TEXT: text_create_value(l_label_txt, GTK_TABLE(table), (l_idx + 1), arr_ptr, arrint_ptr); break; case GAP_ARR_WGT_INT: int_create_value(l_label_txt, GTK_TABLE(table), (l_idx + 1), arr_ptr, arrint_ptr); break; case GAP_ARR_WGT_FLT: flt_create_value(l_label_txt, GTK_TABLE(table), (l_idx + 1), arr_ptr, arrint_ptr); break; case GAP_ARR_WGT_LABEL: label_create_value(l_label_txt, GTK_TABLE(table), (l_idx + 1), arr_ptr, arrint_ptr, 0.5); break; case GAP_ARR_WGT_LABEL_LEFT: label_create_value(l_label_txt, GTK_TABLE(table), (l_idx + 1), arr_ptr, arrint_ptr, 0.0); break; case GAP_ARR_WGT_LABEL_RIGHT: label_create_value(l_label_txt, GTK_TABLE(table), (l_idx + 1), arr_ptr, arrint_ptr, 1.0); break; case GAP_ARR_WGT_ACT_BUTTON: printf ("GAP_ARR_WGT_ACT_BUTTON not implemented yet, widget type ignored\n"); break; case GAP_ARR_WGT_DEFAULT_BUTTON: arr_def_ptr = arr_ptr; break; case GAP_ARR_WGT_HELP_BUTTON: arr_help_ptr = arr_ptr; break; default: /* undefined widget type */ printf ("Unknown widget type %d ignored\n", arr_ptr->widget_type); break; } /* end switch */ arr_ptr->widget_locked = FALSE; g_free(l_label_txt); } /* end for */ } /* Action area help-button (if desired) */ if(arr_help_ptr && gimp_show_help_button ()) { if(arr_help_ptr->help_id) { button = gtk_button_new_from_stock (GTK_STOCK_HELP); g_object_set_data (G_OBJECT (button), GAP_ARR_INTERFACE_PTR, (gpointer)arrint_ptr); gtk_box_pack_end (GTK_BOX (hbbox), button, FALSE, TRUE, 0); gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (hbbox), button, TRUE); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK(arr_help_callback), arr_help_ptr); } } if(arr_def_ptr) { t_all_arr_args arr_all; arr_all.argc = argc; arr_all.argv = argv; default_button_create_value(l_label_txt, hbbox, arr_def_ptr, arrint_ptr, &arr_all); } /* buttons in the action area */ for(l_idx = 0; l_idx < b_argc; l_idx++) { if(b_argv[l_idx].but_txt == NULL) { button = gtk_button_new_from_stock (GTK_STOCK_OK); } else { button = gtk_button_new_from_stock (b_argv[l_idx].but_txt); } g_object_set_data (G_OBJECT (button), GAP_ARR_INTERFACE_PTR, (gpointer)arrint_ptr); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0); if( b_argv[l_idx].but_val == b_def_val ) gtk_widget_grab_default (button); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (but_array_callback), &b_argv[l_idx].but_val); } if(b_argc < 1) { /* if no buttons are specified use one CLOSE button per default */ button = gtk_button_new_from_stock ( GTK_STOCK_CLOSE); g_object_set_data (G_OBJECT (button), GAP_ARR_INTERFACE_PTR, (gpointer)arrint_ptr); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0); gtk_widget_grab_default (button); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (but_array_callback), &l_ok_value); } gtk_widget_show (frame); if(argc > 0) { gtk_widget_show (table); } gtk_widget_show (arrint_ptr->dlg); gtk_main (); gdk_flush (); if(gap_debug) { /* for debugging: print results to stdout */ for(l_idx = 0; l_idx < argc; l_idx++) { arr_ptr = &argv[l_idx]; if(arr_ptr->label_txt == NULL) l_label_txt = g_strdup(_("Value:")); else l_label_txt = g_strdup(arr_ptr->label_txt); arr_ptr = &argv[l_idx]; printf("%02d ", l_idx); switch(arr_ptr->widget_type) { case GAP_ARR_WGT_FLT_PAIR: case GAP_ARR_WGT_FLT: printf("FLT %s : %f\n", l_label_txt, arr_ptr->flt_ret); break; case GAP_ARR_WGT_INT_PAIR: case GAP_ARR_WGT_INT: case GAP_ARR_WGT_TOGGLE: printf("INT %s : %d\n", l_label_txt, arr_ptr->int_ret); break; case GAP_ARR_WGT_TEXT: case GAP_ARR_WGT_OPT_ENTRY: case GAP_ARR_WGT_FILESEL: case GAP_ARR_WGT_FONTSEL: printf("TEXT %s : %s\n", l_label_txt, arr_ptr->text_buf_ret); break; case GAP_ARR_WGT_RADIO: case GAP_ARR_WGT_OPTIONMENU: printf("RADIO/OPTIONMENU %s : %d\n", l_label_txt, arr_ptr->radio_ret); break; default: printf("\n"); break; } g_free(l_label_txt); } } return (arrint_ptr->run); } /* end gap_arr_std_dialog */ void gap_arr_arg_init (GapArrArg *arr_ptr, gint widget_type) { arr_ptr->label_txt = NULL; arr_ptr->help_txt = NULL; arr_ptr->help_id = NULL; arr_ptr->help_func = NULL; arr_ptr->togg_label = NULL; arr_ptr->entry_width = 80; arr_ptr->scale_width = 200; arr_ptr->constraint = TRUE; arr_ptr->has_default = FALSE; arr_ptr->text_entry = NULL; arr_ptr->text_buf_len = 0; arr_ptr->text_buf_default = NULL; arr_ptr->text_buf_ret = NULL; arr_ptr->text_fontsel = NULL; arr_ptr->text_filesel = NULL; arr_ptr->text_entry = NULL; arr_ptr->check_button = NULL; arr_ptr->combo = NULL; arr_ptr->adjustment = NULL; arr_ptr->radiogroup = NULL; switch(widget_type) { case GAP_ARR_WGT_LABEL: case GAP_ARR_WGT_LABEL_LEFT: case GAP_ARR_WGT_LABEL_RIGHT: arr_ptr->text_buf_len = 0; arr_ptr->text_buf_default = NULL; arr_ptr->text_buf_ret = NULL; arr_ptr->widget_type = widget_type; break; case GAP_ARR_WGT_INT_PAIR: case GAP_ARR_WGT_INT: arr_ptr->widget_type = widget_type; arr_ptr->umin = (gfloat)G_MININT; arr_ptr->umax = (gfloat)G_MAXINT; arr_ptr->int_min = 0; arr_ptr->int_max = 100; arr_ptr->int_step = 1; arr_ptr->pagestep = 10.0; arr_ptr->int_default = 0; arr_ptr->int_ret = 0; break; case GAP_ARR_WGT_FLT_PAIR: case GAP_ARR_WGT_FLT: arr_ptr->widget_type = widget_type; arr_ptr->flt_digits = 2; arr_ptr->umin = G_MINFLOAT; arr_ptr->umax = G_MAXFLOAT; arr_ptr->flt_min = 0.0; arr_ptr->flt_max = 100.0; arr_ptr->flt_step = 0.1; arr_ptr->pagestep = 10.0; arr_ptr->flt_default = 0.0; arr_ptr->flt_ret = 0.0; break; case GAP_ARR_WGT_TOGGLE: arr_ptr->widget_type = widget_type; arr_ptr->int_default = 0; arr_ptr->int_ret = 0; break; case GAP_ARR_WGT_RADIO: case GAP_ARR_WGT_OPTIONMENU: case GAP_ARR_WGT_OPT_ENTRY: arr_ptr->widget_type = widget_type; arr_ptr->radio_argc = 0; arr_ptr->radio_default = 0; arr_ptr->radio_ret = 0; arr_ptr->radio_argv = NULL; arr_ptr->radio_help_argv = NULL; /* for GAP_ARR_WGT_OPT_ENTRY */ arr_ptr->text_buf_len = 0; arr_ptr->text_buf_default = NULL; arr_ptr->text_buf_ret = NULL; break; case GAP_ARR_WGT_TEXT: case GAP_ARR_WGT_FONTSEL: case GAP_ARR_WGT_FILESEL: arr_ptr->widget_type = widget_type; arr_ptr->text_buf_len = 0; arr_ptr->text_buf_default = NULL; arr_ptr->text_buf_ret = NULL; arr_ptr->text_fontsel = NULL; arr_ptr->text_filesel = NULL; break; case GAP_ARR_WGT_ACT_BUTTON: arr_ptr->widget_type = widget_type; arr_ptr->action_functon = NULL; arr_ptr->action_data = NULL; break; case GAP_ARR_WGT_DEFAULT_BUTTON: case GAP_ARR_WGT_HELP_BUTTON: arr_ptr->widget_type = widget_type; break; default: /* Calling error: undefined widget type */ arr_ptr->widget_type = GAP_ARR_WGT_LABEL; break; } } /* end gap_arr_arg_init */ /* ============================================================================ * simplified calls of gap_arr_std_dialog * ============================================================================ */ gint gap_arr_ok_cancel_dialog(const char *title_txt, const char *frame_txt, int argc, GapArrArg argv[]) { static GapArrButtonArg b_argv[2]; b_argv[1].but_txt = GTK_STOCK_OK; b_argv[1].but_val = TRUE; b_argv[0].but_txt = GTK_STOCK_CANCEL; b_argv[0].but_val = FALSE; return( gap_arr_std_dialog(title_txt, frame_txt, argc, argv, /* widget array */ 2, b_argv, /* button array */ FALSE) ); /* ret value for window close */ } /* ============================================================================ * gap_arr_buttons_dialog * dialog window wit 1 upto n buttons * return: the value aassigned with the pressed button. * (If window closed by windowmanager return b_def_val) * ============================================================================ */ gint gap_arr_buttons_dialog(const char *title_txt, const char *msg_txt, int b_argc, GapArrButtonArg b_argv[], gint b_def_val) { static GapArrArg argv[1]; char *frame_txt; if(b_argc == 1) frame_txt = _("Press Button"); else frame_txt = _("Select"); gap_arr_arg_init(&argv[0], GAP_ARR_WGT_LABEL); argv[0].label_txt = msg_txt; return( gap_arr_std_dialog(title_txt, frame_txt, 1, argv, b_argc, b_argv, b_def_val) ); /* ret value for window close */ } /* end gap_arr_buttons_dialog */ /* ============================================================================ * gap_arr_slider_dialog * simplified call of gap_arr_ok_cancel_dialog, using an array with one value. * * return the value of the (only) entryfield * or -1 in case of Error or cancel * ============================================================================ */ long gap_arr_slider_dialog(const char *title, const char *frame, const char *label, const char *tooltip, long min, long max, long curr, long constraint, const char *help_id) { static GapArrArg argv[2]; gboolean l_rc; gint argc; argc = 0; gap_arr_arg_init(&argv[argc], GAP_ARR_WGT_INT_PAIR); argv[argc].label_txt = label; argv[argc].help_txt = tooltip; argv[argc].constraint = constraint; argv[argc].entry_width = 80; argv[argc].scale_width = 130; argv[argc].int_min = (gint)min; argv[argc].int_max = (gint)max; argv[argc].int_step = 1; argv[argc].int_ret = (gint)curr; argc++; if(help_id) { gap_arr_arg_init(&argv[argc], GAP_ARR_WGT_HELP_BUTTON); argv[argc].help_id = help_id; argc++; } l_rc = gap_arr_ok_cancel_dialog(title, frame, argc, argv); if(l_rc == TRUE) { return (long)(argv[0].int_ret); } else return -1; } /* end gap_arr_slider_dialog */ /* ------------------------ * gap_arr_confirm_dialog * ------------------------ */ gboolean gap_arr_confirm_dialog(const char *msg_txt, const char *title_txt, const char *frame_txt) { static GapArrButtonArg l_but_argv[2]; static GapArrArg l_argv[1]; gboolean l_continue; gboolean l_confirm; char *value_string; l_confirm = TRUE; value_string = gimp_gimprc_query("video-confirm-frame-delete"); if(value_string) { if(gap_debug) printf("video-confirm-frame-delete: %s\n", value_string); /* check if gimprc preferences value no disables confirmation dialog */ if((*value_string == 'n') || (*value_string == 'N')) { l_confirm = FALSE; } g_free(value_string); } else { if(gap_debug) printf("NOT found in gimprc: video-confirm-frame-delete:\n (CONFIRM default yes is used)"); } if(!l_confirm) { /* automatic confirmed OK (dialog is disabled) */ return TRUE; } l_but_argv[0].but_txt = GTK_STOCK_CANCEL; l_but_argv[0].but_val = -1; l_but_argv[1].but_txt = GTK_STOCK_OK; l_but_argv[1].but_val = 0; gap_arr_arg_init(&l_argv[0], GAP_ARR_WGT_LABEL); l_argv[0].label_txt = msg_txt; l_continue = gap_arr_std_dialog (title_txt ,frame_txt ,G_N_ELEMENTS(l_argv), l_argv ,G_N_ELEMENTS(l_but_argv), l_but_argv ,-1 /* default value is Cancel */ ); if(l_continue == 0) { return TRUE; /* OK pressed */ } return FALSE; } /* end gap_arr_confirm_dialog */ /* ----------------------------- * gap_arr_overwrite_file_dialog * ----------------------------- * if file exists ask for overwrite permission * return TRUE : caller may (over)write the file * FALSE: do not write the file */ gboolean gap_arr_overwrite_file_dialog(const char *filename) { static GapArrButtonArg l_argv[2]; static GapArrArg argv[1]; if(g_file_test(filename, G_FILE_TEST_EXISTS)) { gint l_rc; gchar *l_msg; gint l_ii; l_ii = 0; if(g_file_test(filename, G_FILE_TEST_IS_DIR)) { l_msg = g_strdup_printf(_("Directory '%s' already exists"), filename); /* filename is a directory, do not show the Overwrite Button */ } else { l_msg = g_strdup_printf(_("File '%s' already exists"), filename); l_argv[l_ii].but_txt = _("Overwrite"); l_argv[l_ii].but_val = 0; l_ii++; } l_argv[l_ii].but_txt = GTK_STOCK_CANCEL; l_argv[l_ii].but_val = -1; gap_arr_arg_init(&argv[0], GAP_ARR_WGT_LABEL); argv[0].label_txt = l_msg; l_rc =gap_arr_std_dialog ( _("GAP Question"), _("File Overwrite Warning"), 1, argv, 2, l_argv, -1); g_free(l_msg); if(l_rc < 0) { return (FALSE); /* CANCEL was pressed, dont overwrite */ } } return (TRUE); } /* end gap_arr_overwrite_file_dialog */ /* ---------------------------- * gap_arr_msg_win * ---------------------------- * print a message both to stdout * and to the gimp image window (only when run INTERACTIVE) * */ void gap_arr_msg_win(GimpRunMode run_mode, const char *msg) { if(msg) { if(*msg) { printf("%s\n", msg); if(run_mode == GIMP_RUN_INTERACTIVE) { g_message (msg); } } } } /* end gap_arr_msg_win */ /* ---------------------------- * gap_arr_msg_popup * ---------------------------- * print a message both to stdout * and to a popup dialog window with OK button (only when run INTERACTIVE) * */ void gap_arr_msg_popup(GimpRunMode run_mode, const char *msg) { static GapArrButtonArg b_argv[1]; static GapArrArg argv[1]; b_argv[1].but_txt = GTK_STOCK_OK; b_argv[1].but_val = TRUE; gap_arr_arg_init(&argv[0], GAP_ARR_WGT_LABEL); argv[0].label_txt = msg; if(msg) { if(*msg) { printf("%s\n", msg); if(run_mode == GIMP_RUN_INTERACTIVE) { gap_arr_std_dialog ( _("GAP Message") ,"" ,G_N_ELEMENTS(argv), argv ,G_N_ELEMENTS(b_argv), b_argv ,-1 /* default value is Cancel */ ); } } } } /* end gap_arr_msg_popup */ /* -------------------------------------- * p_mkdir_from_file_if_not_exists * -------------------------------------- * return TRUE if directory part of the specifed filename already exists * or did not exist, but could be created successfully. * return FALSE if directory part does not exist and could not be created. */ int p_mkdir_from_file_if_not_exists (const char *fname, int mode) { gint l_ii; char *l_dir; gboolean l_rc; l_rc = TRUE; /* assume success */ if(fname != NULL) { /* build directory name from filename */ l_dir = g_strdup(fname); for(l_ii = strlen(l_dir) -1; l_ii >= 0; l_ii--) { if(l_dir[l_ii] == G_DIR_SEPARATOR) { l_dir[l_ii] = '\0'; break; } l_dir[l_ii] = '\0'; } if(*l_dir != '\0') { /* check if directory already exists */ if(!g_file_test(l_dir, G_FILE_TEST_IS_DIR)) { gint l_errno; if(0 != gap_file_mkdir(l_dir, mode)) { l_errno = errno; g_message(_("ERROR: could not create directory:" "'%s'" "%s") ,l_dir ,g_strerror (l_errno) ); l_rc = FALSE;/* can not create vindex (invalid direcory path) */ } } } g_free(l_dir); } return(l_rc); } /* end p_mkdir_from_file_if_not_exists */ /* -------------------------------- * p_check_vindex_file * -------------------------------- */ static gboolean p_check_vindex_file(const char *vindex_file) { gboolean l_rc; l_rc = TRUE; /* assume success */ if(vindex_file) { l_rc = p_mkdir_from_file_if_not_exists(vindex_file, GAP_FILE_MKDIR_MODE); if(l_rc) { if(!g_file_test(vindex_file, G_FILE_TEST_EXISTS)) { FILE *fp; gint l_errno; /* try to pre-create an empty videoindex file * this is done to check file creation errors immediate. * without this pre-create check the error would be detected very late * (after minutes minutes on large videos) * when the whole video was scanned and the index * should be written to file. */ fp = g_fopen(vindex_file, "wb"); if(fp) { fclose(fp); /* OK, empty file written */ } else { l_errno = errno; g_message(_("ERROR: Failed to write videoindex\n" "file: '%s'\n" "%s") , vindex_file , g_strerror (l_errno)); l_rc = FALSE; } } } } return(l_rc); } /* end p_check_vindex_file */ /* -------------------------------- * gap_arr_create_vindex_permission * -------------------------------- * this procedure checks permission to create videoindex files * if permission is granted, but the videoindex name * does not reside in a valid directory, the procedure tries to * create the directory automatically * (but this is limited to a simple mkdir call and will create just one directory * not the full path if parent directories are invalid too) * * return TRUE : OK, permission to create videoindex * (for already existing videoindex * TRUE is returned if gimprc settings * permit videoindex creation) * FALSE: user has cancelled, dont create videoindex */ gboolean gap_arr_create_vindex_permission(const char *videofile, const char *vindex_file , gint32 seek_status) { static GapArrArg argv[6]; gint l_ii; char *value_string; char *l_videofile; char *l_vindex_file; char *l_info_msg; char *l_status_info; gboolean l_rc; gboolean l_ask_always; #define SEEK_STATUS_SEEKSUPP_NONE 0 #define SEEK_STATUS_SEEKSUPP_VINDEX 1 #define SEEK_STATUS_SEEKSUPP_NATIVE 2 l_ask_always = FALSE; l_videofile = NULL; l_vindex_file = NULL; value_string = gimp_gimprc_query("video-index-creation"); if(value_string) { if((*value_string == 'n') || (*value_string == 'N')) { return(FALSE); /* gimprc setting refuses permission to create videoindex */ } } l_rc = p_mkdir_from_file_if_not_exists(vindex_file, GAP_FILE_MKDIR_MODE); if (l_rc != TRUE) { return(l_rc); } l_rc = FALSE; if(value_string) { /* check if gimprc setting grants general permission to create */ if((*value_string == 'y') || (*value_string == 'Y')) { if ((seek_status == SEEK_STATUS_SEEKSUPP_NONE) || (seek_status == SEEK_STATUS_SEEKSUPP_NATIVE)) { /* never automatically create videoindex for videos where * - seek is NOT possible (even with a video index) * - native seek support is available (without having video index) */ return(FALSE); } l_rc = p_check_vindex_file(vindex_file); return(l_rc); } if (strcmp(value_string, "ask-always") == 0) { l_ask_always = TRUE; } } if (!l_ask_always) { if (seek_status == SEEK_STATUS_SEEKSUPP_NATIVE) { return(FALSE); } } l_info_msg = g_strdup_printf(_("Do you want to create a videoindex file ?\n" "\n" "If you want GIMP-GAP to create videoindex files automatically\n" "when recommanded, whithout showing up this dialog again\n" "then you should add the following line to\n" "your gimprc file:\n" "%s") , "(video-index-creation \"yes\")" ); l_ii = 0; gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_LABEL_LEFT); argv[l_ii].label_txt = " "; argv[l_ii].text_buf_ret = l_info_msg; l_ii++; gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_LABEL_LEFT); argv[l_ii].label_txt = " "; argv[l_ii].text_buf_ret = " "; l_ii++; gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_LABEL_LEFT); argv[l_ii].label_txt = " "; l_status_info = g_strdup("\0"); switch (seek_status) { case SEEK_STATUS_SEEKSUPP_NONE: l_status_info = g_strdup_printf(_("WARNING:\nrandom positioning is not possible for this video.\n" "creating a video index is NOT recommanded\n" "(would not work)\n")); break; case SEEK_STATUS_SEEKSUPP_VINDEX: l_status_info = g_strdup_printf(_("TIP:\ncreating a video index on this video is recommanded.\n" "This will enable fast and random frame access.\n" "but requires one initial full scann.\n" "(this will take a while).\n")); break; case SEEK_STATUS_SEEKSUPP_NATIVE: l_status_info = g_strdup_printf(_("INFO:\nnative fast and exact random positioning works for this video.\n" "video index is not required, and should be cancelled.\n")); break; } argv[l_ii].text_buf_ret = l_status_info; if(videofile) { l_videofile = g_strdup(videofile); l_ii++; gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_LABEL_LEFT); argv[l_ii].label_txt = _("Video:"); argv[l_ii].text_buf_ret = l_videofile; } if(vindex_file) { l_vindex_file = g_strdup(vindex_file); l_ii++; gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_LABEL_LEFT); argv[l_ii].label_txt = _("Index:"); argv[l_ii].text_buf_ret = l_vindex_file; } l_ii++; l_rc = gap_arr_ok_cancel_dialog( _("Create Videoindex file"), " ", l_ii, argv); if(l_rc) { l_rc = p_check_vindex_file(vindex_file); } if(l_videofile) { g_free(l_videofile); } if(l_vindex_file) { g_free(l_vindex_file); } g_free(l_info_msg); g_free(l_status_info); return (l_rc); } /* end gap_arr_create_vindex_permission */ gimp-gap-2.6.0+dfsg.orig/gap/gap_story_main.c0000644000175000017500000002305411212030253020677 0ustar thibautthibaut/* gap_story_main.c * This module handles GAP storyboard level1 editing * 2004/01/23 */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ static char *plug_in_version_fmt = "%d.%d.%d; 2004/01/26"; /* Revision history * version 1.3.25a; 2004/01/26 hof: created */ #include "config.h" #include #include #include #include #include #include #include "gap_story_main.h" #include "gap_story_dialog.h" #include "gap_player_dialog.h" #include "gap_pview_da.h" #include "gap-intl.h" /* Defines */ #define PLUG_IN_IMAGE_TYPES "RGB*, INDEXED*, GRAY*" #define PLUG_IN_AUTHOR "Wolfgang Hofer (hof@gimp.org)" #define PLUG_IN_COPYRIGHT "Wolfgang Hofer" int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */ static GapStbMainGlobalParams global_params = { GIMP_RUN_INTERACTIVE , FALSE /* initialized */ , FALSE /* gboolean run */ , -1 /* gint32 image_id */ , "\0" /* storyboard_filename */ , "\0" /* cliplist_filename */ , NULL /* stb storyboard pointer */ , NULL /* cll cliplist pointer */ , NULL /* curr_selection (list holds all selected items) */ , NULL /* plp player param pointer */ , NULL /* GapStbTabWidgets *stb_widgets */ , NULL /* GapStbTabWidgets *cll_widgets */ , NULL /* GapStoryVTResurceElem *video_list */ , NULL /* GapVThumbElem *vthumb_list */ , NULL /* t_GVA_Handle *gvahand */ , NULL /* gchar *gva_videofile */ , NULL /* GtkWidget *progress_bar_master */ , NULL /* GtkWidget *progress_bar_sub */ , FALSE /* gboolean gva_lock */ , FALSE /* gboolean cancel_video_api */ , FALSE /* gboolean auto_vthumb */ , FALSE /* gboolean auto_vthumb_refresh_canceled */ , FALSE /* gboolean in_player_call */ , FALSE /* gboolean arr_dlg_open */ , FALSE /* gboolean force_stb_aspect */ , GAP_STB_CLIPTARGET_CLIPLIST_APPEND /* GapStoryClipTargetEnum clip_target */ , GAP_VTHUMB_PREFETCH_NOT_ACTIVE /* GapVThumbPrefetchProgressMode vthumb_prefetch_in_progress */ , FALSE /* gboolean win_prop_dlg_open */ , GAP_STB_EDMO_SEQUENCE_NUMBER /* gint32 cll_edmode */ , 5 /* gint32 cll_cols */ , 6 /* gint32 cll_rows */ , 66 /* gint32 cll_thumbsize */ , GAP_STB_EDMO_FRAME_NUMBER /* gint32 stb_edmode */ , 12 /* gint32 stb_cols */ , 2 /* gint32 stb_rows */ , 66 /* gint32 stb_thumbsize */ , NULL /* GtkWidget *shell_window */ , NULL /* GtkWidget *player_frame */ , NULL /* GtkWidget *menu_item_win_vthumbs */ , NULL /* GtkWidget *menu_item_stb_save */ , NULL /* GtkWidget *menu_item_stb_save_as */ , NULL /* GtkWidget *menu_item_stb_add_clip */ , NULL /* GtkWidget *menu_item_stb_add_section_clip */ , NULL /* GtkWidget *menu_item_stb_playback */ , NULL /* GtkWidget *menu_item_stb_properties */ , NULL /* GtkWidget *menu_item_stb_att_properties */ , NULL /* GtkWidget *menu_item_stb_audio_otone */ , NULL /* GtkWidget *menu_item_stb_encode */ , NULL /* GtkWidget *menu_item_stb_undo */ , NULL /* GtkWidget *menu_item_stb_redo */ , NULL /* GtkWidget *menu_item_stb_close */ , NULL /* GtkWidget *menu_item_cll_save */ , NULL /* GtkWidget *menu_item_cll_save_as */ , NULL /* GtkWidget *menu_item_cll_add_clip */ , NULL /* GtkWidget *menu_item_cll_add_section_clip */ , NULL /* GtkWidget *menu_item_cll_playback */ , NULL /* GtkWidget *menu_item_cll_properties */ , NULL /* GtkWidget *menu_item_cll_att_properties */ , NULL /* GtkWidget *menu_item_cll_audio_otone */ , NULL /* GtkWidget *menu_item_cll_encode */ , NULL /* GtkWidget *menu_item_cll_undo */ , NULL /* GtkWidget *menu_item_cll_redo */ , NULL /* GtkWidget *menu_item_cll_close */ }; static void query (void); static void run (const gchar *name, gint nparams, /* number of parameters passed in */ const GimpParam * param, /* parameters passed in */ gint *nreturn_vals, /* number of parameters returned */ GimpParam ** return_vals); /* parameters to be returned */ /* Global Variables */ GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run /* run_proc */ }; static GimpParamDef in_args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive"}, { GIMP_PDB_IMAGE, "image", "Input image" }, { GIMP_PDB_DRAWABLE, "drawable", "UNUSED"}, }; /* Functions */ MAIN () static void query (void) { char *l_plug_in_version; /* get version numbers from config.h (that is derived from ../configure.in) */ l_plug_in_version = g_strdup_printf(plug_in_version_fmt ,GAP_MAJOR_VERSION ,GAP_MINOR_VERSION ,GAP_MICRO_VERSION ); gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); /* the actual installation of the plugin */ gimp_install_procedure (GAP_STORY_PLUG_IN_PROC, "Storyboardfile Editor", "This plug-in is an interactive GUI to create edit storyboard level1 files, " "storyboard level1 files are videoframe playlist textfiles" "that can be used for playback and encoding", PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, l_plug_in_version, N_("Storyboard..."), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, G_N_ELEMENTS (in_args), 0, /* G_N_ELEMENTS (out_args) */ in_args, NULL /* out_args */ ); // gimp_plugin_menu_branch_register("", "Video"); gimp_plugin_menu_register (GAP_STORY_PLUG_IN_PROC, N_("/Video/")); g_free(l_plug_in_version); } /* end query */ static void run (const gchar *name, /* name of plugin */ gint nparams, /* number of in-paramters */ const GimpParam * param, /* in-parameters */ gint *nreturn_vals, /* number of out-parameters */ GimpParam ** return_vals) /* out-parameters */ { const gchar *l_env; gint32 image_id = -1; GapStbMainGlobalParams *sgpp = &global_params; /* Get the runmode from the in-parameters */ GimpRunMode run_mode = param[0].data.d_int32; /* status variable, use it to check for errors in invocation usualy only * during non-interactive calling */ GimpPDBStatusType status = GIMP_PDB_SUCCESS; /* always return at least the status to the caller. */ static GimpParam values[1]; INIT_I18N(); l_env = g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } if(gap_debug) fprintf(stderr, "\n\nDEBUG: run %s\n", name); /* initialize the return of the status */ values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; *nreturn_vals = 1; *return_vals = values; /* get image and drawable */ image_id = param[1].data.d_int32; switch (run_mode) { case GIMP_RUN_INTERACTIVE: /* Possibly retrieve data from a previous run */ gimp_get_data (GAP_STORY_PLUG_IN_PROC, sgpp); break; case GIMP_RUN_NONINTERACTIVE: /* check to see if invoked with the correct number of parameters */ /* if (nparams == G_N_ELEMENTS (in_args)) */ { printf("%s: noninteractive call NOT supported.\n" , GAP_STORY_PLUG_IN_PROC ); status = GIMP_PDB_CALLING_ERROR; } break; case GIMP_RUN_WITH_LAST_VALS: /* Possibly retrieve data from a previous run */ gimp_get_data (GAP_STORY_PLUG_IN_PROC, sgpp); break; default: break; } if (status == GIMP_PDB_SUCCESS) { sgpp->image_id = image_id; sgpp->initialized = FALSE; sgpp->run_mode = run_mode; sgpp->plp = NULL; sgpp->stb = NULL; sgpp->cll = NULL; gap_storyboard_dialog(sgpp); /* Store variable states for next run */ if (run_mode == GIMP_RUN_INTERACTIVE) gimp_set_data (GAP_STORY_PLUG_IN_PROC, sgpp, sizeof (GapStbMainGlobalParams)); } values[0].data.d_status = status; } /* end run */ gimp-gap-2.6.0+dfsg.orig/gap/gap_story_syntax.c0000644000175000017500000003337211212030253021305 0ustar thibautthibaut/* gap_story_syntax.c * * This module handles GAP storyboard file syntax list for * named parameters parsing support of storyboard level1 files * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 2.1.0a; 2004/04/24 hof: created */ #include #include #include #include "gap_story_syntax.h" typedef struct GapStbSyntaxParElem { gint par_idx; gchar *parname; void *next; } GapStbSyntaxParElem; typedef struct GapStbSyntaxElem { gchar *record_key; /* keyword record identifier string */ GapStbSyntaxParElem *par_list; void *next; } GapStbSyntaxElem; static GapStbSyntaxElem *global_syntax_par_list = NULL; static void p_add_keyword(const char *record_key , ... ); static void p_create_syntax_list(void); /* ------------------------------------- * p_add_keyword * ------------------------------------- */ static void p_add_keyword(const char *record_key , ... ) { va_list args; const char *parname; GapStbSyntaxElem *sxpar_elem; GapStbSyntaxParElem *par_elem; gint par_idx; sxpar_elem = g_new(GapStbSyntaxElem, 1); sxpar_elem->record_key = g_strdup(record_key); sxpar_elem->par_list = NULL; sxpar_elem->next = global_syntax_par_list; global_syntax_par_list = sxpar_elem; par_idx = 1; va_start (args, record_key); parname = va_arg (args, const char *); while (parname) { par_elem = g_new(GapStbSyntaxParElem, 1); par_elem->par_idx = par_idx; par_idx++; par_elem->parname = g_strdup(parname); par_elem->next = sxpar_elem->par_list; sxpar_elem->par_list = par_elem; parname = va_arg (args, const char *); } va_end (args); } /* end p_add_keyword */ /* ------------------------------------- * gap_stb_syntax_get_parname_idx * ------------------------------------- * return the expected postion of the parameter * with name == keyword for the record type specified by record_key * return -1 if the specified record type has no paramter name == keyword */ gint gap_stb_syntax_get_parname_idx(const char *record_key ,const char *parname ) { GapStbSyntaxElem *sp_elem; if(global_syntax_par_list == NULL) { p_create_syntax_list(); } if((record_key == NULL) || (parname == NULL)) { return(-1); } for(sp_elem = global_syntax_par_list; sp_elem != NULL; sp_elem = (GapStbSyntaxElem *)sp_elem->next) { if(strcmp(record_key, sp_elem->record_key) == 0) { GapStbSyntaxParElem *par; for(par=sp_elem->par_list; par != NULL; par = (GapStbSyntaxParElem *)par->next) { if(strcmp(par->parname, parname) == 0) { return(par->par_idx); } } return(-1); } } return(-1); } /* end gap_stb_syntax_get_parname_idx */ /* ------------------------------------- * gap_stb_syntax_get_parname * ------------------------------------- * return the parameter name for the given recodrd_key and index * return NULL if no param found. * the caller must g_free the returned string */ char * gap_stb_syntax_get_parname(const char *record_key ,gint par_idx ) { GapStbSyntaxElem *sp_elem; if(global_syntax_par_list == NULL) { p_create_syntax_list(); } if(record_key == NULL) { return(NULL); } for(sp_elem = global_syntax_par_list; sp_elem != NULL; sp_elem = (GapStbSyntaxElem *)sp_elem->next) { if(strcmp(record_key, sp_elem->record_key) == 0) { GapStbSyntaxParElem *par; for(par=sp_elem->par_list; par != NULL; par = (GapStbSyntaxParElem *)par->next) { if(par->par_idx == par_idx) { if(par->parname) { return(g_strdup(par->parname)); } return(NULL); } } return(NULL); } } return(NULL); } /* end gap_stb_syntax_get_parname */ /* ------------------------------------- * gap_stb_syntax_get_parname_tab * ------------------------------------- */ void gap_stb_syntax_get_parname_tab(const char *record_key ,GapStbSyntaxParnames *par_tab ) { GapStbSyntaxElem *sp_elem; par_tab->tabsize = 0; if(global_syntax_par_list == NULL) { p_create_syntax_list(); } if(record_key == NULL) { return; } for(sp_elem = global_syntax_par_list; sp_elem != NULL; sp_elem = (GapStbSyntaxElem *)sp_elem->next) { if(strcmp(record_key, sp_elem->record_key) == 0) { GapStbSyntaxParElem *par; for(par=sp_elem->par_list; par != NULL; par = (GapStbSyntaxParElem *)par->next) { par_tab->parname[par->par_idx] = par->parname; par_tab->tabsize++; } return; } } return; } /* end gap_stb_syntax_get_parname_tab */ /* ------------------------------------- * p_create_syntax_list * ------------------------------------- */ static void p_create_syntax_list(void) { p_add_keyword(GAP_STBKEY_STB_HEADER ,"version" ,NULL ); p_add_keyword(GAP_STBKEY_CLIP_HEADER ,"version" ,NULL ); p_add_keyword(GAP_STBKEY_LAYOUT_SIZE ,"cols" ,"rows" ,"thumbsize" ,NULL ); p_add_keyword(GAP_STBKEY_EDIT_SETTINGS ,"secition_name" ,"track" ,"page" ,NULL ); p_add_keyword(GAP_STBKEY_VID_MASTER_SIZE ,"width" ,"height" ,NULL ); p_add_keyword(GAP_STBKEY_VID_MASTER_FRAMERATE ,"frames_per_sec" ,NULL ); p_add_keyword(GAP_STBKEY_VID_MASTER_LAYERSTACK ,"track1" ,NULL ); p_add_keyword(GAP_STBKEY_VID_MASTER_FRAME_ASPECT ,"width" ,"height" ,NULL ); p_add_keyword(GAP_STBKEY_VID_PREFERRED_DECODER ,"decoder" ,NULL ); p_add_keyword(GAP_STBKEY_VID_MASTER_INSERT_AREA ,"format" ,NULL ); p_add_keyword(GAP_STBKEY_MAIN_SECTION ,NULL ); p_add_keyword(GAP_STBKEY_SUB_SECTION ,"section_name" ,NULL ); p_add_keyword(GAP_STBKEY_VID_PLAY_SECTION ,"track" ,"section_name" ,"from" ,"to" ,"mode" ,"nloops" ,"stepsize" ,"macro" ,"flip" ,"mask_name" ,"mask_anchor" ,"mask_stepsize" ,"mask_disable" ,"macsteps" ,NULL ); p_add_keyword(GAP_STBKEY_VID_PLAY_BLACKSECTION ,"track" ,"section_name" ,"from" ,"to" ,"mode" ,"nloops" ,"stepsize" ,"macro" ,"flip" ,"mask_name" ,"mask_anchor" ,"mask_stepsize" ,"mask_disable" ,"macsteps" ,NULL ); p_add_keyword(GAP_STBKEY_VID_PLAY_MOVIE ,"track" ,"file" ,"from" ,"to" ,"mode" ,"nloops" ,"seltrack" ,"exactseek" ,"deinterlace" ,"stepsize" ,"macro" ,"decoder" ,"flip" ,"mask_name" ,"mask_anchor" ,"mask_stepsize" ,"mask_disable" ,"macsteps" ,NULL ); p_add_keyword(GAP_STBKEY_VID_PLAY_FRAMES ,"track" ,"base" ,"ext" ,"from" ,"to" ,"mode" ,"nloops" ,"stepsize" ,"macro" ,"flip" ,"mask_name" ,"mask_anchor" ,"mask_stepsize" ,"mask_disable" ,"macsteps" ,NULL ); p_add_keyword(GAP_STBKEY_VID_PLAY_ANIMIMAGE ,"track" ,"file" ,"from" ,"to" ,"mode" ,"nloops" ,"stepsize" ,"macro" ,"flip" ,"mask_name" ,"mask_anchor" ,"mask_stepsize" ,"mask_disable" ,"macsteps" ,NULL ); p_add_keyword(GAP_STBKEY_VID_PLAY_IMAGE ,"track" ,"file" ,"nloops" ,"macro" ,"flip" ,"mask_name" ,"mask_anchor" ,"mask_stepsize" ,"mask_disable" ,"macsteps" ,NULL ); p_add_keyword(GAP_STBKEY_VID_PLAY_COLOR ,"track" ,"red" ,"green" ,"blue" ,"alpha" ,"nloops" ,"macro" ,"flip" ,"mask_name" ,"mask_anchor" ,"mask_stepsize" ,"mask_disable" ,"macsteps" ,NULL ); p_add_keyword(GAP_STBKEY_VID_SILENCE ,"track" ,"nloops" ,"wait_until_sec" ,NULL ); p_add_keyword(GAP_STBKEY_VID_OPACITY ,"track" ,"opacity_from" ,"opacity_to" ,"nframes" ,NULL ); p_add_keyword(GAP_STBKEY_VID_ZOOM_X ,"track" ,"zoom_x_from" ,"zoom_x_to" ,"nframes" ,NULL ); p_add_keyword(GAP_STBKEY_VID_ZOOM_Y ,"track" ,"zoom_y_from" ,"zoom_y_to" ,"nframes" ,NULL ); p_add_keyword(GAP_STBKEY_VID_MOVE_X ,"track" ,"move_x_from" ,"move_x_to" ,"nframes" ,NULL ); p_add_keyword(GAP_STBKEY_VID_MOVE_Y ,"track" ,"move_y_from" ,"move_y_to" ,"nframes" ,NULL ); p_add_keyword(GAP_STBKEY_VID_FIT_SIZE ,"track" ,"mode" ,"proportions" ,NULL ); p_add_keyword(GAP_STBKEY_VID_OVERLAP ,"track" ,"nframes" ,NULL ); p_add_keyword(GAP_STBKEY_MASK_MOVIE ,"mask_name" ,"file" ,"from" ,"to" ,"seltrack" ,"exactseek" ,"deinterlace" ,"decoder" ,"flip" ,NULL ); p_add_keyword(GAP_STBKEY_MASK_BLACKSECTION ,"mask_name" ,"from" ,"to" ,NULL ); p_add_keyword(GAP_STBKEY_MASK_FRAMES ,"mask_name" ,"base" ,"ext" ,"from" ,"to" ,"flip" ,NULL ); p_add_keyword(GAP_STBKEY_MASK_ANIMIMAGE ,"mask_name" ,"file" ,"from" ,"to" ,"flip" ,NULL ); p_add_keyword(GAP_STBKEY_MASK_IMAGE ,"mask_name" ,"file" ,"flip" ,NULL ); p_add_keyword(GAP_STBKEY_AUD_MASTER_VOLUME ,"volume" ,NULL ); p_add_keyword(GAP_STBKEY_AUD_MASTER_SAMPLERATE ,"samples_per_sec" ,NULL ); p_add_keyword(GAP_STBKEY_AUD_PLAY_SOUND ,"track" ,"file" ,"start_sec" ,"end_sec" ,"volume" ,"start_volume" ,"fade_in_time" ,"end_volume" ,"fade_out_time" ,"nloops" ,NULL ); p_add_keyword(GAP_STBKEY_AUD_PLAY_MOVIE ,"track" ,"file" ,"start_sec" ,"end_sec" ,"volume" ,"start_volume" ,"fade_in_time" ,"end_volume" ,"fade_out_time" ,"nloops" ,"seltrack" ,"decoder" ,"from" ,"to" ,"framerate" ,NULL ); p_add_keyword(GAP_STBKEY_AUD_SILENCE ,"track" ,"duration_sec" ,"wait_until_sec" ,NULL ); } /* end p_create_syntax_list */ gimp-gap-2.6.0+dfsg.orig/gap/gap_wr_color_huesat.c0000644000175000017500000006130111212030253021707 0ustar thibautthibaut/* gap_wr_color_hue_saturation.c * 2002.Jan.01 hof (Wolfgang Hofer) * * Wrapper Plugin for GIMP Hue Saturation tool * * Warning: This is just a QUICK HACK to enable * Animated Filterapply in conjunction with the * GIMP Hue Saturation Tool. * * It provides a primitive Dialog Interface where you * can call the Hue Saturation Tool * * Further it has an Interface to 'Run_with_last_values' * and an Iterator Procedure. * (This enables the 'Animated Filter Call' from * the GAP's Menu Filters->Filter all Layers) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* Revision history * (2004/01/15) v1.3.24a hof: adapted for gimp-1.3.x and gtk+2.2 API * (2002/10/27) v1.03 hof: - appear in menu (for filtermacro) * (2002/01/01) v1.02 hof: - created */ #include "config.h" #include #include #include #include #include #include #include "gap-intl.h" /* Defines */ #define PLUG_IN_NAME "plug-in-wr-huesat" #define PLUG_IN_IMAGE_TYPES "RGB*, GRAY*" #define PLUG_IN_AUTHOR "Wolfgang Hofer (hof@gimp.org)" #define PLUG_IN_COPYRIGHT "Wolfgang Hofer" #define PLUG_IN_DESCRIPTION "Wrapper call for GIMP Hue Saturation Color Tool" #define PLUG_IN_ITER_NAME "plug-in-wr-huesat-Iterator" #define PLUG_IN_DATA_ITER_FROM "plug-in-wr-huesat-ITER-FROM" #define PLUG_IN_DATA_ITER_TO "plug-in-wr-huesat-ITER-TO" #define PLUG_IN_HELP_ID "plug-in-wr-huesat" typedef struct { gint32 hue_range; gdouble hue_offset; gdouble lightness; gdouble saturation; } wr_huesat_val_t; typedef struct _WrDialog WrDialog; struct _WrDialog { gint run; gint show_progress; GtkWidget *shell; GtkWidget *radio_master; GtkWidget *radio_red; GtkWidget *radio_yellow; GtkWidget *radio_green; GtkWidget *radio_cyan; GtkWidget *radio_blue; GtkWidget *radio_magenta; wr_huesat_val_t *vals; }; WrDialog *do_dialog (wr_huesat_val_t *); static void query (void); static void run(const gchar *name , gint nparams , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals); /* Global Variables */ GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run /* run_proc */ }; gint gap_debug = 0; /* 0.. no debug, 1 .. print debug messages */ /* -------------- * procedures * -------------- */ /* * Delta Calculations for the iterator */ static void p_delta_gdouble (gdouble *val, gdouble val_from, gdouble val_to, gint32 total_steps, gdouble current_step) { gdouble delta; if(total_steps < 1) return; delta = ((gdouble)(val_to - val_from) / (gdouble)total_steps) * ((gdouble)total_steps - current_step); *val = val_from + delta; } static void p_delta_gint32 (gint32 *val, gint32 val_from, gint32 val_to, gint32 total_steps, gdouble current_step) { gdouble delta; if(total_steps < 1) return; delta = ((gdouble)(val_to - val_from) / (gdouble)total_steps) * ((gdouble)total_steps - current_step); *val = val_from + delta; } /* ============================================================================ * p_gimp_hue_saturation * * ============================================================================ */ gint32 p_gimp_hue_saturation (gint32 drawable_id, gint32 hue_range, gdouble hue_offset, gdouble lightness, gdouble saturation ) { static char *l_procname = "gimp_hue_saturation"; GimpParam *return_vals; int nreturn_vals; return_vals = gimp_run_procedure (l_procname, &nreturn_vals, GIMP_PDB_DRAWABLE, drawable_id, GIMP_PDB_INT32, hue_range, GIMP_PDB_FLOAT, hue_offset, GIMP_PDB_FLOAT, lightness, GIMP_PDB_FLOAT, saturation, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { gimp_destroy_params(return_vals, nreturn_vals); return (0); } gimp_destroy_params(return_vals, nreturn_vals); printf("Error: PDB call of %s failed status:%d\n", l_procname, (int)return_vals[0].data.d_status); return(-1); } /* end p_gimp_hue_saturation */ static void p_run_huesat_tool(gint32 drawable_id, wr_huesat_val_t *cuvals) { if(gap_debug) { printf("p_run_huesat_tool: drawable_id :%d\n", (int)drawable_id); printf("p_run_huesat_tool: hue_range:%d\n", (int)cuvals->hue_range); printf("p_run_huesat_tool: hue_offset:%f\n", (float)cuvals->hue_offset); printf("p_run_huesat_tool: lightness:%f\n", (float)cuvals->lightness); printf("p_run_huesat_tool: saturation:%f\n", (float)cuvals->saturation); } p_gimp_hue_saturation(drawable_id , cuvals->hue_range , cuvals->hue_offset , cuvals->lightness , cuvals->saturation ); } MAIN () static void query (void) { static GimpParamDef args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, { GIMP_PDB_IMAGE, "image", "Input image" }, { GIMP_PDB_DRAWABLE, "drawable", "Input drawable (must be a layer without layermask)"}, { GIMP_PDB_INT32, "hue_range", "Range of affected hues: ALL_HUES (0), RED_HUES(1), YELLOW_HUES(2), GREEN_HUES(3), CYAN_HUES(4), BLUE_HUES(5), MAGENTA_HUES(6)"}, { GIMP_PDB_FLOAT, "hue_offset", "Hue Offset uin degrees (-180 <= hue_offset <= 180"}, { GIMP_PDB_FLOAT, "lightness", "lightness Modification (-100 <= lightness <= 100"}, { GIMP_PDB_FLOAT, "saturation", "saturation Modification (-100 <= saturation <= 100"}, }; static int nargs = sizeof(args) / sizeof(args[0]); static GimpParamDef return_vals[] = { { GIMP_PDB_DRAWABLE, "the_drawable", "the handled drawable" } }; static int nreturn_vals = sizeof(return_vals) / sizeof(return_vals[0]); static GimpParamDef args_iter[] = { {GIMP_PDB_INT32, "run_mode", "non-interactive"}, {GIMP_PDB_INT32, "total_steps", "total number of steps (# of layers-1 to apply the related plug-in)"}, {GIMP_PDB_FLOAT, "current_step", "current (for linear iterations this is the layerstack position, otherwise some value inbetween)"}, {GIMP_PDB_INT32, "len_struct", "length of stored data structure with id is equal to the plug_in proc_name"}, }; static int nargs_iter = sizeof(args_iter) / sizeof(args_iter[0]); static GimpParamDef *return_iter = NULL; static int nreturn_iter = 0; gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); /* the actual installation of the bend plugin */ gimp_install_procedure (PLUG_IN_NAME, PLUG_IN_DESCRIPTION, "This Plugin is a wrapper to call the GIMP Hue Saturation Color Tool (gimp_hue_saturation)" " it has a simplified Dialog (without preview) where you can enter the parameters" " this wrapper is useful for animated filtercalls and provides " " a PDB interface that runs in GIMP_RUN_WITH_LAST_VALUES mode" " and also provides an Iterator Procedure for animated calls" , PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("Hue-Saturation..."), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, nargs, nreturn_vals, args, return_vals); /* the installation of the Iterator extension for the bend plugin */ gimp_install_procedure (PLUG_IN_ITER_NAME, "This extension calculates the modified values for one iterationstep for the call of plug_in_curve_bend", "", PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, NULL, /* do not appear in menus */ NULL, GIMP_PLUGIN, nargs_iter, nreturn_iter, args_iter, return_iter); { /* Menu names */ const char *menupath_image_video_layer_colors = N_("/Video/Layer/Colors/"); //gimp_plugin_menu_branch_register("", "Video"); //gimp_plugin_menu_branch_register("/Video", "Layer"); //gimp_plugin_menu_branch_register("/Video/Layer", "Colors"); gimp_plugin_menu_register (PLUG_IN_NAME, menupath_image_video_layer_colors); } } static void run(const gchar *name , gint nparams , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals) { wr_huesat_val_t l_cuvals; WrDialog *wcd = NULL; gint32 l_image_id = -1; gint32 l_drawable_id = -1; gint32 l_handled_drawable_id = -1; /* Get the runmode from the in-parameters */ GimpRunMode run_mode = param[0].data.d_int32; /* status variable, use it to check for errors in invocation usualy only during non-interactive calling */ GimpPDBStatusType status = GIMP_PDB_SUCCESS; /*always return at least the status to the caller. */ static GimpParam values[2]; INIT_I18N(); /* initialize the return of the status */ values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; values[1].type = GIMP_PDB_DRAWABLE; values[1].data.d_int32 = -1; *nreturn_vals = 2; *return_vals = values; /* the Iterator Stuff */ if (strcmp (name, PLUG_IN_ITER_NAME) == 0) { gint32 len_struct; gint32 total_steps; gdouble current_step; wr_huesat_val_t cval; /* current values while iterating */ wr_huesat_val_t cval_from, cval_to; /* start and end values */ /* Iterator procedure for animated calls is usually called from * "plug_in_gap_layers_run_animfilter" * (always run noninteractive) */ if ((run_mode == GIMP_RUN_NONINTERACTIVE) && (nparams == 4)) { total_steps = param[1].data.d_int32; current_step = param[2].data.d_float; len_struct = param[3].data.d_int32; if(len_struct == sizeof(cval)) { /* get _FROM and _TO data, * This data was stored by plug_in_gap_layers_run_animfilter */ gimp_get_data(PLUG_IN_DATA_ITER_FROM, &cval_from); gimp_get_data(PLUG_IN_DATA_ITER_TO, &cval_to); memcpy(&cval, &cval_from, sizeof(cval)); p_delta_gint32 (&cval.hue_range, cval_from.hue_range, cval_to.hue_range, total_steps, current_step); p_delta_gdouble(&cval.hue_offset, cval_from.hue_offset, cval_to.hue_offset, total_steps, current_step); p_delta_gdouble(&cval.lightness, cval_from.lightness, cval_to.lightness, total_steps, current_step); p_delta_gdouble(&cval.saturation, cval_from.saturation, cval_to.saturation, total_steps, current_step); gimp_set_data(PLUG_IN_NAME, &cval, sizeof(cval)); } else status = GIMP_PDB_CALLING_ERROR; } else status = GIMP_PDB_CALLING_ERROR; values[0].data.d_status = status; return; } /* get image and drawable */ l_image_id = param[1].data.d_int32; l_drawable_id = param[2].data.d_drawable; if(status == GIMP_PDB_SUCCESS) { /* how are we running today? */ switch (run_mode) { case GIMP_RUN_INTERACTIVE: /* Initial values */ l_cuvals.hue_range = 0; l_cuvals.hue_offset = 0; l_cuvals.lightness = 0; l_cuvals.saturation = 0; /* Get information from the dialog */ wcd = do_dialog(&l_cuvals); wcd->show_progress = TRUE; break; case GIMP_RUN_NONINTERACTIVE: /* check to see if invoked with the correct number of parameters */ if (nparams >= 7) { wcd = g_malloc (sizeof (WrDialog)); wcd->run = TRUE; wcd->show_progress = FALSE; l_cuvals.hue_range = param[3].data.d_int32; l_cuvals.hue_offset = param[4].data.d_float; l_cuvals.lightness = param[5].data.d_float; l_cuvals.saturation = param[6].data.d_float; } else { status = GIMP_PDB_CALLING_ERROR; } break; case GIMP_RUN_WITH_LAST_VALS: wcd = g_malloc (sizeof (WrDialog)); wcd->run = TRUE; wcd->show_progress = TRUE; /* Possibly retrieve data from a previous run */ gimp_get_data (PLUG_IN_NAME, &l_cuvals); break; default: break; } } if (wcd == NULL) { status = GIMP_PDB_EXECUTION_ERROR; } if (status == GIMP_PDB_SUCCESS) { /* Run the main function */ if(wcd->run) { gimp_image_undo_group_start (l_image_id); p_run_huesat_tool(l_drawable_id, &l_cuvals); l_handled_drawable_id = l_drawable_id; gimp_image_undo_group_end (l_image_id); /* Store variable states for next run */ if (run_mode == GIMP_RUN_INTERACTIVE) { gimp_set_data(PLUG_IN_NAME, &l_cuvals, sizeof(l_cuvals)); } } else { status = GIMP_PDB_EXECUTION_ERROR; /* dialog ended with cancel button */ } /* If run mode is interactive, flush displays, else (script) don't do it, as the screen updates would make the scripts slow */ if (run_mode != GIMP_RUN_NONINTERACTIVE) { gimp_displays_flush (); } } values[0].data.d_status = status; values[1].data.d_int32 = l_handled_drawable_id; /* return the id of handled layer */ } /* end run */ /* * DIALOG and callback stuff */ static void radio_callback(GtkWidget *wgt, gpointer user_data) { WrDialog *wcd; if(gap_debug) printf("radio_callback: START\n"); wcd = (WrDialog*)user_data; if(wcd != NULL) { if(wcd->vals != NULL) { if(wgt == wcd->radio_magenta) { wcd->vals->hue_range = 6; } if(wgt == wcd->radio_blue) { wcd->vals->hue_range = 5; } if(wgt == wcd->radio_cyan) { wcd->vals->hue_range = 4; } if(wgt == wcd->radio_green) { wcd->vals->hue_range = 3; } if(wgt == wcd->radio_yellow) { wcd->vals->hue_range = 2; } if(wgt == wcd->radio_red) { wcd->vals->hue_range = 1; } if(wgt == wcd->radio_master) { wcd->vals->hue_range = 0; } if(gap_debug) printf("radio_callback: value: %d\n", (int)wcd->vals->hue_range); } } } /* --------------------------------- * wr_huesat_response * --------------------------------- */ static void wr_huesat_response (GtkWidget *widget, gint response_id, WrDialog *wcd) { GtkWidget *dialog; switch (response_id) { case GTK_RESPONSE_OK: if(wcd) { if (GTK_WIDGET_VISIBLE (wcd->shell)) gtk_widget_hide (wcd->shell); wcd->run = TRUE; } default: dialog = NULL; if(wcd) { dialog = wcd->shell; if(dialog) { wcd->shell = NULL; gtk_widget_destroy (dialog); } } gtk_main_quit (); break; } } /* end wr_huesat_response */ WrDialog * do_dialog (wr_huesat_val_t *cuvals) { WrDialog *wcd; GtkWidget *vbox; GtkWidget *dialog1; GtkWidget *dialog_vbox1; GtkWidget *frame1; GtkWidget *hbox1; GtkWidget *vbox1; GtkWidget *label1; GSList *vbox1_group = NULL; GtkWidget *radiobutton1; GtkWidget *radiobutton2; GtkWidget *radiobutton3; GtkWidget *radiobutton4; GtkWidget *radiobutton5; GtkWidget *radiobutton6; GtkWidget *radiobutton7; GtkWidget *table1; GtkWidget *label2; GtkWidget *label3; GtkWidget *label4; GtkObject *spinbutton_sat_adj; GtkWidget *spinbutton_sat; GtkObject *spinbutton_light_adj; GtkWidget *spinbutton_light; GtkObject *spinbutton_hue_adj; GtkWidget *spinbutton_hue; GtkWidget *dialog_action_area1; /* Init UI */ gimp_ui_init ("wr_curves", FALSE); /* The dialog1 */ wcd = g_malloc (sizeof (WrDialog)); wcd->run = FALSE; wcd->vals = cuvals; /* The dialog1 and main vbox */ dialog1 = gimp_dialog_new (_("Hue-Saturation"), "hue_saturation_wrapper", NULL, 0, gimp_standard_help_func, PLUG_IN_HELP_ID, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); wcd->shell = dialog1; /* * g_object_set_data (G_OBJECT (dialog1), "dialog1", dialog1); * gtk_window_set_title (GTK_WINDOW (dialog1), _("dialog1")); */ g_signal_connect (G_OBJECT (dialog1), "response", G_CALLBACK (wr_huesat_response), wcd); /* the vbox */ vbox = gtk_vbox_new (FALSE, 2); gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog1)->vbox), vbox, TRUE, TRUE, 0); gtk_widget_show (vbox); dialog_vbox1 = GTK_DIALOG (dialog1)->vbox; g_object_set_data (G_OBJECT (dialog1), "dialog_vbox1", dialog_vbox1); gtk_widget_show (dialog_vbox1); /* the frame */ frame1 = gimp_frame_new (_("Hue / Lightness / Saturation Adjustments ")); gtk_widget_show (frame1); gtk_box_pack_start (GTK_BOX (dialog_vbox1), frame1, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (frame1), 2); hbox1 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox1); gtk_container_add (GTK_CONTAINER (frame1), hbox1); gtk_container_set_border_width (GTK_CONTAINER (hbox1), 4); vbox1 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox1); gtk_box_pack_start (GTK_BOX (hbox1), vbox1, TRUE, TRUE, 0); /* Hue Mode the label */ label1 = gtk_label_new (_("Hue Mode:")); gtk_widget_show (label1); gtk_box_pack_start (GTK_BOX (vbox1), label1, FALSE, FALSE, 0); gtk_misc_set_alignment (GTK_MISC (label1), 0, 0.5); /* Hue Mode the radio buttons */ radiobutton1 = gtk_radio_button_new_with_label (vbox1_group, _("Master")); vbox1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton1)); gtk_widget_show (radiobutton1); gtk_box_pack_start (GTK_BOX (vbox1), radiobutton1, FALSE, FALSE, 0); radiobutton2 = gtk_radio_button_new_with_label (vbox1_group, _("Red")); vbox1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton2)); gtk_widget_show (radiobutton2); gtk_box_pack_start (GTK_BOX (vbox1), radiobutton2, FALSE, FALSE, 0); radiobutton3 = gtk_radio_button_new_with_label (vbox1_group, _("Yellow")); vbox1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton3)); gtk_widget_show (radiobutton3); gtk_box_pack_start (GTK_BOX (vbox1), radiobutton3, FALSE, FALSE, 0); radiobutton4 = gtk_radio_button_new_with_label (vbox1_group, _("Green")); vbox1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton4)); gtk_widget_show (radiobutton4); gtk_box_pack_start (GTK_BOX (vbox1), radiobutton4, FALSE, FALSE, 0); radiobutton5 = gtk_radio_button_new_with_label (vbox1_group, _("Cyan")); vbox1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton5)); gtk_widget_show (radiobutton5); gtk_box_pack_start (GTK_BOX (vbox1), radiobutton5, FALSE, FALSE, 0); radiobutton6 = gtk_radio_button_new_with_label (vbox1_group, _("Blue")); vbox1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton6)); gtk_widget_show (radiobutton6); gtk_box_pack_start (GTK_BOX (vbox1), radiobutton6, FALSE, FALSE, 0); radiobutton7 = gtk_radio_button_new_with_label (vbox1_group, _("Magenta")); vbox1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton7)); gtk_widget_show (radiobutton7); gtk_box_pack_start (GTK_BOX (vbox1), radiobutton7, FALSE, FALSE, 0); /* table1 for spinbuttons */ table1 = gtk_table_new (4, 2, FALSE); gtk_widget_show (table1); gtk_box_pack_start (GTK_BOX (hbox1), table1, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (table1), 4); label2 = gtk_label_new (_("Hue:")); gtk_widget_show (label2); gtk_table_attach (GTK_TABLE (table1), label2, 0, 1, 1, 2, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment (GTK_MISC (label2), 0, 0.5); label3 = gtk_label_new (_("Lightness:")); gtk_widget_show (label3); gtk_table_attach (GTK_TABLE (table1), label3, 0, 1, 2, 3, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment (GTK_MISC (label3), 0, 0.5); label4 = gtk_label_new (_("Saturation:")); gtk_widget_show (label4); gtk_table_attach (GTK_TABLE (table1), label4, 0, 1, 3, 4, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment (GTK_MISC (label4), 0, 0.5); spinbutton_sat_adj = gtk_adjustment_new (0, -100, 100, 1, 10, 0); spinbutton_sat = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_sat_adj), 1, 0); gtk_widget_show (spinbutton_sat); gtk_table_attach (GTK_TABLE (table1), spinbutton_sat, 1, 2, 3, 4, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); spinbutton_light_adj = gtk_adjustment_new (0, -100, 100, 1, 10, 0); spinbutton_light = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_light_adj), 1, 0); gtk_widget_show (spinbutton_light); gtk_table_attach (GTK_TABLE (table1), spinbutton_light, 1, 2, 2, 3, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); spinbutton_hue_adj = gtk_adjustment_new (0, -180, 180, 1, 10, 0); spinbutton_hue = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_hue_adj), 1, 0); gtk_widget_show (spinbutton_hue); gtk_table_attach (GTK_TABLE (table1), spinbutton_hue, 1, 2, 1, 2, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); dialog_action_area1 = GTK_DIALOG (dialog1)->action_area; gtk_widget_show (dialog_action_area1); gtk_container_set_border_width (GTK_CONTAINER (dialog_action_area1), 10); wcd->radio_master = radiobutton1; wcd->radio_red = radiobutton2; wcd->radio_yellow = radiobutton3; wcd->radio_green = radiobutton4; wcd->radio_cyan = radiobutton5; wcd->radio_blue = radiobutton6; wcd->radio_magenta = radiobutton7; /* signals */ g_signal_connect (G_OBJECT (wcd->radio_master), "clicked", G_CALLBACK (radio_callback), wcd); g_signal_connect (G_OBJECT (wcd->radio_red), "clicked", G_CALLBACK (radio_callback), wcd); g_signal_connect (G_OBJECT (wcd->radio_yellow), "clicked", G_CALLBACK (radio_callback), wcd); g_signal_connect (G_OBJECT (wcd->radio_green), "clicked", G_CALLBACK (radio_callback), wcd); g_signal_connect (G_OBJECT (wcd->radio_cyan), "clicked", G_CALLBACK (radio_callback), wcd); g_signal_connect (G_OBJECT (wcd->radio_blue), "clicked", G_CALLBACK (radio_callback), wcd); g_signal_connect (G_OBJECT (wcd->radio_magenta), "clicked", G_CALLBACK (radio_callback), wcd); g_signal_connect (G_OBJECT (spinbutton_hue_adj), "value_changed", G_CALLBACK (gimp_double_adjustment_update), &cuvals->hue_offset); g_signal_connect (G_OBJECT (spinbutton_light_adj), "value_changed", G_CALLBACK (gimp_double_adjustment_update), &cuvals->lightness); g_signal_connect (G_OBJECT (spinbutton_sat_adj), "value_changed", G_CALLBACK (gimp_double_adjustment_update), &cuvals->saturation); gtk_widget_show (dialog1); gtk_main (); gdk_flush (); return wcd; } gimp-gap-2.6.0+dfsg.orig/gap/gap_story_undo.h0000644000175000017500000000444111212030253020724 0ustar thibautthibaut/* gap_story_undo.h * * This module handles GAP storyboard undo and redo features. */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.25a; 2007/10/18 hof: created */ #ifndef _GAP_STORY_UNDO_H #define _GAP_STORY_UNDO_H #include "libgimp/gimp.h" #include "gap_lib.h" #include #include #include #include "gap_story_main.h" #include "gap_story_file.h" #include "gap_story_undo_types.h" void gap_stb_undo_debug_print_stack(GapStbTabWidgets *tabw); const char * gap_stb_undo_feature_to_string(GapStoryFeatureEnum feature_id); GapStoryBoard * gap_stb_undo_pop(GapStbTabWidgets *tabw); GapStoryBoard * gap_stb_undo_redo(GapStbTabWidgets *tabw); void gap_stb_undo_destroy_undo_stack(GapStbTabWidgets *tabw); void gap_stb_undo_push_clip(GapStbTabWidgets *tabw , GapStoryFeatureEnum feature_id , gint32 story_id ); void gap_stb_undo_push(GapStbTabWidgets *tabw, GapStoryFeatureEnum feature_id); void gap_stb_undo_group_begin(GapStbTabWidgets *tabw); void gap_stb_undo_group_end(GapStbTabWidgets *tabw); const char * gap_stb_undo_get_undo_feature(GapStbTabWidgets *tabw); const char * gap_stb_undo_get_redo_feature(GapStbTabWidgets *tabw); void gap_stb_undo_stack_set_unsaved_changes(GapStbTabWidgets *tabw); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_story_dialog.h0000644000175000017500000000560111212030253021215 0ustar thibautthibaut/* gap_story_dialog.h * * This module handles GAP storyboard dialog editor */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.27a; 2004/03/15 hof: gap_story_get_velem * version 1.3.25a; 2004/01/23 hof: created */ #ifndef _GAP_STORY_DIALOG_H #define _GAP_STORY_DIALOG_H #include "libgimp/gimp.h" #include "gap_story_main.h" #include "gap_story_properties.h" void gap_storyboard_dialog(GapStbMainGlobalParams *gpp); void gap_story_dlg_attw_render_all(GapStbAttrWidget *attw); void gap_story_dlg_pw_render_all(GapStbPropWidget *pw, gboolean recreate); void gap_story_pw_single_clip_playback(GapStbPropWidget *pw); void gap_story_pw_composite_playback(GapStbPropWidget *pw); void gap_story_attw_range_playback(GapStbAttrWidget *attw, gint32 begin_frame , gint32 end_frame); void gap_story_dlg_pw_update_mask_references(GapStbTabWidgets *tabw); void gap_story_dlg_spw_section_refresh(GapStbSecpropWidget *spw, GapStorySection *section); void gap_story_dlg_recreate_tab_widgets(GapStbTabWidgets *tabw ,GapStbMainGlobalParams *sgpp ); void gap_story_dlg_render_default_icon(GapStoryElem *stb_elem, GapPView *pv_ptr); void gap_story_dlg_tabw_update_frame_label (GapStbTabWidgets *tabw , GapStbMainGlobalParams *sgpp ); void gap_story_dlg_tabw_undo_redo_sensitivity(GapStbTabWidgets *tabw); guchar * gap_story_dlg_fetch_videoframe(GapStbMainGlobalParams *sgpp , const char *gva_videofile , gint32 framenumber , gint32 seltrack , const char *preferred_decoder , gdouble delace , gint32 *th_bpp , gint32 *th_width , gint32 *th_height , gboolean do_scale ); GapStoryBoard * gap_story_dlg_tabw_get_stb_ptr (GapStbTabWidgets *tabw); void gap_story_dlg_update_edit_settings(GapStoryBoard *stb , GapStbTabWidgets *tabw ); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_onion_dialog.h0000644000175000017500000000240711212030253021160 0ustar thibautthibaut/* gap_onion_dialog.h * 2003.05.22 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains GAP Onionskin GUI Procedures */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.14a; 2003.05.22 hof: created */ #ifndef _GAP_ONION_DIALOG_H #define _GAP_ONION_DIALOG_H #include "gap_onion_main.h" void gap_onion_dlg_init_default_values(GapOnionMainGlobalParams *gpp); gint gap_onion_dlg_onion_cfg_dialog(GapOnionMainGlobalParams *gpp); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_morph_dialog.c0000644000175000017500000035733311212030253021171 0ustar thibautthibaut/* gap_morph_dialog.c * * This module handles GAP morph dialog */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* revision history: * version 2.1.0a; 2004/04/18 hof: created */ /* define GAP_MORPH_DEBUG_FEATURES shows both experimental features * and testfeatures for developers only. */ #undef GAP_MORPH_DEBUG_FEATURES #include "config.h" #include #include #include #include #include #include #include #include #include #include "gap_morph_main.h" #include "gap_morph_dialog.h" #include "gap_morph_exec.h" #include "gap_pdb_calls.h" #include "gap_pview_da.h" #include "gap_stock.h" #include "gap_lib.h" #include "gap_image.h" #include "gap_vin.h" #include "gap_timeconv.h" #include "gap_thumbnail.h" #include "gap_arr_dialog.h" #include "gap-intl.h" extern int gap_debug; /* 1 == print debug infos , 0 dont print debug infos */ #define GAP_MORPH_RESPONSE_RESET 1 #define GAP_MORPH_CHECK_SIZE 8 #define GAP_MORPH_PV_WIDTH 480 #define GAP_MORPH_PV_HEIGHT 320 #define GAP_MORPH_ZOOMSTEP 1.5 #define RADIUS 3 #define RADIUS_SHOW 4 #define GAP_MORPH_MAXGINT32 2147483647 /* for picking: define what is "NEAR" enough in square pixels */ #define GAP_MORPH_PICK_SQR_NEAR_THRESHOLD 25 #define GAP_MORPH_DLG_UPD_REQUEST_NONE 0 #define GAP_MORPH_DLG_UPD_REQUEST_REDRAW 1 #define GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH 2 #define GAP_MORPH_KOORD_WPX 1 #define GAP_MORPH_KOORD_WPY 2 /* event masks for the preview widgets */ #define GAP_MORPH_PVIEW_MASK GDK_EXPOSURE_MASK | \ GDK_BUTTON_PRESS_MASK |\ GDK_BUTTON_RELEASE_MASK |\ GDK_BUTTON_MOTION_MASK /* op_mode Radio Buttons */ #define GAP_MORPH_OP_MODE_SET 0 #define GAP_MORPH_OP_MODE_MOVE 1 #define GAP_MORPH_OP_MODE_DELETE 2 #define GAP_MORPH_OP_MODE_ZOOM 3 #define GAP_MORPH_OP_MODE_SHOW 4 #define GAP_MORPH_SWAP(ty, x, y) { ty tmp; tmp = x; x = y; y = tmp; } static void p_morph_response(GtkWidget *w, gint response_id, GapMorphGUIParams *mgup); static void p_upd_widget_values(GapMorphGUIParams *mgup); static void p_upd_warp_info_label(GapMorphGUIParams *mgup); static gboolean p_pixel_check_opaque(GimpPixelFetcher *pft , gint bpp , gdouble needx , gdouble needy ); static void p_find_outmost_opaque_pixel(GimpPixelFetcher *pft ,gint bpp ,gdouble alpha_rad ,gint32 width ,gint32 height ,gdouble *px ,gdouble *py ); static void p_generate_outline_shape_workpoints(GapMorphGUIParams *mgup); static void p_add_4corner_workpoints(GapMorphGUIParams *mgup); static void p_zoom_in(GapMorphSubWin *swp, gdouble l_x, gdouble l_y); //XXX unfinished static void p_zoom_out(GapMorphSubWin *swp); //XXX unfinished static void p_fit_zoom_into_pview_size(GapMorphSubWin *swp); static void on_swap_button_pressed_callback(GtkWidget *wgt, GapMorphGUIParams *mgup); static void on_fit_zoom_pressed_callback(GtkWidget *wgt, GapMorphSubWin *swp); static void p_hvscale_adj_set_limits(GapMorphSubWin *swp); static void on_timer_update_job(GapMorphGUIParams *mgup); static void p_set_upd_timer_request(GapMorphGUIParams *mgup, gint32 src_request, gint32 dst_request); static void on_koord_spinbutton_changed (GtkObject *obj, gint32 koord_id); static void on_curr_point_spinbutton_changed(GtkObject *obj, GapMorphGUIParams *mgup); GapMorphWorkPoint * gap_morph_dlg_new_workpont(gdouble srcx, gdouble srcy, gdouble dstx, gdouble dsty); static void p_delete_current_point(GapMorphSubWin *swp); static void p_set_nearest_current_workpoint(GapMorphSubWin *swp , gdouble in_x , gdouble in_y ); static void p_set_current_workpoint_no_refresh(GapMorphSubWin *swp, GapMorphWorkPoint *wp); static void p_set_current_workpoint(GapMorphSubWin *swp, GapMorphWorkPoint *wp); static GapMorphWorkPoint * p_add_new_point(GapMorphSubWin *swp, gdouble in_x, gdouble in_y); static void p_add_new_point_refresh(GapMorphSubWin *swp, gdouble in_x, gdouble in_y); static void p_refresh_total_points_label(GapMorphGUIParams *mgup); static GapMorphWorkPoint * p_find_nearest_point(GapMorphSubWin *swp , gdouble in_x , gdouble in_y , gdouble *ret_sqr_dist ); static gboolean p_pick_nearest_point(GapMorphSubWin *swp, gdouble l_x, gdouble l_y); static void p_show_warp_pick_point(GapMorphGUIParams *mgup ,gdouble l_x ,gdouble l_y ); static void p_draw_workpoints (GapMorphSubWin *swp); static void p_prevw_draw (GapMorphSubWin *swp); static void p_render_zoomed_pview(GapMorphSubWin *swp); static gint on_pview_events (GtkWidget *widget , GdkEvent *event , GapMorphSubWin *swp ); static void p_scale_wp_list(GapMorphGUIParams *mgup); static void p_imglayer_menu_callback(GtkWidget *widget, GapMorphSubWin *swp); static gint p_imglayer_constrain(gint32 image_id, gint32 drawable_id, gpointer data); static void p_refresh_layer_menu(GapMorphSubWin *swp, GapMorphGUIParams *mgup); static void on_pointcolor_button_changed(GimpColorButton *widget, GimpRGB *pcolor); static void on_wp_filesel_destroy (GtkObject *object ,GapMorphGUIParams *mgup); static void on_wp_filesel_button_OK_clicked (GtkButton *button ,GapMorphGUIParams *mgup); static void on_wp_filesel_button_cancel_clicked (GtkButton *button , GapMorphGUIParams *mgup); static void p_create_wp_filesel (GapMorphGUIParams *mgup ,GdkEventButton *bevent ,gboolean save_mode); static void on_wp_save_button_clicked (GtkButton *button ,GdkEventButton *bevent ,GapMorphGUIParams *mgup); static void on_wp_load_button_clicked (GtkButton *button ,GdkEventButton *bevent ,GapMorphGUIParams *mgup); static void on_wp_shape_button_clicked (GtkButton *button ,GdkEventButton *bevent ,GapMorphGUIParams *mgup); static void on_hvscale_changed_callback(GtkObject *obj, GapMorphSubWin *swp); static void on_show_lines_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup); static void on_use_quality_wp_selection_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup); static void on_use_gravity_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup); static void on_have_workpointsets_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup); static void on_create_tween_layers_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup); static void on_radio_op_mode_callback(GtkWidget *widget, gint32 op_mode); static void on_radio_render_mode_callback(GtkWidget *widget, gint32 op_mode); static void p_radio_create_op_mode(GtkWidget *table, int row, int col, GapMorphGUIParams *mgup); static void p_radio_create_render_mode(GtkWidget *table, int row, int col, GapMorphGUIParams *mgup); static GtkWidget * p_create_subwin(GapMorphSubWin *swp , const char *title , GapMorphGUIParams *mgup , GtkWidget *master_hbox ); static void gap_morph_create_dialog(GapMorphGUIParams *mgup); /* ----------------------------- * p_morph_response * ----------------------------- */ static void p_morph_response(GtkWidget *w, gint response_id, GapMorphGUIParams *mgup) { GtkWidget *dialog; switch (response_id) { case GAP_MORPH_RESPONSE_RESET: gap_morph_exec_free_workpoint_list(&mgup->mgpp->master_wp_list); p_add_4corner_workpoints(mgup); p_set_upd_timer_request(mgup ,GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH ,GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH ); p_refresh_total_points_label(mgup); mgup->mgpp->tween_steps = 1; mgup->num_shapepoints = 16; mgup->mgpp->affect_radius = 100; mgup->mgpp->gravity_intensity = 2.0; mgup->mgpp->use_quality_wp_selection = FALSE; mgup->mgpp->use_gravity = FALSE; mgup->mgpp->create_tween_layers = TRUE; mgup->mgpp->have_workpointsets = FALSE; p_upd_widget_values(mgup); break; case GTK_RESPONSE_OK: if(mgup) { if (GTK_WIDGET_VISIBLE (mgup->shell)) { gtk_widget_hide (mgup->shell); } mgup->run_flag = TRUE; } default: dialog = NULL; if(mgup) { dialog = mgup->shell; if(dialog) { mgup->shell = NULL; gtk_widget_destroy (dialog); } } gtk_main_quit (); break; } } /* end p_morph_response */ /* -------------------------------- * p_upd_widget_values * -------------------------------- */ static void p_upd_widget_values(GapMorphGUIParams *mgup) { if(mgup) { gtk_adjustment_set_value( GTK_ADJUSTMENT(mgup->tween_steps_spinbutton_adj) ,mgup->mgpp->tween_steps); gtk_adjustment_set_value( GTK_ADJUSTMENT(mgup->num_shapepoints_adj) ,mgup->num_shapepoints); gtk_adjustment_set_value( GTK_ADJUSTMENT(mgup->affect_radius_spinbutton_adj) ,mgup->mgpp->affect_radius); gtk_adjustment_set_value( GTK_ADJUSTMENT(mgup->gravity_intensity_spinbutton_adj) ,mgup->mgpp->gravity_intensity); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgup->use_quality_wp_selection_checkbutton) , mgup->mgpp->use_quality_wp_selection); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgup->use_gravity_checkbutton) , mgup->mgpp->use_gravity); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgup->create_tween_layers_checkbutton) , mgup->mgpp->create_tween_layers); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgup->have_workpointsets_checkbutton) , mgup->mgpp->have_workpointsets); } } /* end p_upd_widget_values */ /* ----------------------------- * p_upd_warp_info_label * ----------------------------- * Debug info: show weight and distance of current point */ static void p_upd_warp_info_label(GapMorphGUIParams *mgup) { GapMorphWorkPoint *wp; if(mgup) { wp = mgup->dst_win.curr_wp; if((mgup->warp_info_label) && (wp)) { gchar msg[100]; g_snprintf(&msg[0], sizeof(msg) , "si:%d rl:%d d:%.1f w:%.4f" , (int)wp->sek_idx , (int)wp->xy_relation , (float)sqrt(wp->sqr_dist) , (float)wp->warp_weight ); gtk_label_set_text(GTK_LABEL(mgup->warp_info_label), msg); } } } /* end p_upd_warp_info_label */ /* ----------------------------- * p_pixel_check_opaque * ----------------------------- * check average opacity in an area * of 2x2 pixels * return TRUE if average alpha is 50% or more opaque */ static gboolean p_pixel_check_opaque(GimpPixelFetcher *pft, gint bpp, gdouble needx, gdouble needy) { guchar pixel[4][4]; gdouble alpha_val; gint xi, yi; gint alpha_idx; if (needx >= 0.0) xi = (int) needx; else xi = -((int) -needx + 1); if (needy >= 0.0) yi = (int) needy; else yi = -((int) -needy + 1); gimp_pixel_fetcher_get_pixel (pft, xi, yi, pixel[0]); gimp_pixel_fetcher_get_pixel (pft, xi + 1, yi, pixel[1]); gimp_pixel_fetcher_get_pixel (pft, xi, yi + 1, pixel[2]); gimp_pixel_fetcher_get_pixel (pft, xi + 1, yi + 1, pixel[3]); alpha_idx = bpp -1; /* average aplha channel normalized to range 0.0 upto 1.0 */ alpha_val = ( (gdouble)pixel[0][alpha_idx] / 255.0 + (gdouble)pixel[1][alpha_idx] / 255.0 + (gdouble)pixel[2][alpha_idx] / 255.0 + (gdouble)pixel[3][alpha_idx] / 255.0 ) / 4.0; if (alpha_val > 0.5) /* fix THRESHOLD half or more opaque */ { return (TRUE); } return (FALSE); } /* end p_pixel_check_opaque */ /* ----------------------------- * p_find_outmost_opaque_pixel * ----------------------------- * returns koords in paramters px, py */ static void p_find_outmost_opaque_pixel(GimpPixelFetcher *pft ,gint bpp ,gdouble alpha_rad ,gint32 width ,gint32 height ,gdouble *px ,gdouble *py ) { gdouble center_x; gdouble center_y; gdouble cos_alpha; gdouble sin_alpha; gdouble l_x, l_y, l_r; gdouble half_width; gdouble half_height; l_x = 0; l_y = 0; cos_alpha = cos(alpha_rad); sin_alpha = sin(alpha_rad); /* printf("sin: %.5f cos:%.5f\n", sin_alpha, cos_alpha); */ half_width = (gdouble)(width /2.0); half_height = (gdouble)(height /2.0); center_x = half_width; center_y = half_height; l_r = MAX(half_width, half_height); l_r *= l_r; /* start at the out-most point * (may be out of the layer in most cases) * and search towards the center along * the line with angle alpha */ while(l_r > 0) { l_y = l_r * sin_alpha; l_x = l_r * cos_alpha; if((l_x <= half_width) && (l_y <= half_height)) { if (((center_x + l_x) >= 0) && ((center_y + l_y) >= 0)) { /* now we are inside the layer area */ if (p_pixel_check_opaque(pft ,bpp ,center_x + l_x ,center_y + l_y )) { break; } } } l_r--; } *px = center_x + l_x; *py = center_y + l_y; } /* end p_find_outmost_opaque_pixel */ /* ----------------------------------- * p_generate_outline_shape_workpoints * ----------------------------------- */ static void p_generate_outline_shape_workpoints(GapMorphGUIParams *mgup) { GapMorphWorkPoint *wp; GimpPixelFetcher *src_pixfet; GimpPixelFetcher *dst_pixfet; GimpDrawable *dst_drawable; GimpDrawable *src_drawable; gdouble alpha_rad; gdouble step_rad; gint ii; src_drawable = gimp_drawable_get (mgup->mgpp->osrc_layer_id); dst_drawable = gimp_drawable_get (mgup->mgpp->fdst_layer_id); src_pixfet = gimp_pixel_fetcher_new (src_drawable, FALSE /*shadow*/); dst_pixfet = gimp_pixel_fetcher_new (dst_drawable, FALSE /*shadow*/); step_rad = (2.0 * G_PI) / MAX(1, mgup->num_shapepoints); alpha_rad = 0.0; /* loop from 0 to 360 degree */ for(ii=0; ii < mgup->num_shapepoints; ii++) { gdouble sx, sy, dx, dy; p_find_outmost_opaque_pixel(src_pixfet ,src_drawable->bpp ,alpha_rad ,src_drawable->width ,src_drawable->height ,&sx ,&sy ); p_find_outmost_opaque_pixel(dst_pixfet ,dst_drawable->bpp ,alpha_rad ,dst_drawable->width ,dst_drawable->height ,&dx ,&dy ); /* create a new workpoint with sx,sy, dx, dy coords */ wp = gap_morph_dlg_new_workpont(sx ,sy ,dx ,dy); wp->next = mgup->mgpp->master_wp_list; mgup->mgpp->master_wp_list = wp; alpha_rad += step_rad; } gimp_pixel_fetcher_destroy (src_pixfet); gimp_pixel_fetcher_destroy (dst_pixfet); gimp_drawable_detach(src_drawable); gimp_drawable_detach(dst_drawable); } /* end p_generate_outline_shape_workpoints */ /* ----------------------------- * p_add_4corner_workpoints * ----------------------------- */ static void p_add_4corner_workpoints(GapMorphGUIParams *mgup) { GapMorphWorkPoint *wp; gint32 dst_drawable_id; gint32 src_drawable_id; gdouble sx[4]; gdouble sy[4]; gdouble dx[4]; gdouble dy[4]; gint ii; src_drawable_id = mgup->mgpp->osrc_layer_id; dst_drawable_id = mgup->mgpp->fdst_layer_id; sx[0] = gimp_drawable_width(src_drawable_id) -1; sy[0] = gimp_drawable_height(src_drawable_id) -1; dx[0] = gimp_drawable_width(dst_drawable_id) -1; dy[0] = gimp_drawable_height(dst_drawable_id) -1; sx[1] = gimp_drawable_width(src_drawable_id) -1; sy[1] = 0; dx[1] = gimp_drawable_width(dst_drawable_id) -1; dy[1] = 0; sx[2] = 0; sy[2] = gimp_drawable_height(src_drawable_id) -1; dx[2] = 0; dy[2] = gimp_drawable_height(dst_drawable_id) -1; sx[3] = 0; sy[3] = 0; dx[3] = 0; dy[3] = 0; for(ii=0; ii<4; ii++) { wp = gap_morph_dlg_new_workpont(sx[ii] ,sy[ii] ,dx[ii] ,dy[ii]); wp->next = mgup->mgpp->master_wp_list; mgup->mgpp->master_wp_list = wp; } } /* end p_add_4corner_workpoints */ /* ----------------------------- * p_zoom_in * ----------------------------- * zoom into preview where x/y is the new center */ static void p_zoom_in(GapMorphSubWin *swp, gdouble l_x, gdouble l_y) { GapMorphGUIParams *mgup; gdouble width; gdouble height; mgup = (GapMorphGUIParams *)swp->mgup; swp->zoom = (swp->zoom / GAP_MORPH_ZOOMSTEP); if(swp->zoom == 0) { swp->zoom = 1.0; } width = swp->zoom * swp->pv_ptr->pv_width; height = swp->zoom * swp->pv_ptr->pv_height; swp->offs_x = l_x - (width / 2.0); swp->offs_y = l_y - (height / 2.0); p_set_upd_timer_request(mgup ,GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH ,GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH ); } /* end p_zoom_in */ /* ----------------------------- * p_zoom_out * ----------------------------- * zoom into preview where x/y is the new center */ static void p_zoom_out(GapMorphSubWin *swp) { GapMorphGUIParams *mgup; swp->zoom = (swp->zoom * GAP_MORPH_ZOOMSTEP); if(swp->zoom > swp->max_zoom) { swp->zoom = swp->max_zoom; } mgup = (GapMorphGUIParams *)swp->mgup; swp->offs_x /= GAP_MORPH_ZOOMSTEP; swp->offs_y /= GAP_MORPH_ZOOMSTEP; p_set_upd_timer_request(mgup ,GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH ,GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH ); } /* end p_zoom_out */ /* ---------------------------------- * p_fit_zoom_into_pview_size * ---------------------------------- */ static void p_fit_zoom_into_pview_size(GapMorphSubWin *swp) { swp->zoom = 1.0; if(swp->layer_id_ptr) { if(*swp->layer_id_ptr >= 0) { gdouble width; gdouble height; gdouble pv_width; gdouble pv_height; gdouble pv_pixelsize; gint32 src_request; gint32 dst_request; width = (gdouble) gimp_drawable_width(*swp->layer_id_ptr); height = (gdouble) gimp_drawable_height(*swp->layer_id_ptr); pv_pixelsize = MAX(GAP_MORPH_PV_WIDTH, GAP_MORPH_PV_HEIGHT); /* * Resize the greater one of dwidth and dheight to PREVIEW_SIZE */ if ( width > height ) { /* landscape */ pv_height = height * pv_pixelsize / width; pv_width = pv_pixelsize; swp->zoom = width / (gdouble)pv_width; } else { /* portrait */ pv_width = width * pv_pixelsize / height; pv_height = pv_pixelsize; swp->zoom = height / (gdouble)pv_height; } swp->max_zoom = swp->zoom; if(gap_debug) { printf("p_fit_zoom_into_pview_size: width: %d height:%d ## ZOOM:%f\n" , (int)width , (int)height , (float)swp->zoom) ; } if((pv_width != swp->pv_ptr->pv_width) || (pv_height != swp->pv_ptr->pv_height)) { gap_pview_set_size(swp->pv_ptr , pv_width , pv_height , MAX(GAP_MORPH_CHECK_SIZE, (pv_pixelsize / 16)) ); } if(swp->src_flag) { src_request = GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH; dst_request = GAP_MORPH_DLG_UPD_REQUEST_NONE; } else { src_request = GAP_MORPH_DLG_UPD_REQUEST_NONE; dst_request = GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH; } p_set_upd_timer_request(swp->mgup, src_request, dst_request); } } } /* end p_fit_zoom_into_pview_size */ /* ------------------------------- * on_swap_button_pressed_callback * ------------------------------- */ static void on_swap_button_pressed_callback(GtkWidget *wgt, GapMorphGUIParams *mgup) { GapMorphWorkPoint *wp; gint32 src_layer_width; gint32 src_layer_height; gint32 dst_layer_width; gint32 dst_layer_height; if((mgup->mgpp->osrc_layer_id < 0) || (mgup->mgpp->fdst_layer_id < 0)) { return; } src_layer_width = gimp_drawable_width(mgup->mgpp->osrc_layer_id); src_layer_height = gimp_drawable_height(mgup->mgpp->osrc_layer_id); dst_layer_width = gimp_drawable_width(mgup->mgpp->fdst_layer_id); dst_layer_height = gimp_drawable_height(mgup->mgpp->fdst_layer_id); GAP_MORPH_SWAP(gint32 ,mgup->mgpp->osrc_layer_id ,mgup->mgpp->fdst_layer_id ) GAP_MORPH_SWAP(gint32 ,mgup->src_win.offs_x ,mgup->dst_win.offs_x ) GAP_MORPH_SWAP(gint32 ,mgup->src_win.offs_y ,mgup->dst_win.offs_y ) GAP_MORPH_SWAP(gdouble ,mgup->src_win.max_zoom ,mgup->dst_win.max_zoom ) GAP_MORPH_SWAP(gdouble ,mgup->src_win.zoom ,mgup->dst_win.zoom ) for(wp = mgup->mgpp->master_wp_list; wp != NULL; wp = (GapMorphWorkPoint *)wp->next) { GAP_MORPH_SWAP(gdouble ,wp->osrc_x ,wp->fdst_x ) GAP_MORPH_SWAP(gdouble ,wp->osrc_y ,wp->fdst_y ) } if((src_layer_width != dst_layer_width) || (src_layer_height != dst_layer_height)) { /* scale is needed because src and dst layer differ in size */ p_scale_wp_list(mgup); } gimp_int_combo_box_set_active(GIMP_INT_COMBO_BOX(mgup->src_win.combo) , mgup->mgpp->osrc_layer_id); gimp_int_combo_box_set_active(GIMP_INT_COMBO_BOX(mgup->dst_win.combo) , mgup->mgpp->fdst_layer_id); p_set_upd_timer_request(mgup ,GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH ,GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH ); } /* end on_swap_button_pressed_callback */ /* ------------------------------ * on_fit_zoom_pressed_callback * ------------------------------ */ static void on_fit_zoom_pressed_callback(GtkWidget *wgt, GapMorphSubWin *swp) { p_fit_zoom_into_pview_size(swp); } /* end on_fit_zoom_pressed_callback */ /* --------------------------------- * p_hvscale_adj_set_limits * --------------------------------- */ static void p_hvscale_adj_set_limits(GapMorphSubWin *swp) { gdouble upper_limit; gdouble lower_limit; gdouble page_increment; gdouble page_size; gdouble value; gdouble fwidth; gdouble fheight; gdouble width; gdouble height; if(swp == NULL) { return; } if(swp->vscale_adj == NULL) { return; } if(swp->hscale_adj == NULL) { return; } if(*swp->layer_id_ptr < 0) { return; } width = (gdouble) gimp_drawable_width(*swp->layer_id_ptr); height = (gdouble) gimp_drawable_height(*swp->layer_id_ptr); fwidth = swp->zoom * (gdouble)swp->pv_ptr->pv_width; fheight = swp->zoom * (gdouble)swp->pv_ptr->pv_height; lower_limit = 0.0; upper_limit = width; page_size = (gdouble)fwidth; page_increment = (gdouble)(page_size / 2); value = swp->offs_x; if(gap_debug) { printf("\np_hvscale_adj_set_limits: ###\nfwidth : %d width:%d\n", (int)fwidth ,(int)width); printf("lower_limit %f\n", (float)lower_limit ); printf("upper_limit %f\n", (float)upper_limit ); printf("page_size %f\n", (float) page_size); printf("page_increment %f\n", (float)page_increment ); printf("value %f\n", (float)value ); } GTK_ADJUSTMENT(swp->hscale_adj)->lower = lower_limit; GTK_ADJUSTMENT(swp->hscale_adj)->upper = upper_limit; GTK_ADJUSTMENT(swp->hscale_adj)->page_increment = page_increment; GTK_ADJUSTMENT(swp->hscale_adj)->value = MIN(value, upper_limit); GTK_ADJUSTMENT(swp->hscale_adj)->page_size = page_size; lower_limit = 0.0; upper_limit = height; page_size = (gdouble)fheight; page_increment = (gdouble)(page_size / 2); value = swp->offs_y; if(gap_debug) { printf("\n fheight : %d height:%d\n", (int)fheight ,(int)height); printf("lower_limit %f\n", (float)lower_limit ); printf("upper_limit %f\n", (float)upper_limit ); printf("page_size %f\n", (float) page_size); printf("page_increment %f\n", (float)page_increment ); printf("value %f\n", (float)value ); } GTK_ADJUSTMENT(swp->vscale_adj)->lower = lower_limit; GTK_ADJUSTMENT(swp->vscale_adj)->upper = upper_limit; GTK_ADJUSTMENT(swp->vscale_adj)->page_increment = page_increment; GTK_ADJUSTMENT(swp->vscale_adj)->value = MIN(value, upper_limit); GTK_ADJUSTMENT(swp->vscale_adj)->page_size = page_size; gtk_widget_queue_draw(swp->hscale); gtk_widget_queue_draw(swp->vscale); } /* end p_hvscale_adj_set_limits */ /* ------------------- * on_timer_update_job * ------------------- */ static void on_timer_update_job(GapMorphGUIParams *mgup) { if(gap_debug) printf("\non_timer_update_job: START\n"); if(mgup) { if(mgup->src_win.upd_request != GAP_MORPH_DLG_UPD_REQUEST_NONE) { if(mgup->src_win.upd_request == GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH) { p_render_zoomed_pview(&mgup->src_win); } else { p_prevw_draw(&mgup->src_win); } mgup->src_win.upd_request = GAP_MORPH_DLG_UPD_REQUEST_NONE; } if(mgup->dst_win.upd_request != GAP_MORPH_DLG_UPD_REQUEST_NONE) { if(mgup->dst_win.upd_request == GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH) { p_render_zoomed_pview(&mgup->dst_win); } else { p_prevw_draw(&mgup->dst_win); } mgup->dst_win.upd_request = GAP_MORPH_DLG_UPD_REQUEST_NONE; } if(mgup->upd_timertag >= 0) { g_source_remove(mgup->upd_timertag); } mgup->upd_timertag = -1; } } /* end on_timer_update_job */ /* ----------------------- * p_set_upd_timer_request * ----------------------- */ static void p_set_upd_timer_request(GapMorphGUIParams *mgup, gint32 src_request, gint32 dst_request) { mgup->src_win.upd_request = MAX(mgup->src_win.upd_request, src_request); mgup->dst_win.upd_request = MAX(mgup->dst_win.upd_request, dst_request); /* add a timer with 16 millesec delay * (no need to do that if the there is already a pending * timer request. if there is no pending request upd_timertag == -1) */ if(mgup->upd_timertag < 0) { mgup->upd_timertag = (gint32) g_timeout_add(16, (GtkFunction)on_timer_update_job, mgup); } } /* end p_set_upd_timer_request */ /* ----------------------------- * on_koord_spinbutton_changed * ----------------------------- * because the val_ptr changes to follow * current workpoint we use the koord_id * and have to find the val_ptr at runtime * new at each call */ static void on_koord_spinbutton_changed (GtkObject *obj, gint32 koord_id) { GapMorphSubWin *swp; gdouble *val_ptr; gdouble value; swp = g_object_get_data( G_OBJECT(obj), "swp" ); val_ptr = NULL; switch(koord_id) { case GAP_MORPH_KOORD_WPX: val_ptr = swp->wpx_ptr; break; case GAP_MORPH_KOORD_WPY: val_ptr = swp->wpy_ptr; break; default: return; } value = (gint32)GTK_ADJUSTMENT(obj)->value; if(value != *val_ptr) { gimp_double_adjustment_update(GTK_ADJUSTMENT(obj), val_ptr); // *val_ptr = value; if(swp) { /* setup a timer request for pview redraw after 16 millisec * to prevent multiple updates */ p_set_upd_timer_request((GapMorphGUIParams *)swp->mgup , GAP_MORPH_DLG_UPD_REQUEST_REDRAW /* src_request */ , GAP_MORPH_DLG_UPD_REQUEST_REDRAW /* dst_request */ ); } } } /* end on_koord_spinbutton_changed */ /* ----------------------------- * on_curr_point_spinbutton_changed * ----------------------------- * set current workpoint to the n.the list element * where n == the entered number in the spinbutton widget */ static void on_curr_point_spinbutton_changed (GtkObject *obj, GapMorphGUIParams *mgup) { gdouble value; gint32 l_idx; GapMorphWorkPoint *wp; GapMorphGlobalParams *mgpp; if(mgup == NULL) { return; } mgpp = mgup->mgpp; if(mgpp == NULL) { return; } value = (gint32)GTK_ADJUSTMENT(obj)->value; /* find the n.th workpoint in the list */ l_idx = 1; for(wp = mgpp->master_wp_list; wp != NULL; wp= wp->next) { if(l_idx == value) { break; } l_idx++; } if(wp == NULL) { gtk_adjustment_set_value(GTK_ADJUSTMENT(obj), (gdouble)(l_idx-1)); } else { if(wp != mgup->src_win.curr_wp) { p_set_current_workpoint(&mgup->src_win, wp); } } } /* end on_curr_point_spinbutton_changed */ /* ----------------------------- * gap_morph_dlg_new_workpont * ----------------------------- */ GapMorphWorkPoint * gap_morph_dlg_new_workpont(gdouble srcx, gdouble srcy, gdouble dstx, gdouble dsty) { GapMorphWorkPoint *wp; wp = g_new(GapMorphWorkPoint, 1); wp->next = NULL; wp->fdst_x = dstx; wp->fdst_y = dsty; wp->osrc_x = srcx; wp->osrc_y = srcy; wp->dst_x = wp->fdst_x; wp->dst_y = wp->fdst_y; wp->src_x = wp->osrc_x; wp->src_y = wp->osrc_y; return(wp); } /* end gap_morph_dlg_new_workpont */ /* ----------------------------- * p_delete_current_point * ----------------------------- * delete the current workpoint. * but: never delete the last workpoint in the list. */ static void p_delete_current_point(GapMorphSubWin *swp) { GapMorphGUIParams *mgup; GapMorphWorkPoint *wp; gdouble delx; gdouble dely; mgup = (GapMorphGUIParams *)swp->mgup; if(mgup->mgpp->master_wp_list->next) { GapMorphWorkPoint *wp_prev; wp_prev = NULL; for(wp = mgup->mgpp->master_wp_list; wp != NULL; wp = (GapMorphWorkPoint *)wp->next) { if(wp == mgup->src_win.curr_wp) { if(swp->src_flag) { delx = wp->osrc_x; dely = wp->osrc_y; } else { delx = wp->fdst_x; dely = wp->fdst_y; } if(wp_prev == NULL) { /* delete the 1.st workpoint */ wp = mgup->mgpp->master_wp_list->next; g_free(mgup->mgpp->master_wp_list); mgup->mgpp->master_wp_list = wp; p_set_nearest_current_workpoint(swp, delx, dely); return; } /* delete a workpoint that is not the 1.st one */ wp_prev->next = wp->next; g_free(wp); p_set_nearest_current_workpoint(swp, delx, dely); break; } wp_prev = wp; } } p_refresh_total_points_label(mgup); } /* end p_delete_current_point */ /* ----------------------------- * p_set_nearest_current_workpoint * ----------------------------- * set reference pointers to the current workpoint * always for both (src_win and dst_win) */ static void p_set_nearest_current_workpoint(GapMorphSubWin *swp, gdouble in_x, gdouble in_y) { GapMorphWorkPoint *wp; gdouble ret_sqr_dist; wp = p_find_nearest_point(swp, in_x, in_y, &ret_sqr_dist); if(wp) { p_set_current_workpoint(swp, wp); } } /*end p_set_nearest_current_workpoint */ /* ----------------------------- * p_set_current_workpoint_no_refresh * ----------------------------- * set reference pointers to the current workpoint * always for both (src_win and dst_win) */ static void p_set_current_workpoint_no_refresh(GapMorphSubWin *swp, GapMorphWorkPoint *wp_cur) { GapMorphGUIParams *mgup; GapMorphWorkPoint *wp; gint32 l_idx; mgup = (GapMorphGUIParams *)swp->mgup; if(wp_cur == NULL) { return; } mgup->src_win.curr_wp = wp_cur; mgup->dst_win.curr_wp = wp_cur; mgup->src_win.wpx_ptr = &wp_cur->osrc_x; mgup->src_win.wpy_ptr = &wp_cur->osrc_y; mgup->dst_win.wpx_ptr = &wp_cur->fdst_x; mgup->dst_win.wpy_ptr = &wp_cur->fdst_y; if((mgup->mgpp == NULL) || (mgup->curr_point_spinbutton_adj == NULL)) { return; } p_upd_warp_info_label(mgup); /* find the index of the current workpoint in the master list */ l_idx = 1; for(wp = mgup->mgpp->master_wp_list; wp != NULL; wp= wp->next) { if(wp == wp_cur) { gtk_adjustment_set_value(GTK_ADJUSTMENT(mgup->curr_point_spinbutton_adj), (gdouble)(l_idx)); break; return; } l_idx++; } } /* end p_set_current_workpoint_no_refresh */ /* ----------------------------- * p_set_current_workpoint * ----------------------------- * set reference pointers to the current workpoint * always for both (src_win and dst_win) */ static void p_set_current_workpoint(GapMorphSubWin *swp, GapMorphWorkPoint *wp_cur) { GapMorphGUIParams *mgup; gint wgt_count; mgup = (GapMorphGUIParams *)swp->mgup; if(wp_cur == NULL) { return; } p_set_current_workpoint_no_refresh(swp, wp_cur); if(swp->startup_flag) { return; } wgt_count = 0; if(mgup->src_win.x_spinbutton_adj) { wgt_count++; } if(mgup->src_win.y_spinbutton_adj) { wgt_count++; } if(mgup->dst_win.x_spinbutton_adj) { wgt_count++; } if(mgup->dst_win.y_spinbutton_adj) { wgt_count++; } if(wgt_count >= 4) { /* set adjustment values and start timer request * but only if we already have all * reqired (4) widgets initialized * (otherwise we are in startup and may crash when timer fires too early) */ gtk_adjustment_set_value(GTK_ADJUSTMENT(mgup->src_win.x_spinbutton_adj), wp_cur->osrc_x); gtk_adjustment_set_value(GTK_ADJUSTMENT(mgup->src_win.y_spinbutton_adj), wp_cur->osrc_y); gtk_adjustment_set_value(GTK_ADJUSTMENT(mgup->dst_win.x_spinbutton_adj), wp_cur->fdst_x); gtk_adjustment_set_value(GTK_ADJUSTMENT(mgup->dst_win.y_spinbutton_adj), wp_cur->fdst_y); p_set_upd_timer_request(mgup ,GAP_MORPH_DLG_UPD_REQUEST_REDRAW ,GAP_MORPH_DLG_UPD_REQUEST_REDRAW ); } } /* end p_set_current_workpoint */ /* ----------------------------- * p_add_new_point * ----------------------------- * add a new point at in_x/in_y * and calculate the other koordianates * (using the offests of the nearest existing point * as guess) */ static GapMorphWorkPoint * p_add_new_point(GapMorphSubWin *swp, gdouble in_x, gdouble in_y) { GapMorphGUIParams *mgup; GapMorphSubWin *swp_other; GapMorphWorkPoint *wp_near; GapMorphWorkPoint *wp; gdouble srcx; gdouble srcy; gdouble dstx; gdouble dsty; gdouble ret_sqr_dist; gdouble wo, ho, w, h; mgup = (GapMorphGUIParams *)swp->mgup; wo = 1.0; ho = 1.0; w = 1.0; h = 1.0; /* set the other point with same offset as the nearest available point */ wp_near = p_find_nearest_point(swp, in_x, in_y, &ret_sqr_dist); if(swp->src_flag) { swp_other = &mgup->dst_win; if(*swp_other->layer_id_ptr >= 0) { wo = gimp_drawable_width(*swp_other->layer_id_ptr); w = gimp_drawable_width(*swp->layer_id_ptr); ho = gimp_drawable_height(*swp_other->layer_id_ptr); h = gimp_drawable_height(*swp->layer_id_ptr); } srcx = in_x; srcy = in_y; if(mgup->op_mode == GAP_MORPH_OP_MODE_MOVE) { dstx = (srcx) * w / MAX(wo,1); dsty = (srcy) * h / MAX(ho,1); } else { dstx = (srcx + (wp_near->fdst_x - wp_near->osrc_x)) * w / MAX(wo,1); dsty = (srcy + (wp_near->fdst_y - wp_near->osrc_y)) * h / MAX(ho,1); } } else { swp_other = &mgup->src_win; if(*swp_other->layer_id_ptr >= 0) { wo = gimp_drawable_width(*swp_other->layer_id_ptr); w = gimp_drawable_width(*swp->layer_id_ptr); ho = gimp_drawable_height(*swp_other->layer_id_ptr); h = gimp_drawable_height(*swp->layer_id_ptr); } dstx = in_x; dsty = in_y; if(mgup->op_mode == GAP_MORPH_OP_MODE_MOVE) { srcx = (dstx) * w / MAX(wo,1); srcy = (dsty) * h / MAX(ho,1); } else { srcx = (dstx + (wp_near->osrc_x - wp_near->fdst_x)) * w / MAX(wo,1); srcy = (dsty + (wp_near->osrc_y - wp_near->fdst_y)) * h / MAX(ho,1); } } wp = gap_morph_dlg_new_workpont(srcx, srcy, dstx, dsty); /* add new workpoint as 1st listelement */ wp->next = mgup->mgpp->master_wp_list; mgup->mgpp->master_wp_list = wp; return(wp); } /* end p_add_new_point */ /* ----------------------------- * p_add_new_point_refresh * ----------------------------- * add a new point at in_x/in_y * and set the newly added point as current point * (this also sets refresh request) */ static void p_add_new_point_refresh(GapMorphSubWin *swp, gdouble in_x, gdouble in_y) { GapMorphGUIParams *mgup; GapMorphWorkPoint *wp; wp = p_add_new_point(swp, in_x, in_y); p_set_current_workpoint(swp, wp); mgup = (GapMorphGUIParams *)swp->mgup; p_refresh_total_points_label(mgup); } /* end p_add_new_point_refresh */ /* ----------------------------- * p_refresh_total_points_label * ----------------------------- * add a new point at in_x/in_y * and set the newly added point as current point * (this also sets refresh request) */ static void p_refresh_total_points_label(GapMorphGUIParams *mgup) { GapMorphWorkPoint *wp; gint total_points; total_points = 0; for(wp = mgup->mgpp->master_wp_list; wp != NULL; wp = (GapMorphWorkPoint *)wp->next) { total_points++; } if(mgup->toal_points_label) { char num_buf[10]; g_snprintf(num_buf, sizeof(num_buf), "%03d", (int)total_points); gtk_label_set_text(GTK_LABEL(mgup->toal_points_label), num_buf); } } /* end p_refresh_total_points_label */ /* --------------------------------- * p_find_nearest_point * --------------------------------- * saerch the workpoint list for the point that is the nearest * to position in_x/in_y in the osrc or fdst koord system. * (depending on the swp->src_flag) */ static GapMorphWorkPoint * p_find_nearest_point(GapMorphSubWin *swp , gdouble in_x , gdouble in_y , gdouble *ret_sqr_dist ) { GapMorphWorkPoint *wp; GapMorphWorkPoint *wp_list; GapMorphWorkPoint *wp_ret; gdouble sqr_distance; gdouble min_sqr_distance; GapMorphGUIParams *mgup; mgup = (GapMorphGUIParams *)swp->mgup; wp_list = mgup->mgpp->master_wp_list; wp_ret = wp_list; min_sqr_distance = GAP_MORPH_MAXGINT32; for(wp = wp_list; wp != NULL; wp = (GapMorphWorkPoint *)wp->next) { register gdouble adx; register gdouble ady; if(swp->src_flag) { adx = abs(wp->osrc_x - in_x); ady = abs(wp->osrc_y - in_y); } else { adx = abs(wp->fdst_x - in_x); ady = abs(wp->fdst_y - in_y); } sqr_distance = (adx * adx) + (ady * ady); if(sqr_distance < min_sqr_distance) { wp_ret = wp; min_sqr_distance = sqr_distance; } } *ret_sqr_dist = min_sqr_distance; return(wp_ret); } /* end p_find_nearest_point */ /* ----------------------------- * p_pick_nearest_point * ----------------------------- * if there is a near point * then set this point as new current workpoint and * return TRUE * else * return FALSE */ static gboolean p_pick_nearest_point(GapMorphSubWin *swp, gdouble l_x, gdouble l_y) { GapMorphWorkPoint *wp; gdouble sqr_distance; wp = p_find_nearest_point(swp, l_x, l_y, &sqr_distance); if(sqr_distance <= GAP_MORPH_PICK_SQR_NEAR_THRESHOLD) { p_set_current_workpoint(swp, wp); return (TRUE); } return (FALSE); } /* end p_pick_nearest_point */ /* -------------------------------- * p_show_warp_pick_point * -------------------------------- */ static void p_show_warp_pick_point(GapMorphGUIParams *mgup ,gdouble in_x ,gdouble in_y ) { gdouble pick_x; gdouble pick_y; gdouble scale_x; gdouble scale_y; gint32 src_layer_width; gint32 src_layer_height; gint32 dst_layer_width; gint32 dst_layer_height; scale_x = 1.0; scale_y = 1.0; if((mgup->mgpp->osrc_layer_id >= 0) && (mgup->mgpp->fdst_layer_id >= 0)) { src_layer_width = gimp_drawable_width(mgup->mgpp->osrc_layer_id); src_layer_height = gimp_drawable_height(mgup->mgpp->osrc_layer_id); dst_layer_width = gimp_drawable_width(mgup->mgpp->fdst_layer_id); dst_layer_height = gimp_drawable_height(mgup->mgpp->fdst_layer_id); scale_x = src_layer_width / MAX(1,dst_layer_width); scale_y = src_layer_height / MAX(1,dst_layer_height); } gap_morph_exec_get_warp_pick_koords(mgup->mgpp->master_wp_list ,in_x ,in_y ,scale_x ,scale_y ,mgup->mgpp->use_quality_wp_selection ,mgup->mgpp->use_gravity ,mgup->mgpp->gravity_intensity ,mgup->mgpp->affect_radius ,&pick_x ,&pick_y ); mgup->show_in_x = in_x; mgup->show_in_y = in_y; mgup->show_px = pick_x; mgup->show_py = pick_y; p_upd_warp_info_label(mgup); /* show debug values distance & weight to current point */ p_set_upd_timer_request(mgup , GAP_MORPH_DLG_UPD_REQUEST_REDRAW /* src_request */ , GAP_MORPH_DLG_UPD_REQUEST_REDRAW /* dst_request */ ); } /* end p_show_warp_pick_point */ /* ------------------------------ * p_draw_workpoints * ------------------------------ */ static void p_draw_workpoints (GapMorphSubWin *swp) { GdkColor fg; GdkColor fg_curr; GdkColor fg_sel; GdkColormap *cmap; guchar l_red, l_green, l_blue; GapMorphWorkPoint *wp; GapMorphWorkPoint *wp_list; GapMorphGUIParams *mgup; gdouble px, py; gdouble scalex, scaley; GapMorphSubWin *swp_other; gboolean show_lines; mgup = (GapMorphGUIParams *)swp->mgup; wp_list = mgup->mgpp->master_wp_list; show_lines = FALSE; if(mgup->show_lines_checkbutton) { if (GTK_TOGGLE_BUTTON (mgup->show_lines_checkbutton)->active) { show_lines = TRUE; } } if(swp->src_flag) { swp_other = &mgup->dst_win; } else { swp_other = &mgup->src_win; } scalex = gimp_drawable_width(*swp->layer_id_ptr) / gimp_drawable_width(*swp_other->layer_id_ptr); scaley = gimp_drawable_height(*swp->layer_id_ptr) / gimp_drawable_height(*swp_other->layer_id_ptr); cmap = gtk_widget_get_colormap(swp->pv_ptr->da_widget); gimp_rgb_get_uchar (&mgup->pointcolor, &l_red, &l_green, &l_blue); fg.red = (l_red << 8) | l_red; fg.green = (l_green << 8) | l_green; fg.blue = (l_blue << 8) | l_blue; gimp_rgb_get_uchar (&mgup->curr_pointcolor, &l_red, &l_green, &l_blue); fg_curr.red = (l_red << 8) | l_red; fg_curr.green = (l_green << 8) | l_green; fg_curr.blue = (l_blue << 8) | l_blue; fg_sel.red = (l_red << 8) | l_red; fg_sel.green = (l_green << 7) | l_green; fg_sel.blue = (l_blue << 8) | l_blue; /*if(gap_debug) printf ("fg.r/g/b (%d %d %d)\n", (int)fg.red ,(int)fg.green, (int)fg.blue); */ if(cmap) { gdk_colormap_alloc_color(cmap , &fg , FALSE /* writeable */ , TRUE /* best_match */ ); gdk_colormap_alloc_color(cmap , &fg_curr , FALSE /* writeable */ , TRUE /* best_match */ ); gdk_colormap_alloc_color(cmap , &fg_sel , FALSE /* writeable */ , TRUE /* best_match */ ); } /*if(gap_debug) printf ("fg.pixel (%d)\n", (int)fg.pixel); */ for(wp=(GapMorphWorkPoint *)wp_list; wp != NULL; wp = (GapMorphWorkPoint *)wp->next) { if(swp->src_flag) { px = (wp->osrc_x - swp->offs_x) / swp->zoom; py = (wp->osrc_y - swp->offs_y) / swp->zoom; } else { px = (wp->fdst_x - swp->offs_x) / swp->zoom; py = (wp->fdst_y - swp->offs_y) / swp->zoom; } if(wp == swp->curr_wp) { gdk_gc_set_foreground (swp->pv_ptr->da_widget->style->black_gc, &fg_curr); } else { if((mgup->show_in_x >= 0) && (wp->warp_weight >= 0)) { /* for debug: show in selected color */ gdk_gc_set_foreground (swp->pv_ptr->da_widget->style->black_gc, &fg_sel); } else { gdk_gc_set_foreground (swp->pv_ptr->da_widget->style->black_gc, &fg); } } /* draw the morph workpoint(s) */ gdk_draw_arc (swp->pv_ptr->da_widget->window, swp->pv_ptr->da_widget->style->black_gc , TRUE , (px -RADIUS) , (py -RADIUS) , RADIUS * 2, RADIUS * 2, 0, 23040 ); if((!swp->src_flag) && (show_lines)) { gdouble qx, qy; qx = ((wp->osrc_x * scalex) - swp->offs_x) / swp->zoom; qy = ((wp->osrc_y * scaley) - swp->offs_y) / swp->zoom; /* draw vektor of workpoint movement (only in dst window) */ gdk_draw_line (swp->pv_ptr->da_widget->window ,swp->pv_ptr->da_widget->style->black_gc ,px ,py ,qx ,qy ); } } if(mgup->show_in_x >= 0) { l_red = 250; l_green = 16; l_blue = 16; fg.red = (l_red << 8) | l_red; fg.green = (l_green << 8) | l_green; fg.blue = (l_blue << 8) | l_blue; if(cmap) { gdk_colormap_alloc_color(cmap , &fg , FALSE /* writeable */ , TRUE /* best_match */ ); gdk_gc_set_foreground (swp->pv_ptr->da_widget->style->black_gc, &fg); } if(swp->src_flag) { px = (mgup->show_px - swp->offs_x) / swp->zoom; py = (mgup->show_py - swp->offs_y) / swp->zoom; } else { px = (mgup->show_in_x - swp->offs_x) / swp->zoom; py = (mgup->show_in_y - swp->offs_y) / swp->zoom; } /* draw the warp pick point * (the point that will be picked for the current position in src by the warp procedure) * THIS is a debug feature */ gdk_draw_arc (swp->pv_ptr->da_widget->window, swp->pv_ptr->da_widget->style->black_gc , TRUE , (px -RADIUS_SHOW) , (py -RADIUS_SHOW) , RADIUS_SHOW * 2, RADIUS_SHOW * 2, 0, 23040 ); } /* restore black gc */ fg.red = 0; fg.green = 0; fg.blue = 0; if(cmap) { gdk_colormap_alloc_color(cmap , &fg , FALSE /* writeable */ , TRUE /* best_match */ ); } gdk_gc_set_foreground (swp->pv_ptr->da_widget->style->black_gc, &fg); } /* end p_draw_workpoints */ /* ------------------------------ * p_prevw_draw * ------------------------------ * Preview Rendering routine * does refresh preview and draw the workpoints */ static void p_prevw_draw (GapMorphSubWin *swp) { /*if(gap_debug) printf("p_prevw_draw: START\n");*/ if(swp->pv_ptr == NULL) { return; } if(swp->pv_ptr->da_widget==NULL) { return; } /*if(gap_debug) printf("p_prevw_draw: gap_pview_repaint\n");*/ gap_pview_repaint(swp->pv_ptr); p_draw_workpoints(swp); } /* end p_prevw_draw */ /* ---------------------------------- * p_render_zoomed_pview * ---------------------------------- * set image in the pview widget * according to current zoom and offet settings */ static void p_render_zoomed_pview(GapMorphSubWin *swp) { if(*swp->layer_id_ptr >= 0) { GimpDrawable *dst_drawable; GimpDrawable *src_drawable; GimpImageBaseType l_basetype; GimpImageBaseType l_type; gint32 src_image_id; gint32 src_layer_id; gint32 tmp_image_id; gint32 tmp_layer_id; gdouble fwidth; gdouble fheight; gint width; gint height; gint offs_x; gint offs_y; src_layer_id = *swp->layer_id_ptr; if(gap_debug) printf("p_render_zoomed_pview START src_layer_id: %d\n", (int)src_layer_id); src_image_id = gimp_drawable_get_image(src_layer_id); l_basetype = gimp_image_base_type(src_image_id); l_type = GIMP_RGBA_IMAGE; if(l_basetype == GIMP_GRAY) { l_type = GIMP_GRAYA_IMAGE; } src_drawable = gimp_drawable_get (src_layer_id); /* constrain to legal values */ fwidth = swp->zoom * (gdouble)swp->pv_ptr->pv_width; fheight = swp->zoom * (gdouble)swp->pv_ptr->pv_height; width = CLAMP((gint)fwidth, 1, (gint)src_drawable->width); height = CLAMP((gint)fheight, 1, (gint)src_drawable->height); offs_x = CLAMP(swp->offs_x, 0, ((gint)src_drawable->width - width)); offs_y = CLAMP(swp->offs_y, 0, ((gint)src_drawable->height - height)); /* feedback constrained values */ swp->offs_x = offs_x; swp->offs_y = offs_y; tmp_image_id = gimp_image_new(width, height, l_basetype); tmp_layer_id = gimp_layer_new(tmp_image_id, "bg" , width , height , l_type , 100.0 /* full opaque */ , GIMP_NORMAL_MODE ); gimp_image_add_layer (tmp_image_id, tmp_layer_id, 0); /* copy the visible region to temp_layer_id */ { GimpPixelRgn srcPR; GimpPixelRgn dstPR; guchar *buf_ptr; dst_drawable = gimp_drawable_get (tmp_layer_id); buf_ptr = g_malloc(dst_drawable->bpp * dst_drawable->width * dst_drawable->height); if(gap_debug) { printf("p_render_zoomed_pview: w/h: %d / %d offs_x/y: %d / %d\n" , (int)width , (int)height , (int)offs_x , (int)offs_y ); } gimp_pixel_rgn_init (&srcPR, src_drawable , offs_x, offs_y /* x1, y1 */ , width , height , FALSE /* dirty */ , FALSE /* shadow */ ); gimp_pixel_rgn_init (&dstPR, dst_drawable , 0, 0 /* x1, y1 */ , width , height , TRUE /* dirty */ , FALSE /* shadow */ ); gimp_pixel_rgn_get_rect(&srcPR ,buf_ptr ,offs_x ,offs_y ,width ,height ); gimp_pixel_rgn_set_rect(&dstPR ,buf_ptr ,0 ,0 ,width ,height ); g_free(buf_ptr); gimp_drawable_detach(dst_drawable); gimp_drawable_detach(src_drawable); } /* render the preview (this includes scaling to preview size) */ gap_pview_render_from_image(swp->pv_ptr, tmp_image_id); gimp_image_delete(tmp_image_id); p_draw_workpoints(swp); p_hvscale_adj_set_limits(swp); } } /* end p_render_zoomed_pview */ /* ----------------------------- * on_pview_events * ----------------------------- */ static gint on_pview_events (GtkWidget *widget , GdkEvent *event , GapMorphSubWin *swp) { GapMorphGUIParams *mgup; GdkEventButton *bevent; GdkEventMotion *mevent; gint mouse_button; gdouble curx; /* current mouse position koordinate */ gdouble cury; static gdouble prevx; /* prev mouse position koordinate */ static gdouble prevy; static gboolean drag_disabled = FALSE; /* ALT or CTRL pressed */ mouse_button = 0; bevent = (GdkEventButton *) event; if(swp == NULL) { return FALSE;} if(swp->startup_flag) { return FALSE;} mgup = (GapMorphGUIParams *)swp->mgup; if(mgup == NULL) { return FALSE;} switch (event->type) { case GDK_EXPOSE: /*if(gap_debug) printf("GDK_EXPOSE\n"); */ p_prevw_draw(swp); /* draw preview and workpoints */ return FALSE; break; case GDK_BUTTON_RELEASE: bevent = (GdkEventButton *) event; mouse_button = 0 - bevent->button; swp->pview_scrolling = FALSE; drag_disabled = FALSE; prevx = -1; prevy = -1; return (FALSE); case GDK_BUTTON_PRESS: bevent = (GdkEventButton *) event; mouse_button = bevent->button; curx = bevent->x; cury = bevent->y; goto mouse; case GDK_MOTION_NOTIFY: mevent = (GdkEventMotion *) event; if ( !mevent->state ) break; curx = mevent->x; cury = mevent->y; mouse: if((mouse_button == 1) || (mouse_button == 3)) { gdouble l_x; gdouble l_y; gboolean make_new_point; /* Picking of pathpoints is done when * the left mousebutton goes down (mouse_button == 1) */ l_x = swp->offs_x + (curx * swp->zoom); l_y = swp->offs_y + (cury * swp->zoom); make_new_point = FALSE; /* Debug SHOW handling */ if (mgup->op_mode == GAP_MORPH_OP_MODE_SHOW) { if(mouse_button == 1) { p_show_warp_pick_point(mgup, l_x, l_y); } else { GapMorphWorkPoint *wp; gdouble sqr_distance; /* set nearest point as new current point */ wp = p_find_nearest_point(swp, l_x, l_y, &sqr_distance); p_set_current_workpoint(swp, wp); } return (FALSE); } /* ZOOM handling */ if (mgup->op_mode == GAP_MORPH_OP_MODE_ZOOM) { mgup->show_in_x = -1; mgup->show_in_y = -1; if(bevent->state & GDK_CONTROL_MASK) { if(mouse_button == 1) { p_zoom_out(swp); } else { p_zoom_in(swp, l_x, l_y); } } else { if(mouse_button == 1) { p_zoom_in(swp, l_x, l_y); } else { p_zoom_out(swp); } } return (FALSE); } /* DELETE handling */ if((mouse_button == 3) || (mgup->op_mode == GAP_MORPH_OP_MODE_DELETE)) { if((p_pick_nearest_point(swp, l_x, l_y)) || (mgup->op_mode == GAP_MORPH_OP_MODE_DELETE)) { p_delete_current_point(swp); p_prevw_draw(swp); } return (FALSE); } if(bevent->state & GDK_SHIFT_MASK) { /* SHIFT-Click: force creation of new point * at mouse pointer position */ make_new_point = TRUE; } else { GapMorphWorkPoint *wp; gdouble sqr_distance; wp = p_find_nearest_point(swp, l_x, l_y, &sqr_distance); /* on ALT-click just pick current point * but dont drag and dont create new point */ if(bevent->state & GDK_CONTROL_MASK) { drag_disabled = TRUE; } if(bevent->state & GDK_MOD1_MASK) { p_set_current_workpoint(swp, wp); drag_disabled = TRUE; return(FALSE); } /* normal SET op_mode: try to pick near point * create new point if nothing is near * MOVE op_mode: always pick nearest point, * dont create point on click */ if(sqr_distance <= GAP_MORPH_PICK_SQR_NEAR_THRESHOLD) { p_set_current_workpoint(swp, wp); } else { if (mgup->op_mode != GAP_MORPH_OP_MODE_MOVE) { make_new_point = TRUE; } else { p_set_current_workpoint(swp, wp); } } } if(make_new_point) { /* add the new point and handle refresh for both src and dst view */ p_add_new_point_refresh(swp, l_x, l_y); return(FALSE); } } /* Handle SCROLLING */ if((mgup->op_mode == GAP_MORPH_OP_MODE_ZOOM) || (mouse_button == 2) || (swp->pview_scrolling)) { gint l_dx; gint l_dy; gint32 src_request; gint32 dst_request; l_dx = 0; l_dy = 0; if((prevx >= 0) && (prevy >= 0)) { l_dx = prevx - curx; l_dy = prevy - cury; } swp->offs_x += l_dx; swp->offs_y += l_dy; swp->pview_scrolling = TRUE; if(gap_debug) printf("scrolling dx:%d dy: %d\n", (int)l_dx ,(int)l_dy); prevx = curx; prevy = cury; if(swp->src_flag) { src_request = GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH; dst_request = GAP_MORPH_DLG_UPD_REQUEST_NONE; } else { src_request = GAP_MORPH_DLG_UPD_REQUEST_NONE; dst_request = GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH; } p_set_upd_timer_request(swp->mgup, src_request, dst_request); return (FALSE); } /* dragging the current workpoint * (is locked if we are currently deleting or zooming * or by modifier Keys ALT and CTRL in SET mode) */ if((!drag_disabled) & (mgup->op_mode != GAP_MORPH_OP_MODE_SHOW)) { *swp->wpx_ptr = swp->offs_x + (curx * swp->zoom); *swp->wpy_ptr = swp->offs_y + (cury * swp->zoom); if((swp->x_spinbutton_adj) &&(swp->y_spinbutton_adj)) { /* Render the Preview and Workpoints */ p_prevw_draw(swp); gtk_adjustment_set_value (GTK_ADJUSTMENT(swp->x_spinbutton_adj), *swp->wpx_ptr); gtk_adjustment_set_value (GTK_ADJUSTMENT(swp->y_spinbutton_adj), *swp->wpy_ptr); } } break; default: break; } return FALSE; } /* end on_pview_events */ /* ---------------------------------- * p_scale_wp_list * ---------------------------------- * scale workpoints from old width/height to * new layer dimensions. * (dont scale if old_width value 0 * in that case there we had no other valid layerdimension before) * this procedures sets the old dimensions width/height equal to the * current dimensions at end of processing. */ static void p_scale_wp_list(GapMorphGUIParams *mgup) { GapMorphWorkPoint *wp; gint32 src_layer_width; gint32 src_layer_height; gint32 dst_layer_width; gint32 dst_layer_height; gdouble src_scale_x; gdouble src_scale_y; gdouble dst_scale_x; gdouble dst_scale_y; if(mgup == NULL) { return; } src_scale_x = 1.0; src_scale_y = 1.0; src_layer_width = 0; src_layer_height = 0; if(mgup->mgpp->osrc_layer_id >= 0) { src_layer_width = gimp_drawable_width(mgup->mgpp->osrc_layer_id); src_layer_height = gimp_drawable_height(mgup->mgpp->osrc_layer_id); if(mgup->old_src_layer_width > 0) { src_scale_x = (gdouble)src_layer_width / (gdouble)MAX(1,mgup->old_src_layer_width); src_scale_y = (gdouble)src_layer_height / (gdouble)MAX(1,mgup->old_src_layer_height); } } dst_scale_x = 1.0; dst_scale_y = 1.0; dst_layer_width = 0; dst_layer_height = 0; if(mgup->mgpp->fdst_layer_id >= 0) { dst_layer_width = gimp_drawable_width(mgup->mgpp->fdst_layer_id); dst_layer_height = gimp_drawable_height(mgup->mgpp->fdst_layer_id); if(mgup->old_dst_layer_width > 0) { dst_scale_x = (gdouble)dst_layer_width / (gdouble)MAX(1,mgup->old_dst_layer_width); dst_scale_y = (gdouble)dst_layer_height / (gdouble)MAX(1,mgup->old_dst_layer_height); } } if(gap_debug) { printf("p_scale_wp_list SRC_LAYER: %d DST_LAYER: %d\n" , (int)mgup->mgpp->osrc_layer_id , (int)mgup->mgpp->fdst_layer_id ); printf("p_scale_wp_list src_layer_width: (old:%d) %d\n" , (int)mgup->old_src_layer_width , (int)src_layer_width ); printf("p_scale_wp_list src_layer_height: (old:%d) %d\n" , (int)mgup->old_src_layer_height , (int)src_layer_height ); printf("p_scale_wp_list dst_layer_width: (old:%d) %d\n" , (int)mgup->old_dst_layer_width , (int)dst_layer_width ); printf("p_scale_wp_list dst_layer_height: (old:%d) %d\n" , (int)mgup->old_dst_layer_height , (int)dst_layer_height ); printf("p_scale_wp_list src_scale_x: %f\n", (float)src_scale_x); printf("p_scale_wp_list src_scale_y: %f\n", (float)src_scale_y); printf("p_scale_wp_list dst_scale_x: %f\n", (float)dst_scale_x); printf("p_scale_wp_list dst_scale_y: %f\n", (float)dst_scale_y); } for(wp = mgup->mgpp->master_wp_list; wp != NULL; wp = (GapMorphWorkPoint *)wp->next) { /* scale the loaded workpoints * (to fit the current layer) */ wp->osrc_x *= src_scale_x; wp->osrc_y *= src_scale_y; wp->fdst_x *= dst_scale_x; wp->fdst_y *= dst_scale_y; wp->src_x = wp->osrc_x; wp->src_y = wp->osrc_y; wp->dst_x = wp->fdst_x; wp->dst_y = wp->fdst_y; } /* store current dimensions as old dimensions * to be prepared for the next call */ if(src_layer_width > 0) { mgup->old_src_layer_width = src_layer_width; mgup->old_src_layer_height = src_layer_height; } if(dst_layer_width > 0) { mgup->old_dst_layer_width = dst_layer_width; mgup->old_dst_layer_height = dst_layer_height; } } /* end p_scale_wp_list */ /* ----------------------------- * p_imglayer_menu_callback * ----------------------------- */ static void p_imglayer_menu_callback(GtkWidget *widget, GapMorphSubWin *swp) { gint32 l_image_id; gint value; gint32 layer_id; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value); layer_id = value; l_image_id = gimp_drawable_get_image(layer_id); if(!gap_image_is_alive(l_image_id)) { if(gap_debug) printf("p_imglayer_menu_callback: NOT ALIVE image_id=%d layer_id=%d\n", (int)l_image_id, (int)layer_id); return; } if(swp->layer_id_ptr) { if(layer_id != *swp->layer_id_ptr) { *swp->layer_id_ptr = layer_id; if(gap_debug) printf("p_imglayer_menu_callback new LAYER_ID: %d\n", (int)layer_id); p_scale_wp_list(swp->mgup); p_fit_zoom_into_pview_size(swp); } } if(gap_debug) { printf("p_imglayer_menu_callback: image_id=%d layer_id=%d\n" , (int)swp->image_id, (int)*swp->layer_id_ptr); } } /* end p_imglayer_menu_callback */ /* ----------------------------- * p_imglayer_constrain * ----------------------------- */ static gint p_imglayer_constrain(gint32 image_id, gint32 drawable_id, gpointer data) { if(gap_debug) { printf("GAP-DEBUG: p_imglayer_constrain PROCEDURE image_id:%d drawable_id:%d\n" ,(int)image_id ,(int)drawable_id ); } if(drawable_id < 0) { /* gimp 1.1 makes a first call of the constraint procedure * with drawable_id = -1, and skips the whole image if FALSE is returned */ return(TRUE); } if(!gap_image_is_alive(image_id)) { return(FALSE); } if(!gimp_drawable_has_alpha(drawable_id)) { return(FALSE); } /* Accept all other RGB and GRAY layers */ if(gimp_drawable_is_rgb(drawable_id)) { return(TRUE); } if(gimp_drawable_is_gray(drawable_id)) { return(TRUE); } return (FALSE); } /* end p_imglayer_constrain */ /* ----------------------------- * p_refresh_layer_menu * ----------------------------- */ static void p_refresh_layer_menu(GapMorphSubWin *swp, GapMorphGUIParams *mgup) { gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (swp->combo), *swp->layer_id_ptr, /* the initial value to set */ G_CALLBACK (p_imglayer_menu_callback), swp ); } /* end p_refresh_layer_menu */ /* ----------------------------- * on_pointcolor_button_changed * ----------------------------- * repaint with new pointcolors * (for both pviews) */ static void on_pointcolor_button_changed(GimpColorButton *widget, GimpRGB *pcolor ) { GapMorphGUIParams *mgup; mgup = g_object_get_data( G_OBJECT(widget), "mgup"); if(mgup) { gimp_color_button_get_color(widget, pcolor); p_set_upd_timer_request(mgup ,GAP_MORPH_DLG_UPD_REQUEST_REDRAW ,GAP_MORPH_DLG_UPD_REQUEST_REDRAW ); } } /* end on_pointcolor_button_changed */ /* -------------------------------- * on_wp_filesel_destroy * -------------------------------- */ static void on_wp_filesel_destroy (GtkObject *object ,GapMorphGUIParams *mgup) { if(gap_debug) printf("CB: on_wp_filesel_destroy\n"); if(mgup == NULL) return; mgup->wp_filesel = NULL; } /* end on_wp_filesel_destroy */ /* ----------------------------------- * on_wp_filesel_button_cancel_clicked * ----------------------------------- */ static void on_wp_filesel_button_cancel_clicked (GtkButton *button ,GapMorphGUIParams *mgup) { if(gap_debug) printf("CB: on_wp_filesel_button_cancel_clicked\n"); if(mgup == NULL) return; /* update workpoint_file_labels */ if(mgup->workpoint_file_lower_label) { gtk_label_set_text(GTK_LABEL(mgup->workpoint_file_lower_label) ,mgup->mgpp->workpoint_file_lower ); } if(mgup->workpoint_file_upper_label) { gtk_label_set_text(GTK_LABEL(mgup->workpoint_file_upper_label) ,mgup->mgpp->workpoint_file_upper ); } if(mgup->wp_filesel) { gtk_widget_destroy(mgup->wp_filesel); mgup->wp_filesel = NULL; } } /* end on_wp_filesel_button_cancel_clicked */ /* -------------------------------- * on_wp_filesel_button_OK_clicked * -------------------------------- * used both for save and load */ static void on_wp_filesel_button_OK_clicked (GtkButton *button ,GapMorphGUIParams *mgup) { const gchar *filename; gint l_errno; if(gap_debug) printf("CB: on_wp_filesel_button_OK_clicked\n"); if(mgup == NULL) return; if(mgup->workpoint_file_ptr == NULL) return; /* quit if Main window was closed */ if(mgup->shell == NULL) { gtk_main_quit (); return; } if(mgup->wp_filesel) { filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (mgup->wp_filesel)); g_snprintf(mgup->workpoint_file_ptr ,GAP_MORPH_WORKPOINT_FILENAME_MAX_LENGTH ,"%s" ,filename ); if(mgup->wp_save_mode) { gboolean l_wr_permission; l_wr_permission = gap_arr_overwrite_file_dialog(filename); /* quit if Main window was closed while overwrite dialog was open */ if(mgup->shell == NULL) { gtk_main_quit (); return; } if(l_wr_permission) { if(!gap_moprh_exec_save_workpointfile(filename, mgup)) { l_errno = errno; g_message (_("Failed to write morph workpointfile\n" "filename: '%s':\n%s") , filename , g_strerror (l_errno) ); } } } else { GapMorphWorkPoint *wp_list; wp_list = gap_moprh_exec_load_workpointfile(filename, mgup); l_errno = errno; if(wp_list) { if(mgup->mgpp->master_wp_list) { gap_morph_exec_free_workpoint_list(&mgup->mgpp->master_wp_list); } mgup->mgpp->master_wp_list = wp_list; p_set_current_workpoint(&mgup->src_win, mgup->mgpp->master_wp_list); p_refresh_total_points_label(mgup); p_upd_widget_values(mgup); } else { if(l_errno != 0) { g_message(_("ERROR: Could not open morph workpoints\n" "filename: '%s'\n%s") ,filename, g_strerror (errno)); } else { g_message(_("ERROR: Could not read morph workpoints\n" "filename: '%s'\n(Is not a valid morph workpoint file)") ,filename); } } } on_wp_filesel_button_cancel_clicked(NULL, (gpointer)mgup); } } /* end on_wp_filesel_button_OK_clicked */ /* ---------------------------------- * p_create_wp_filesel * ---------------------------------- * videofile selection dialog */ static void p_create_wp_filesel (GapMorphGUIParams *mgup ,GdkEventButton *bevent ,gboolean save_mode) { GtkWidget *wp_button_OK; GtkWidget *wp_button_cancel; if(mgup == NULL) { return; } mgup->workpoint_file_ptr = &mgup->mgpp->workpoint_file_lower[0]; if(bevent) { if(bevent->state & GDK_SHIFT_MASK) { mgup->workpoint_file_ptr = &mgup->mgpp->workpoint_file_upper[0]; } } if(mgup->wp_filesel) { gtk_window_present(GTK_WINDOW(mgup->wp_filesel)); printf("p_create_wp_filesel: filesel dialog already open\n"); return; } mgup->wp_save_mode = save_mode; if(save_mode) { mgup->wp_filesel = gtk_file_selection_new (_("Save Morph Workpointfile")); } else { mgup->wp_filesel = gtk_file_selection_new (_("Load Morph Workpointfile")); } gtk_container_set_border_width (GTK_CONTAINER (mgup->wp_filesel), 10); wp_button_OK = GTK_FILE_SELECTION (mgup->wp_filesel)->ok_button; gtk_widget_show (wp_button_OK); GTK_WIDGET_SET_FLAGS (wp_button_OK, GTK_CAN_DEFAULT); wp_button_cancel = GTK_FILE_SELECTION (mgup->wp_filesel)->cancel_button; gtk_widget_show (wp_button_cancel); GTK_WIDGET_SET_FLAGS (wp_button_cancel, GTK_CAN_DEFAULT); g_signal_connect (G_OBJECT (mgup->wp_filesel), "destroy", G_CALLBACK (on_wp_filesel_destroy), mgup); g_signal_connect (G_OBJECT (wp_button_OK), "clicked", G_CALLBACK (on_wp_filesel_button_OK_clicked), mgup); g_signal_connect (G_OBJECT (wp_button_cancel), "clicked", G_CALLBACK (on_wp_filesel_button_cancel_clicked), mgup); gtk_file_selection_set_filename (GTK_FILE_SELECTION (mgup->wp_filesel), mgup->workpoint_file_ptr); gtk_widget_grab_default (wp_button_cancel); gtk_widget_show (mgup->wp_filesel); } /* end p_create_wp_filesel */ /* -------------------------------- * on_wp_save_button_clicked * -------------------------------- */ static void on_wp_save_button_clicked (GtkButton *button ,GdkEventButton *bevent ,GapMorphGUIParams *mgup) { p_create_wp_filesel(mgup ,bevent ,TRUE /* save_mode */ ); } /* end on_wp_save_button_clicked */ /* -------------------------------- * on_wp_load_button_clicked * -------------------------------- */ static void on_wp_load_button_clicked (GtkButton *button ,GdkEventButton *bevent ,GapMorphGUIParams *mgup) { p_create_wp_filesel(mgup ,bevent ,FALSE /* save_mode */ ); } /* end on_wp_load_button_clicked */ /* -------------------------------- * on_wp_shape_button_clicked * -------------------------------- */ static void on_wp_shape_button_clicked (GtkButton *button ,GdkEventButton *bevent ,GapMorphGUIParams *mgup ) { if(mgup) { gboolean clear_old_workpoint_set; clear_old_workpoint_set = TRUE; if(bevent) { if(bevent->state & GDK_SHIFT_MASK) { clear_old_workpoint_set = FALSE; } } if(clear_old_workpoint_set) { gap_morph_exec_free_workpoint_list(&mgup->mgpp->master_wp_list); } mgup->num_shapepoints = (gint32)GTK_ADJUSTMENT(mgup->num_shapepoints_adj)->value;; p_generate_outline_shape_workpoints(mgup); p_set_upd_timer_request(mgup ,GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH ,GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH ); p_refresh_total_points_label(mgup); } } /* end on_wp_shape_button_clicked */ /* ------------------------------ * on_hvscale_changed_callback * ------------------------------ */ static void on_hvscale_changed_callback(GtkObject *obj, GapMorphSubWin *swp) { gint32 value; gint32 src_request; gint32 dst_request; if(swp == NULL) { return;} if(obj == swp->vscale_adj) { value = (gint32)GTK_ADJUSTMENT(swp->vscale_adj)->value; if(value != swp->offs_y) { swp->offs_y = value; } } else { value = (gint32)GTK_ADJUSTMENT(swp->hscale_adj)->value; if(value != swp->offs_x) { swp->offs_x = value; } } if(swp->src_flag) { src_request = GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH; dst_request = GAP_MORPH_DLG_UPD_REQUEST_NONE; } else { src_request = GAP_MORPH_DLG_UPD_REQUEST_NONE; dst_request = GAP_MORPH_DLG_UPD_REQUEST_FULL_REFRESH; } p_set_upd_timer_request(swp->mgup, src_request, dst_request); } /* end on_hvscale_changed_callback */ /* ------------------------------ * on_show_lines_toggled_callback * ------------------------------ */ static void on_show_lines_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup) { if(mgup) { p_set_upd_timer_request(mgup , 0 /* src_request */ , GAP_MORPH_DLG_UPD_REQUEST_REDRAW /* dst_request */ ); } } /* end on_show_lines_toggled_callback */ /* -------------------------------------------- * on_use_quality_wp_selection_toggled_callback * -------------------------------------------- */ static void on_use_quality_wp_selection_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup) { if(mgup) { if(GTK_TOGGLE_BUTTON (mgup->use_quality_wp_selection_checkbutton)->active) { mgup->mgpp->use_quality_wp_selection = TRUE; } else { mgup->mgpp->use_quality_wp_selection = FALSE; } } } /* end on_use_quality_wp_selection_toggled_callback */ /* ------------------------------ * on_use_gravity_toggled_callback * ------------------------------ */ static void on_use_gravity_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup) { if(mgup) { if(GTK_TOGGLE_BUTTON (mgup->use_gravity_checkbutton)->active) { mgup->mgpp->use_gravity = TRUE; gtk_widget_set_sensitive(mgup->gravity_intensity_spinbutton, TRUE); } else { mgup->mgpp->use_gravity = FALSE; gtk_widget_set_sensitive(mgup->gravity_intensity_spinbutton, FALSE); } } } /* end on_use_gravity_toggled_callback */ /* -------------------------------------- * on_have_workpointsets_toggled_callback * -------------------------------------- */ static void on_have_workpointsets_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup) { if(mgup) { if(GTK_TOGGLE_BUTTON (mgup->have_workpointsets_checkbutton)->active) { mgup->mgpp->have_workpointsets = TRUE; gtk_widget_show(mgup->workpoint_file_lower_label); gtk_widget_show(mgup->workpoint_file_upper_label); gtk_widget_show(mgup->workpoint_lower_label); gtk_widget_show(mgup->workpoint_upper_label); } else { mgup->mgpp->have_workpointsets = FALSE; gtk_widget_hide(mgup->workpoint_file_lower_label); gtk_widget_hide(mgup->workpoint_file_upper_label); gtk_widget_hide(mgup->workpoint_lower_label); gtk_widget_hide(mgup->workpoint_upper_label); } } } /* end on_have_workpointsets_toggled_callback */ /* --------------------------------------- * on_create_tween_layers_toggled_callback * --------------------------------------- */ static void on_create_tween_layers_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup) { if(mgup) { if(GTK_TOGGLE_BUTTON (mgup->create_tween_layers_checkbutton)->active) { mgup->mgpp->create_tween_layers = TRUE; } else { mgup->mgpp->create_tween_layers = FALSE; } } } /* end on_create_tween_layers_toggled_callback */ /* --------------------------------- * on_radio_op_mode_callback * --------------------------------- */ static void on_radio_op_mode_callback(GtkWidget *widget, gint32 op_mode) { GapMorphGUIParams *mgup; mgup = g_object_get_data( G_OBJECT(widget), "mgup"); if((mgup) && (GTK_TOGGLE_BUTTON (widget)->active)) { if(gap_debug) printf("on_radio_op_mode_callback: OP_MODE: %d\n", (int)op_mode); mgup->op_mode = op_mode; } } /* end on_radio_op_mode_callback */ /* --------------------------------- * on_radio_render_mode_callback * --------------------------------- */ static void on_radio_render_mode_callback(GtkWidget *widget, gint32 render_mode) { GapMorphGUIParams *mgup; mgup = g_object_get_data( G_OBJECT(widget), "mgup"); if((mgup) && (GTK_TOGGLE_BUTTON (widget)->active)) { if(gap_debug) printf("on_radio_render_mode_callback: render_mode: %d\n", (int)render_mode); mgup->mgpp->render_mode = render_mode; } } /* end on_radio_render_mode_callback */ /* --------------------------------- * p_radio_create_op_mode * --------------------------------- */ static void p_radio_create_op_mode(GtkWidget *table, int row, int col, GapMorphGUIParams *mgup) { GtkWidget *label; GtkWidget *radio_table; GtkWidget *radio_button; GSList *radio_group = NULL; gint l_idx; gint l_idy; gboolean l_radio_pressed; label = gtk_label_new(_("Edit Mode:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach( GTK_TABLE (table), label, col, col+1, row, row+1 , GTK_FILL, GTK_FILL, 8, 0); gtk_widget_show(label); /* radio_table */ /*radio_table = gtk_table_new (1, 5, FALSE);*/ radio_table = table; l_idx = col+1; l_idy = row; /* radio button SET */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Set") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach ( GTK_TABLE (radio_table), radio_button, l_idx, l_idx+1, l_idy, l_idy+1 , GTK_FILL | GTK_EXPAND, 0, 0, 0); mgup->op_mode_set_toggle = radio_button; l_radio_pressed = (mgup->op_mode == GAP_MORPH_OP_MODE_SET); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button , _("Click: pick and drag point at cursor" " or create new point\n" "SHIFT-Click: force create new point\n" "Alt-Click: disable drag\n" "Right-Click: delete point at cursor") , NULL); gtk_widget_show (radio_button); g_object_set_data( G_OBJECT(radio_button), "mgup", mgup); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (on_radio_op_mode_callback), (gpointer)GAP_MORPH_OP_MODE_SET); l_idx++; /* radio button MOVE */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Move") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach ( GTK_TABLE (radio_table), radio_button, l_idx, l_idx+1, l_idy, l_idy+1 , GTK_FILL | GTK_EXPAND, 0, 0, 0); mgup->op_mode_move_toggle = radio_button; l_radio_pressed = (mgup->op_mode == GAP_MORPH_OP_MODE_MOVE); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button , _("Click: drag next point\n" "SHIFT-Click: force create new point\n" "Alt-Click: disable drag\n" "Right-Click: delete point at cursor\n") , NULL); gtk_widget_show (radio_button); g_object_set_data( G_OBJECT(radio_button), "mgup", mgup); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (on_radio_op_mode_callback), (gpointer)GAP_MORPH_OP_MODE_MOVE); l_idx++; /* radio button DELETE */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Delete") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach ( GTK_TABLE (radio_table), radio_button, l_idx, l_idx+1, l_idy, l_idy+1 , GTK_FILL | GTK_EXPAND, 0, 0, 0); mgup->op_mode_delete_toggle = radio_button; l_radio_pressed = (mgup->op_mode == GAP_MORPH_OP_MODE_DELETE); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button , _("Click: delete next point") , NULL); gtk_widget_show (radio_button); g_object_set_data( G_OBJECT(radio_button), "mgup", mgup); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (on_radio_op_mode_callback), (gpointer)GAP_MORPH_OP_MODE_DELETE); l_idx++; /* radio button ZOOM */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Zoom") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach ( GTK_TABLE (radio_table), radio_button, l_idx, l_idx+1, l_idy, l_idy+1 , GTK_FILL | GTK_EXPAND, 0, 0, 0); mgup->op_mode_zoom_toggle = radio_button; l_radio_pressed = (mgup->op_mode == GAP_MORPH_OP_MODE_ZOOM); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button , _("Click: zoom in,\nCTRL-click: zoom out") , NULL); gtk_widget_show (radio_button); g_object_set_data( G_OBJECT(radio_button), "mgup", mgup); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (on_radio_op_mode_callback), (gpointer)GAP_MORPH_OP_MODE_ZOOM); l_idx++; /* radio button SHOW */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Show") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach ( GTK_TABLE (radio_table), radio_button, l_idx, l_idx+1, l_idy, l_idy+1 , GTK_FILL | GTK_EXPAND, 0, 0, 0); mgup->op_mode_show_toggle = radio_button; l_radio_pressed = (mgup->op_mode == GAP_MORPH_OP_MODE_SHOW); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button , _("Click: show warp pick coordinates in the source window") , NULL); gtk_widget_show (radio_button); g_object_set_data( G_OBJECT(radio_button), "mgup", mgup); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (on_radio_op_mode_callback), (gpointer)GAP_MORPH_OP_MODE_SHOW); } /* end p_radio_create_op_mode */ /* --------------------------------- * p_radio_create_render_mode * --------------------------------- */ static void p_radio_create_render_mode(GtkWidget *table, int row, int col, GapMorphGUIParams *mgup) { GtkWidget *label; GtkWidget *radio_table; GtkWidget *radio_button; GSList *radio_group = NULL; gint l_idx; gint l_idy; gboolean l_radio_pressed; label = gtk_label_new(_("Render Mode:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach( GTK_TABLE (table), label, col, col+1, row, row+1 , GTK_FILL, GTK_FILL, 8, 0); gtk_widget_show(label); /* radio_table */ radio_table = table; l_idx = col +1; l_idy = row; /* radio button MORPH */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Morph") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach ( GTK_TABLE (radio_table), radio_button, l_idx, l_idx+1, l_idy, l_idy+1 , GTK_FILL | GTK_EXPAND, 0, 0, 0); mgup->render_mode_morph_toggle = radio_button; l_radio_pressed = (mgup->mgpp->render_mode == GAP_MORPH_RENDER_MODE_MORPH); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button , _("Render morph transition (warp forward, warp backward and cross fade)") , NULL); gtk_widget_show (radio_button); g_object_set_data( G_OBJECT(radio_button), "mgup", mgup); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (on_radio_render_mode_callback), (gpointer)GAP_MORPH_RENDER_MODE_MORPH); l_idx++; /* radio button WARP */ radio_button = gtk_radio_button_new_with_label ( radio_group, _("Warp") ); radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (radio_button) ); gtk_table_attach ( GTK_TABLE (radio_table), radio_button, l_idx, l_idx+1, l_idy, l_idy+1 , GTK_FILL | GTK_EXPAND, 0, 0, 0); mgup->render_mode_warp_toggle = radio_button; l_radio_pressed = (mgup->mgpp->render_mode == GAP_MORPH_RENDER_MODE_WARP); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), l_radio_pressed); gimp_help_set_help_data(radio_button , _("Render forward warp transitions only") , NULL); gtk_widget_show (radio_button); g_object_set_data( G_OBJECT(radio_button), "mgup", mgup); g_signal_connect ( G_OBJECT (radio_button), "toggled", G_CALLBACK (on_radio_render_mode_callback), (gpointer)GAP_MORPH_RENDER_MODE_WARP); } /* end p_radio_create_render_mode */ /* ----------------------------- * p_create_subwin * ----------------------------- */ static GtkWidget * p_create_subwin(GapMorphSubWin *swp , const char *title , GapMorphGUIParams *mgup , GtkWidget *master_hbox ) { GtkWidget *frame; GtkWidget *vbox; GtkWidget *aspect_frame; GtkWidget *da_widget; GtkWidget *table; GtkWidget *pv_table; GtkWidget *spinbutton; GtkWidget *button; GtkWidget *combo; GtkWidget *label; gint row; GtkObject *adj; /* the frame */ frame = gimp_frame_new (title); gtk_box_pack_start (GTK_BOX (master_hbox), frame, FALSE, FALSE, 0); /* the vbox */ vbox = gtk_vbox_new (FALSE, 4); gtk_container_add (GTK_CONTAINER (frame), vbox); gtk_widget_show (vbox); /* table */ table = gtk_table_new (2, 11, FALSE); gtk_widget_show (table); gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); row = 0; /* the layer seletion combobox */ label = gtk_label_new( _("Layer:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1 , GTK_FILL, 0, 4, 0); gtk_widget_show(label); combo = gimp_drawable_combo_box_new (p_imglayer_constrain, NULL); gtk_table_attach(GTK_TABLE(table), combo, 1, 10, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); if(swp->src_flag) { gimp_help_set_help_data(combo, _("Select the source layer") , NULL); } else { gimp_help_set_help_data(combo, _("Select the destination layer ") , NULL); } gtk_widget_show(combo); swp->combo = combo; /* p_refresh_layer_menu(swp, mgup); */ /* is done later after the pview widget is initialized */ gtk_widget_show(combo); row++; /* the x koordinate label */ label = gtk_label_new (_("X:")); gtk_widget_show (label); gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 4, 0); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); /* the x koordinate spinbutton */ adj = gtk_adjustment_new ( 0 , 0 , 10000 /* constrain to image width is done later */ , 1, 10, 0); swp->x_spinbutton_adj = adj; spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); gtk_widget_show (spinbutton); gtk_table_attach (GTK_TABLE (table), spinbutton, 1, 2, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (spinbutton, 60, -1); gimp_help_set_help_data (spinbutton, _("Morphpoint X coordinate"), NULL); g_object_set_data( G_OBJECT(adj), "swp", swp); g_signal_connect (G_OBJECT (adj), "value_changed" , G_CALLBACK (on_koord_spinbutton_changed) , (gpointer)GAP_MORPH_KOORD_WPX); /* the y koordinate label */ label = gtk_label_new (_("Y:")); gtk_widget_show (label); gtk_table_attach (GTK_TABLE (table), label, 2, 3, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 4, 0); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); /* the y koordinate spinbutton */ adj = gtk_adjustment_new ( 0 , 0 , 10000 /* constrain to image height is done later */ , 1, 10, 0); swp->y_spinbutton_adj = adj; spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); gtk_widget_show (spinbutton); gtk_table_attach (GTK_TABLE (table), spinbutton, 3, 4, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (spinbutton, 60, -1); gimp_help_set_help_data (spinbutton, _("Morphpoint Y coordinate"), NULL); g_object_set_data( G_OBJECT(adj), "swp", swp); g_signal_connect (G_OBJECT (adj), "value_changed" , G_CALLBACK (on_koord_spinbutton_changed) , (gpointer)GAP_MORPH_KOORD_WPY); /* Fit Zoom Button */ button = gtk_button_new_from_stock ( _("Fit Zoom") ); gtk_table_attach( GTK_TABLE(table), button, 4, 5, row, row+1, GTK_FILL, 0, 8, 0 ); gimp_help_set_help_data(button, _("Show the whole layer." " (by adjusting zoom to fit into preview).") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "pressed", G_CALLBACK (on_fit_zoom_pressed_callback), swp); if(!swp->src_flag) { /* there is just one total_points display (always in the dst frame) */ /* the current Point label */ label = gtk_label_new (_("Point:")); gtk_widget_show (label); gtk_table_attach (GTK_TABLE (table), label, 6, 7, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 4, 0); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); /* the current point spinbutton */ adj = gtk_adjustment_new ( 0 , 1 , 10000 /* constrain to image height is done later */ , 1, 10, 0); mgup->curr_point_spinbutton_adj = adj; spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); gtk_widget_show (spinbutton); gtk_table_attach (GTK_TABLE (table), spinbutton, 7, 8, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (spinbutton, 60, -1); gimp_help_set_help_data (spinbutton, _("Number of the current point"), NULL); g_signal_connect (G_OBJECT (adj), "value_changed" , G_CALLBACK (on_curr_point_spinbutton_changed) , mgup); /* the number_of_points label */ label = gtk_label_new (_("of total:")); gtk_widget_show (label); gtk_table_attach (GTK_TABLE (table), label, 8, 9, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 4, 0); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); /* the number_of_points label */ label = gtk_label_new (_("001")); mgup->toal_points_label = label; gtk_widget_show (label); gtk_table_attach (GTK_TABLE (table), label, 9, 10, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 4, 0); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); } /* the pv_table (for aspect_frame and vscale hscale)*/ pv_table = gtk_table_new(2, 2, FALSE); gtk_widget_show (pv_table); gtk_box_pack_start (GTK_BOX (vbox), pv_table, FALSE, FALSE, 0); /* aspect_frame is the CONTAINER for the preview */ aspect_frame = gtk_aspect_frame_new (NULL /* without label */ , 0.5 /* xalign center */ , 0.5 /* yalign center */ , GAP_MORPH_PV_WIDTH / GAP_MORPH_PV_HEIGHT /* ratio */ , TRUE /* obey_child */ ); /* PREVIEW DRAWING AREA */ /* the preview drawing_area_widget */ /* ############################### */ swp->pv_ptr = gap_pview_new(GAP_MORPH_PV_WIDTH , GAP_MORPH_PV_HEIGHT , GAP_MORPH_CHECK_SIZE , aspect_frame ); da_widget = swp->pv_ptr->da_widget; gtk_container_add (GTK_CONTAINER (aspect_frame), da_widget); gtk_table_attach (GTK_TABLE (pv_table), aspect_frame, 0, 1, 0, 1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0); gtk_widget_show (aspect_frame); gtk_widget_show (da_widget); gtk_widget_realize (da_widget); /* p_update_pviewsize(gpp); */ /* the call to gtk_widget_set_events results in WARNING: * (gimp-1.3:13789): Gtk-CRITICAL **: file gtkwidget.c: line 5257 (gtk_widget_set_events): assertion `!GTK_WIDGET_REALIZED (widget)' failed * * must use gtk_widget_add_events because the widget is already realized at this time */ gtk_widget_add_events( GTK_WIDGET(da_widget), GAP_MORPH_PVIEW_MASK ); g_signal_connect (G_OBJECT (da_widget), "event", G_CALLBACK (on_pview_events), swp); { gdouble upper_max; gdouble initial_val; GtkWidget *hscale; GtkWidget *vscale; upper_max = 1; initial_val = 1; /* the vscale */ adj = gtk_adjustment_new (initial_val , 1 , upper_max , 1.0, 1.0, 0.0 ); vscale = gtk_vscrollbar_new (GTK_ADJUSTMENT(adj)); gtk_range_set_update_policy (GTK_RANGE (vscale), GTK_UPDATE_DELAYED); /* GTK_UPDATE_CONTINUOUS */ gtk_table_attach (GTK_TABLE (pv_table), vscale, 1, 2, 0, 1, (GtkAttachOptions) (0), (GtkAttachOptions) (GTK_FILL), 0, 0); g_signal_connect (adj, "value_changed", G_CALLBACK (on_hvscale_changed_callback), swp); gtk_widget_show (vscale); swp->vscale_adj = adj; swp->vscale = vscale; /* the hscale */ adj = gtk_adjustment_new (initial_val , 1 , upper_max , 1.0, 1.0, 0.0 ); hscale = gtk_hscrollbar_new (GTK_ADJUSTMENT(adj)); gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_DELAYED); /* GTK_UPDATE_CONTINUOUS */ gtk_table_attach (GTK_TABLE (pv_table), hscale, 0, 1, 1, 2, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); g_signal_connect (adj, "value_changed", G_CALLBACK (on_hvscale_changed_callback), swp); gtk_widget_show (hscale); swp->hscale_adj = adj; swp->hscale = hscale; p_hvscale_adj_set_limits(swp); } return(frame); } /* end p_create_subwin */ /* ----------------------------- * gap_morph_create_dialog * ----------------------------- */ static void gap_morph_create_dialog(GapMorphGUIParams *mgup) { GtkWidget *dlg; GtkWidget *main_vbox; GtkWidget *hbox; GtkWidget *vbox; GtkWidget *frame; GtkWidget *table; GtkWidget *label; GtkWidget *button; GtkWidget *color_button; GtkWidget *spinbutton; GtkWidget *checkbutton; gint row; GtkObject *adj; dlg = gimp_dialog_new (_("Morph / Warp"), GAP_MORPH_PLUGIN_NAME, NULL, 0, gimp_standard_help_func, GAP_MORPH_HELP_ID, GIMP_STOCK_RESET, GAP_MORPH_RESPONSE_RESET, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_window_set_type_hint (dlg, GDK_WINDOW_TYPE_HINT_NORMAL); mgup->shell = dlg; mgup->src_win.startup_flag = TRUE; mgup->dst_win.startup_flag = TRUE; mgup->upd_timertag = -1; mgup->wp_filesel = NULL; mgup->wp_save_mode = FALSE; mgup->curr_point_spinbutton_adj = NULL; mgup->toal_points_label = NULL; mgup->workpoint_file_lower_label = NULL; mgup->workpoint_file_upper_label = NULL; mgup->warp_info_label = NULL; mgup->show_lines_checkbutton = NULL; mgup->src_win.x_spinbutton_adj = NULL; mgup->src_win.y_spinbutton_adj = NULL; mgup->dst_win.x_spinbutton_adj = NULL; mgup->dst_win.y_spinbutton_adj = NULL; mgup->src_win.layer_id_ptr = NULL; mgup->dst_win.layer_id_ptr = NULL; gimp_rgb_set(&mgup->pointcolor, 0.1, 1.0, 0.1); /* startup with GREEN pointcolor */ gimp_rgb_set_alpha(&mgup->pointcolor, 1.0); gimp_rgb_set(&mgup->curr_pointcolor, 1.0, 1.0, 0.1); /* startup with YELLOW color */ gimp_rgb_set_alpha(&mgup->curr_pointcolor, 1.0); mgup->old_src_layer_width = 0; mgup->old_src_layer_height = 0; mgup->old_dst_layer_width = 0; mgup->old_dst_layer_height = 0; mgup->op_mode = GAP_MORPH_OP_MODE_SET; mgup->show_in_x = -1; mgup->show_in_y = -1; mgup->num_shapepoints = 64; g_signal_connect (G_OBJECT (mgup->shell), "response", G_CALLBACK (p_morph_response), mgup); main_vbox = gtk_vbox_new (FALSE, 4); gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6); gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dlg)->vbox), main_vbox); /* the frame */ frame = gimp_frame_new (NULL); gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); /* the vbox */ vbox = gtk_vbox_new (FALSE, 4); gtk_container_add (GTK_CONTAINER (frame), vbox); gtk_widget_show (vbox); /* the hbox */ hbox = gtk_hbox_new (FALSE, 4); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); /* make sure that we have at least one workpoint */ if(mgup->mgpp->master_wp_list == NULL) { mgup->mgpp->master_wp_list = gap_morph_dlg_new_workpont(0,0,0,0); } /* src_frame */ mgup->src_win.mgup = mgup; mgup->src_win.src_flag = TRUE; mgup->src_win.startup_flag = FALSE; mgup->src_win.upd_request = GAP_MORPH_DLG_UPD_REQUEST_NONE; mgup->src_win.pview_scrolling = FALSE; mgup->src_win.max_zoom = 1.0; mgup->src_win.zoom = 1.0; mgup->src_win.offs_x = 0; mgup->src_win.offs_y = 0; mgup->src_win.layer_id_ptr = &mgup->mgpp->osrc_layer_id; p_set_current_workpoint_no_refresh(&mgup->src_win, mgup->mgpp->master_wp_list); frame = p_create_subwin(&mgup->src_win, _("Source"), mgup, hbox); gtk_widget_show (frame); /* dst_frame */ mgup->dst_win.mgup = mgup; mgup->dst_win.src_flag = FALSE; mgup->dst_win.upd_request = GAP_MORPH_DLG_UPD_REQUEST_NONE; mgup->dst_win.pview_scrolling = FALSE; mgup->dst_win.max_zoom = 1.0; mgup->dst_win.zoom = 1.0; mgup->dst_win.offs_x = 0; mgup->dst_win.offs_y = 0; mgup->dst_win.layer_id_ptr = &mgup->mgpp->fdst_layer_id; p_set_current_workpoint_no_refresh(&mgup->dst_win, mgup->mgpp->master_wp_list); frame = p_create_subwin(&mgup->dst_win, _("Destination"), mgup, hbox); gtk_widget_show (frame); p_refresh_layer_menu(&mgup->src_win, mgup); p_refresh_layer_menu(&mgup->dst_win, mgup); mgup->src_win.startup_flag = FALSE; mgup->dst_win.startup_flag = FALSE; p_set_current_workpoint(&mgup->dst_win, mgup->mgpp->master_wp_list); /* table 5rows 14cols */ table = gtk_table_new (5, 14, FALSE); gtk_widget_show (table); gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); row = 0; /* the nubner of ShapePoints label */ label = gtk_label_new (_("ShapePoints:")); gtk_widget_show (label); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* num_shapepoints spinbutton */ adj = gtk_adjustment_new ( mgup->num_shapepoints , 1 , 1000 , 1, 10, 0); mgup->num_shapepoints_adj = adj; spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); gtk_widget_show (spinbutton); gtk_table_attach (GTK_TABLE (table), spinbutton, 1, 2, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (spinbutton, 80, -1); gimp_help_set_help_data (spinbutton, _("Number of workpoints to create when Shape button is pressed"), NULL); g_signal_connect (G_OBJECT (adj), "value_changed" , G_CALLBACK (gimp_int_adjustment_update) , &mgup->num_shapepoints); /* Shape Button */ button = gtk_button_new_from_stock ( _("Shape") ); gtk_table_attach( GTK_TABLE(table), button, 2, 4, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Create N workpoints following the outline shape of the layer." "(the shape detection is looking for non-transparent pixels)." "SHIFT-click: adds the new points and keeps the old points") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (on_wp_shape_button_clicked), mgup); /* RADIO Buttons (attaches to 6 Columns) */ p_radio_create_op_mode(table, row, 4, mgup); /* the show lines checkbutton */ checkbutton = gtk_check_button_new_with_label ( _("Lines")); mgup->show_lines_checkbutton = checkbutton; gtk_widget_show (checkbutton); gtk_table_attach( GTK_TABLE(table), checkbutton, 10, 11, row, row+1, GTK_FILL, 0, 0, 0 ); g_signal_connect (checkbutton, "toggled", G_CALLBACK (on_show_lines_toggled_callback), mgup); gimp_help_set_help_data(checkbutton, _("Show movement vector lines in the destination preview") , NULL); /* Swap Windows Button */ button = gtk_button_new_from_stock (_("Swap")); gtk_table_attach( GTK_TABLE(table), button, 11, 12, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Exchange source and destination") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "pressed", G_CALLBACK (on_swap_button_pressed_callback), mgup); row++; /* the deform affect radius label */ label = gtk_label_new (_("Radius:")); gtk_widget_show (label); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* affect radius spinbutton */ adj = gtk_adjustment_new ( mgup->mgpp->affect_radius , 0 , 10000 , 1, 10, 0); mgup->affect_radius_spinbutton_adj = adj; spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); gtk_widget_show (spinbutton); gtk_table_attach (GTK_TABLE (table), spinbutton, 1, 2, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (spinbutton, 80, -1); gimp_help_set_help_data (spinbutton, _("Deform radius in pixels." " Each workpoint causes a move-deform operation" " within this affect radius.") , NULL); g_signal_connect (G_OBJECT (adj), "value_changed" , G_CALLBACK (gimp_double_adjustment_update) , &mgup->mgpp->affect_radius); /* the deform intensity label */ label = gtk_label_new (_("Intensity:")); gtk_widget_show (label); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 4, 5, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 8, 0); /* intensity spinbutton */ adj = gtk_adjustment_new ( mgup->mgpp->gravity_intensity , 1 , 5 , .1, 1, 0); mgup->gravity_intensity_spinbutton_adj = adj; spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 2); mgup->gravity_intensity_spinbutton = spinbutton; gtk_widget_show (spinbutton); gtk_table_attach (GTK_TABLE (table), spinbutton, 5, 7, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (spinbutton, 80, -1); gimp_help_set_help_data (spinbutton, _("Deform intensity.") , NULL); g_signal_connect (G_OBJECT (adj), "value_changed" , G_CALLBACK (gimp_double_adjustment_update) , &mgup->mgpp->gravity_intensity); /* the use_intensity checkbutton */ checkbutton = gtk_check_button_new_with_label ( _("Use Intensity")); mgup->use_gravity_checkbutton = checkbutton; gtk_widget_show (checkbutton); gtk_table_attach( GTK_TABLE(table), checkbutton, 8, 10, row, row+1, GTK_FILL, 0, 0, 0 ); g_signal_connect (checkbutton, "toggled", G_CALLBACK (on_use_gravity_toggled_callback), mgup); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), mgup->mgpp->use_gravity); gimp_help_set_help_data(checkbutton, _("ON: Descending deform action from workpoint (full) to radius (zero). Descend by power of intensity." "OFF: Linear deform action inside the radius") , NULL); /* the use_quality_wp_selection checkbutton */ checkbutton = gtk_check_button_new_with_label ( _("Quality")); mgup->use_quality_wp_selection_checkbutton = checkbutton; gtk_widget_show (checkbutton); gtk_table_attach( GTK_TABLE(table), checkbutton, 10, 11, row, row+1, GTK_FILL, 0, 0, 0 ); g_signal_connect (checkbutton, "toggled", G_CALLBACK (on_use_quality_wp_selection_toggled_callback), mgup); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), mgup->mgpp->use_quality_wp_selection); gimp_help_set_help_data(checkbutton, _("ON: Use quality workpoint selection algorithm." "OFF: Use fast workpoint selection algorithm.") , NULL); /* Load Workpoints Button */ button = gtk_button_new_from_stock (GTK_STOCK_OPEN ); gtk_table_attach( GTK_TABLE(table), button, 11, 12, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Load morph workpoints from file. SHIFT-click: define filename of Pointset B") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (on_wp_load_button_clicked), mgup); /* Save Workpoints Button */ button = gtk_button_new_from_stock ( GTK_STOCK_SAVE ); gtk_table_attach( GTK_TABLE(table), button, 12, 13, row, row+1, GTK_FILL, 0, 0, 0 ); gimp_help_set_help_data(button, _("Save morph workpoints to file. SHIFT-click: define filename of Pointset B") , NULL); gtk_widget_show (button); g_signal_connect (G_OBJECT (button), "button_press_event", G_CALLBACK (on_wp_save_button_clicked), mgup); row++; /* the tween_steps label */ label = gtk_label_new (_("Steps:")); gtk_widget_show (label); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* tween_steps_spinbutton */ adj = gtk_adjustment_new ( mgup->mgpp->tween_steps , 1 , 1000 , 1, 10, 0); mgup->tween_steps_spinbutton_adj = adj; spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); gtk_widget_show (spinbutton); gtk_table_attach (GTK_TABLE (table), spinbutton, 1, 2, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (spinbutton, 80, -1); gimp_help_set_help_data (spinbutton, _("Number of layers to create or modify." " Steps refers to N layers under the destination layer." " Steps is ignored if render mode is warp" " and source and destination are different layers" " of the same image"), NULL); g_signal_connect (G_OBJECT (adj), "value_changed" , G_CALLBACK (gimp_int_adjustment_update) , &mgup->mgpp->tween_steps); /* the pointcolor colorbutton */ color_button = gimp_color_button_new (_("Pointcolor"), 25, 12, /* WIDTH, HEIGHT, */ &mgup->pointcolor, GIMP_COLOR_AREA_FLAT); gtk_table_attach(GTK_TABLE(table), color_button, 2, 3, row, row+1 , 0, 0, 4, 0); gtk_widget_show (color_button); gimp_help_set_help_data(color_button, _("Set color for the morph workpoints") , NULL); g_object_set_data( G_OBJECT(color_button), "mgup", mgup); g_signal_connect (color_button, "color_changed", G_CALLBACK (on_pointcolor_button_changed), &mgup->pointcolor); /* the currentcolor colorbutton */ color_button = gimp_color_button_new (_("Current Pointcolor"), 25, 12, /* WIDTH, HEIGHT, */ &mgup->curr_pointcolor, GIMP_COLOR_AREA_FLAT); gtk_table_attach(GTK_TABLE(table), color_button, 3, 4, row, row+1 , 0, 0, 4, 0); gtk_widget_show (color_button); gimp_help_set_help_data(color_button, _("Set color for the current morph workpoint") , NULL); g_object_set_data( G_OBJECT(color_button), "mgup", mgup); g_signal_connect (color_button, "color_changed", G_CALLBACK (on_pointcolor_button_changed), mgup); /* the render_mode RADIO Buttons (attaches to 3 Columns: 4,5,6 ) */ p_radio_create_render_mode(table, row, 4, mgup); /* the create tween checkbutton */ checkbutton = gtk_check_button_new_with_label ( _("Create Layers")); mgup->create_tween_layers_checkbutton = checkbutton; gtk_widget_show (checkbutton); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), mgup->mgpp->create_tween_layers); gtk_table_attach( GTK_TABLE(table), checkbutton, 10, 11, row, row+1, GTK_FILL, 0, 0, 0 ); g_signal_connect (checkbutton, "toggled", G_CALLBACK (on_create_tween_layers_toggled_callback), mgup); gimp_help_set_help_data(checkbutton, _("ON: Create specified number of tween layers. " "OFF: Operate on existing layers below the destination layer") , NULL); /* the multiple pointsets checkbutton */ checkbutton = gtk_check_button_new_with_label ( _("Multiple Pointsets")); mgup->have_workpointsets_checkbutton = checkbutton; #ifdef GAP_MORPH_DEBUG_FEATURES gtk_widget_show (checkbutton); #endif gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), mgup->mgpp->have_workpointsets); gtk_table_attach( GTK_TABLE(table), checkbutton, 11, 13, row, row+1, GTK_FILL, 0, 0, 0 ); g_signal_connect (checkbutton, "toggled", G_CALLBACK (on_have_workpointsets_toggled_callback), mgup); gimp_help_set_help_data(checkbutton, _("ON: use 2 or more pointsets from file. " "Please create and save the pointsets first, " "using filenames with a 2-digit numberpart before the extension " "(points_01.txt, points_02.txt, points_03.txt) " "then open and SHIFT open the first and last pointset\n" "OFF: use current set of workpoints") , NULL); row++; /* the number_of_points label */ label = gtk_label_new ("---"); mgup->warp_info_label = label; #ifdef GAP_MORPH_DEBUG_FEATURES gtk_widget_show (label); #endif gtk_table_attach (GTK_TABLE (table), label, 0, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 4, 0); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); row++; /* the lower workpoint label */ label = gtk_label_new (_("Pointset A:")); mgup->workpoint_lower_label = label; gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* the lower workpoint file label */ label = gtk_label_new (&mgup->mgpp->workpoint_file_lower[0]); mgup->workpoint_file_lower_label = label; gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 1, 12, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); row++; /* the upper workpoint label */ label = gtk_label_new (_("Pointset B:")); mgup->workpoint_upper_label = label; gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* the upper workpoint file label */ label = gtk_label_new (&mgup->mgpp->workpoint_file_upper[0]); mgup->workpoint_file_upper_label = label; gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 1, 12, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* Show the main container */ gtk_widget_show (main_vbox); /* force have_workpointsets callback to show/hide workpoint lables * (those labels are only visible when multiple pontsets are enabled */ on_have_workpointsets_toggled_callback(mgup->have_workpointsets_checkbutton, mgup); on_use_gravity_toggled_callback(mgup->use_gravity_checkbutton, mgup); on_use_quality_wp_selection_toggled_callback(mgup->use_quality_wp_selection_checkbutton, mgup); } /* end gap_morph_create_dialog */ /* ----------------------------- * gap_morph_dialog * ----------------------------- */ gboolean gap_morph_dialog(GapMorphGlobalParams *mgpp) { GapMorphGUIParams morph_gui_params; GapMorphGUIParams *mgup; if(gap_debug) printf("gap_morph_dialog: ** START **\n"); gimp_ui_init ("gap_morph", FALSE); gap_stock_init(); mgup = &morph_gui_params; mgup->mgpp = mgpp; if(gap_debug) printf("gap_morph_dialog: START mgpp->master_wp_list: %d\n", (int)mgpp->master_wp_list); /* startup with empty workpoint list * (the pointer may be initalized with illegal adress * with parameter settings from the last execution) */ mgpp->master_wp_list = NULL; mgup->run_flag = FALSE; gap_morph_create_dialog(mgup); gtk_widget_show (mgup->shell); /* fit both src and dst into preview size * (this implicite forces full refresh) */ p_scale_wp_list(mgup); p_fit_zoom_into_pview_size(&mgup->src_win); p_fit_zoom_into_pview_size(&mgup->dst_win); if(gap_debug) printf("gap_morph_dialog.c BEFORE gtk_main\n"); gtk_main (); gdk_flush (); if(gap_debug) printf("gap_morph_dialog.c END\n"); if(mgup->run_flag) { return TRUE; /* OK, request to run the morph plug-in now */ } return FALSE; /* for cancel or close dialog without run request */ } /* end gap_morph_dialog */ gimp-gap-2.6.0+dfsg.orig/gap/gimplastvaldesc.h0000644000175000017500000002463611212030253021062 0ustar thibautthibaut/* gimplastvaldesc.h * * GAP ... Gimp Animation Plugins * * This Module contains: * Headers and types to register a plugin's LAST_VALUES buffer description * (needed for animated filtercalls using a common iterator procedure) * * should be a part of future libgimp for easy use in many plugin's. * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 2003/09/20 hof: added datatype support for guint guint32. * 2002/04/07 hof: created. */ #ifndef __GIMPLASTVALDESC_H__ #define __GIMPLASTVALDESC_H__ #ifndef __GIMP_H__ #include "libgimp/gimp.h" #endif typedef enum { GIMP_LASTVAL_NONE, /* keep GIMP_LASTVAL_NONE always the first entry */ GIMP_LASTVAL_ARRAY, GIMP_LASTVAL_STRUCT_BEGIN, GIMP_LASTVAL_STRUCT_END, GIMP_LASTVAL_LONG, GIMP_LASTVAL_SHORT, GIMP_LASTVAL_INT, GIMP_LASTVAL_GINT, GIMP_LASTVAL_GINT32, GIMP_LASTVAL_CHAR, GIMP_LASTVAL_GCHAR, GIMP_LASTVAL_GUCHAR, GIMP_LASTVAL_GDOUBLE, GIMP_LASTVAL_GFLOAT, GIMP_LASTVAL_FLOAT, GIMP_LASTVAL_DOUBLE, GIMP_LASTVAL_DRAWABLE, GIMP_LASTVAL_GINTDRAWABLE, GIMP_LASTVAL_GBOOLEAN, GIMP_LASTVAL_ENUM, /* not able to iterate */ GIMP_LASTVAL_GUINT, GIMP_LASTVAL_GUINT32, GIMP_LASTVAL_END, /* keep GIMP_LASTVAL_END always the last entry */ } GimpLastvalType; /* Helper MACROS for static initialisation of GimpLastvalDef Element(s) */ #define GIMP_LASTVALDEF_NONE(flag,val,name) { GIMP_LASTVAL_NONE, &val, sizeof(val), flag, name } #define GIMP_LASTVALDEF_ARRAY(flag,elem,name) { GIMP_LASTVAL_ARRAY, 0, G_N_ELEMENTS(elem), flag, name } #define GIMP_LASTVALDEF_STRUCT_BEGIN(flag,elem,name) { GIMP_LASTVAL_STRUCT_BEGIN, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_STRUCT_END(flag,elem,name) { GIMP_LASTVAL_STRUCT_END, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_LONG(flag,elem,name) { GIMP_LASTVAL_LONG, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_SHORT(flag,elem,name) { GIMP_LASTVAL_SHORT, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_INT(flag,elem,name) { GIMP_LASTVAL_INT, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_GINT(flag,elem,name) { GIMP_LASTVAL_GINT, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_GINT32(flag,elem,name) { GIMP_LASTVAL_GINT32, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_CHAR(flag,elem,name) { GIMP_LASTVAL_CHAR, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_GCHAR(flag,elem,name) { GIMP_LASTVAL_GCHAR, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_GUCHAR(flag,elem,name) { GIMP_LASTVAL_GUCHAR, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_GDOUBLE(flag,elem,name) { GIMP_LASTVAL_GDOUBLE, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_GFLOAT(flag,elem,name) { GIMP_LASTVAL_GFLOAT, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_FLOAT(flag,elem,name) { GIMP_LASTVAL_FLOAT, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_DOUBLE(flag,elem,name) { GIMP_LASTVAL_DOUBLE, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_DRAWABLE(flag,elem,name) { GIMP_LASTVAL_DRAWABLE, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_GINTDRAWABLE(flag,elem,name) { GIMP_LASTVAL_GINTDRAWABLE, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_GBOOLEAN(flag,elem,name) { GIMP_LASTVAL_BOOLEAN, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_ENUM(flag,elem,name) { GIMP_LASTVAL_ENUM, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_GUINT(flag,elem,name) { GIMP_LASTVAL_GUINT, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_GUINT32(flag,elem,name) { GIMP_LASTVAL_GUINT32, &elem, sizeof(elem), flag, name } /* More Helper MACROS for some often used Structured Types */ #define GIMP_LASTVALDEF_GIMPRGB(flag,elem,name) \ { GIMP_LASTVAL_STRUCT_BEGIN, &elem, sizeof(elem), flag, name }, \ { GIMP_LASTVAL_GDOUBLE, &elem.r, sizeof(elem.r), flag, "r" }, \ { GIMP_LASTVAL_GDOUBLE, &elem.g, sizeof(elem.g), flag, "g" }, \ { GIMP_LASTVAL_GDOUBLE, &elem.b, sizeof(elem.b), flag, "b" }, \ { GIMP_LASTVAL_GDOUBLE, &elem.a, sizeof(elem.a), flag, "a" }, \ { GIMP_LASTVAL_STRUCT_END, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_GIMPHSV(flag,elem,name) \ { GIMP_LASTVAL_STRUCT_BEGIN, &elem, sizeof(elem), flag, name }, \ { GIMP_LASTVAL_GDOUBLE, &elem.h, sizeof(elem.h), flag, "h" }, \ { GIMP_LASTVAL_GDOUBLE, &elem.s, sizeof(elem.s), flag, "s" }, \ { GIMP_LASTVAL_GDOUBLE, &elem.v, sizeof(elem.v), flag, "v" }, \ { GIMP_LASTVAL_GDOUBLE, &elem.a, sizeof(elem.a), flag, "a" }, \ { GIMP_LASTVAL_STRUCT_END, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_GIMPVECTOR2(flag,elem,name) \ { GIMP_LASTVAL_STRUCT_BEGIN, &elem, sizeof(elem), flag, name }, \ { GIMP_LASTVAL_GDOUBLE, &elem.x, sizeof(elem.x), flag, "x" }, \ { GIMP_LASTVAL_GDOUBLE, &elem.y, sizeof(elem.y), flag, "y" }, \ { GIMP_LASTVAL_STRUCT_END, &elem, sizeof(elem), flag, name } #define GIMP_LASTVALDEF_GIMPVECTOR3(flag,elem,name) \ { GIMP_LASTVAL_STRUCT_BEGIN, &elem, sizeof(elem), flag, name }, \ { GIMP_LASTVAL_GDOUBLE, &elem.x, sizeof(elem.x), flag, "x" }, \ { GIMP_LASTVAL_GDOUBLE, &elem.y, sizeof(elem.y), flag, "y" }, \ { GIMP_LASTVAL_GDOUBLE, &elem.z, sizeof(elem.z), flag, "z" }, \ { GIMP_LASTVAL_STRUCT_END, &elem, sizeof(elem), flag, name } /* typenames used in the lastval_description file */ #define GIMP_DDESC_NONE "NONE" #define GIMP_DDESC_ARRAY "ARRAY" #define GIMP_DDESC_STRUCT_BEGIN "STRUCT_BEGIN" #define GIMP_DDESC_STRUCT_END "STRUCT_END" #define GIMP_DDESC_LONG "long" #define GIMP_DDESC_SHORT "short" #define GIMP_DDESC_INT "int" #define GIMP_DDESC_GINT "gint" #define GIMP_DDESC_GINT32 "gint32" #define GIMP_DDESC_CHAR "char" #define GIMP_DDESC_GCHAR "gchar" #define GIMP_DDESC_GUCHAR "guchar" #define GIMP_DDESC_GDOUBLE "gdouble" #define GIMP_DDESC_GFLOAT "gfloat" #define GIMP_DDESC_FLOAT "float" #define GIMP_DDESC_DOUBLE "double" #define GIMP_DDESC_DRAWABLE "drawable" #define GIMP_DDESC_GINTDRAWABLE "gintdrawable" #define GIMP_DDESC_GBOOLEAN "gboolean" #define GIMP_DDESC_ENUM "ENUM" #define GIMP_DDESC_GUINT "guint" #define GIMP_DDESC_GUINT32 "guint32" #define GIMP_DDESC_END "END" #define GIMP_PLUGIN_GAP_COMMON_ITER "plug-in-gap-COMMON-ITERATOR" #define GIMP_ITER_TRUE 1 #define GIMP_ITER_FALSE 0 typedef struct _GimpLastvalDef GimpLastvalDef; struct _GimpLastvalDef { GimpLastvalType type; void *elem_adress; gint32 elem_size; gint32 iter_flag; /* 0 ignore, 1 iterate */ gchar *elem_name; }; typedef struct GimpLastvalDescType { GimpLastvalType lastval_type; gint32 offset; gint32 elem_size; /* only for ARRAY and STRUCT */ gint32 iter_flag; /* 0 ignore, 1 iterate */ gchar elem_name[100]; /* parameter name */ } GimpLastvalDescType; /* ---------------------------------- * gimp_lastval_desc_register * ---------------------------------- * with this procedure a plug-in can register the structure of * it's LAST_VALUES buffer for iteration. * - the registration (call of gimp_lastval_desc_register) * should be done in a plug-in's query procedure. * the structure description is stored in a file in the users gimp_dir. * gimp_lastval_desc_filename returns the name of that file. * * - iteration is useful when the plug-in is called automatic * in RUN_WITH_LAST_VALUES mode on many layers. (Animated filtercall) * A central iterator procedure can read the registered sturcture, * and slightly modify the LAST_VALUES Buffer for each step. * The plug-in must not open parameter DIALOG when called * in RUN_WITH_LAST_VALUES mode. * * - describe at least all the paramters that make sense to modify (iterate) * (you may use GIMP_ITER_FALSE for parameters that should stay constant.) * * - a plug-in can write it's own private iterator. (in that case there is * no need to register the structure, because the private iterator * is always used rather than the common one.) * * - plug-ins that are not able to work on a single drawable or * are not able to run with LAST_VALUES can not be used in animated filtercalls * (even if they register their structructure) * * ---------------------------------- * gimp_lastval_desc_register * ---------------------------------- * read all available structure description(s) from file * (and set in memory for the current gimp session) */ gboolean gimp_lastval_desc_register(const gchar *keyname, void *baseadress, gint32 total_size, gint32 nlastvals, GimpLastvalDef *lastvals); void gimp_lastval_desc_update(void); gchar * gimp_lastval_desc_filename(void); gchar * gimp_lastval_desc_keyname(const gchar *keyname); #endif /* __GIMPLASTVALDESC_H__ */ gimp-gap-2.6.0+dfsg.orig/gap/gap_lock.h0000644000175000017500000000240011212030253017440 0ustar thibautthibaut/* gap_lock.h * 2002.04.21 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins LOCKING * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 1.3.5a; 2002/04/21 hof: created (new gap locking procedures with locktable) */ #ifndef _GAP_LOCK_H #define _GAP_LOCK_H #include "libgimp/gimp.h" gboolean gap_lock_check_for_lock(gint32 image_id, GimpRunMode run_mode); void gap_lock_set_lock(gint32 image_id); void gap_lock_remove_lock(gint32 image_id); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_lock.c0000644000175000017500000001454211212030253017445 0ustar thibautthibaut/* gap_lock.c * 2002.04.21 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins LOCKING * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 1.3.12a; 2003/05/01 hof: use gap-intl.h * 1.3.5a; 2002/04/21 hof: created (new gap locking procedures with locktable) */ #include "config.h" /* SYSTEM (UNIX) includes */ #include #include #include #include #include /* for kill */ #ifdef HAVE_SYS_TIMES_H #include #endif #include #include #include #ifdef HAVE_UNISTD_H #include #endif /* GIMP includes */ #include "gtk/gtk.h" #include "gap-intl.h" #include "libgimp/gimp.h" /* GAP includes */ #include "gap_libgapbase.h" #include "gap_lock.h" extern int gap_debug; /* ==0 ... dont print debug infos */ #define GAP_LOCKTABLE_KEY "plug_in_gap_plugins_LOCKTABLE" typedef struct t_gap_lockdata { gint32 image_id; /* -1 marks an empty record */ gint32 pid; } t_gap_lockdata; /* ============================================================================ * gap_lock_check_for_lock * check if image_id is in the LOCKTABLE and if the locking Process is still * alive. return TRUE if both is TRUE * return FALSE if no valid lock is found. * ============================================================================ */ gboolean gap_lock_check_for_lock(gint32 image_id, GimpRunMode run_mode) { gint32 l_idx; gint32 l_locksize; gint32 l_nlocks; t_gap_lockdata *l_locktab; /* check locktable for locks */ l_locksize = gimp_get_data_size (GAP_LOCKTABLE_KEY); if (l_locksize > 0) { l_nlocks = l_locksize / (sizeof(t_gap_lockdata)); l_locktab = g_new(t_gap_lockdata, l_nlocks); gimp_get_data (GAP_LOCKTABLE_KEY, l_locktab); for(l_idx=0; l_idx < l_nlocks; l_idx++) { if(l_locktab[l_idx].image_id == image_id) { if(gap_base_is_pid_alive(l_locktab[l_idx].pid)) { if(run_mode == GIMP_RUN_INTERACTIVE) { g_message(_("Can't execute more than 1 video function\n" "on the same video frame image at the same time.\n" "Locking image_id:%d\n") , (int)image_id); } printf("GAP plug-in is LOCKED IMAGE_ID:%d PID:%d\n", (int)l_locktab[l_idx].image_id, (int)l_locktab[l_idx].pid); return(TRUE); } break; } } g_free(l_locktab); } return(FALSE); } /* end gap_lock_check_for_lock */ /* ============================================================================ * gap_lock_set_lock * add a lock for image_id and current Process to the LOCKTABLE. * (overwrite empty record or add a new record if no empty one is found) * ============================================================================ */ void gap_lock_set_lock(gint32 image_id) { gint32 l_idx; gint32 l_locksize; gint32 l_nlocks; gint32 l_nlocks_old; t_gap_lockdata *l_locktab; /* check locktable for empty records */ l_locksize = gimp_get_data_size (GAP_LOCKTABLE_KEY); if (l_locksize > 0) { l_nlocks_old = l_locksize / (sizeof(t_gap_lockdata)); /* l_nlocks + one extra record in case there is no empty record in the table * for overwrite */ l_nlocks = l_nlocks_old + 1; l_locktab = g_new(t_gap_lockdata, l_nlocks); gimp_get_data (GAP_LOCKTABLE_KEY, l_locktab); for(l_idx=0; l_idx < l_nlocks_old; l_idx++) { if((l_locktab[l_idx].image_id < 0) || (!gap_base_is_pid_alive(l_locktab[l_idx].pid))) { l_nlocks--; /* empty record found, dont need the extra record */ break; } } } else { /* create a new locktab with 1 entry */ l_nlocks = 1; l_idx = 0; l_locktab = g_new(t_gap_lockdata, l_nlocks); } l_locktab[l_idx].image_id = image_id; l_locktab[l_idx].pid = gap_base_getpid(); gimp_set_data(GAP_LOCKTABLE_KEY, l_locktab, l_nlocks * sizeof(t_gap_lockdata)); if (gap_debug) { for(l_idx=0; l_idx < l_nlocks; l_idx++) { printf("gap_lock_set_lock: LOCKTAB[%d] IMAGE_ID:%d PID:%d\n", (int)l_idx, (int)l_locktab[l_idx].image_id, (int)l_locktab[l_idx].pid ); } } g_free(l_locktab); } /* end gap_lock_set_lock */ /* ============================================================================ * gap_lock_remove_lock * remove lock for image_id from the LOCKTABLE. * (by setting the corresponding record empty) * ============================================================================ */ void gap_lock_remove_lock(gint32 image_id) { gint32 l_idx; gint32 l_locksize; gint32 l_nlocks; t_gap_lockdata *l_locktab; /* check locktable for empty records */ l_locksize = gimp_get_data_size (GAP_LOCKTABLE_KEY); if (l_locksize > 0) { l_nlocks = l_locksize / (sizeof(t_gap_lockdata)); l_locktab = g_new(t_gap_lockdata, l_nlocks); gimp_get_data (GAP_LOCKTABLE_KEY, l_locktab); for(l_idx=0; l_idx < l_nlocks; l_idx++) { if(l_locktab[l_idx].image_id == image_id) { /* mark this record as empty (image_id = -1) */ l_locktab[l_idx].image_id = -1; l_locktab[l_idx].pid = 0; gimp_set_data(GAP_LOCKTABLE_KEY, l_locktab, l_nlocks * sizeof(t_gap_lockdata)); break; } } g_free(l_locktab); } } /* end gap_lock_remove_lock */ gimp-gap-2.6.0+dfsg.orig/gap/gap_filter_iterators.c0000644000175000017500000023142111212030253022073 0ustar thibautthibaut/* gap_filter_iterators.c * * 1998.01.29 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * - Implementation of c common Iterator Procedure * for those Plugins * - that can operate on a single drawable, * - and have paramters for varying. (that are documented in the LASTVALUES Decription file) * * If New plugins were added to the gimp, or existing ones were updated, * the Authors should supply original _Iterator Procedures * to modify the settings for the plugin when called step by step * on animated multilayer Images. * Another simpler way is to register the structure description of the LAST_VALUES Buffer. * (so that the common iterator can be used) * * * Common things to all Iteratur Plugins: * Interface: run_mode # is always GIMP_RUN_NONINTERACTIVE * total_steps # total number of handled layers (drawables) * current_step # current layer (beginning wit 0) * has type gdouble for later extensions * to non-linear iterations. * the iterator always computes linear inbetween steps, * but the (central) caller may fake step 1.2345 in the future * for logaritmic iterations or userdefined curves. * * Naming Convention: * Iterators must have the name of the plugin (PDB proc_name), whose values * are iterated, with Suffix * "_Iterator" * "_Iterator_ALT" (if not provided within the original Plugin's sources) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* Change Log: * gimp 1.3.26a; 2004/02/07 hof: added p_delta_CML_PARAM, removed gfig * gimp 1.3.20b; 2003/09/20 hof: include gap_dbbrowser_utils.h, datatype support for guint, guint32 * replaced t_GckVector3 and t_GckColor by GimpVector3 and GimpRGB * gimp 1.3.17a; 2003/07/29 hof: fixed signed/unsigned comparison warnings * gimp 1.3.12a; 2003/05/02 hof: merge into CVS-gimp-gap project, added iter_ALT Procedures again * gimp 1.3.8a; 2002/09/21 hof: gap_lastvaldesc * gimp 1.3.5a; 2002/04/14 hof: removed Stuctured Iterators (Material, Light ..) * gimp 1.3.4b; 2002/03/24 hof: support COMMON_ITERATOR, removed iter_ALT Procedures * version gimp 1.1.17b 2000.02.22 hof: - removed limit PLUGIN_DATA_SIZE * 1999.11.16 hof: added p_delta_gintdrawable * 1999.06.21 hof: removed Colorify iterator * 1999.03.14 hof: added iterators for gimp 1.1.3 prerelease * iterator code reorganized in _iter_ALT.inc Files * 1998.06.12 hof: added p_delta_drawable (Iterate layers in the layerstack) * this enables to apply an animated bumpmap. * 1998.01.29 hof: 1st release */ #include "config.h" /* SYTEM (UNIX) includes */ #include #include #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" /* GAP includes */ #include "gap_lastvaldesc.h" #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; static gchar *g_plugin_data_to = NULL; extern int gap_debug; /* Funtion type for use in the common iterator */ typedef void (*GapDeltaFunctionType) (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step); typedef struct JmpTableEntryType { GapDeltaFunctionType func_ptr; gint32 item_size; } JmpTableEntryType; typedef struct IterStackItemType { GimpLastvalType lastval_type; /* only ARRAY and STRUCT are pushed on the stack */ gint32 elem_size; /* only for ARRAY and STRUCT */ gint32 arr_count; gint idx; gint32 iter_flag; }IterStackItemType; typedef struct IterStackType { IterStackItemType *stack_arr; /* only ARRAY and STRUCT are pushed on the stack */ gint32 stack_max_elem; /* only for ARRAY and STRUCT */ gint32 stack_top; /* current stack top index (-1 for empty stack */ gint idx; }IterStackType; static JmpTableEntryType jmp_table[GIMP_LASTVAL_END]; static gchar * p_alloc_plugin_data(char *key) { int l_len; gchar *l_plugin_data; l_len = gimp_get_data_size (key); if(l_len < 1) { fprintf(stderr, "ERROR: no stored data found for Key %s\n", key); return NULL; } l_plugin_data = g_malloc0(l_len+1); if(gap_debug) printf("DEBUG Key:%s plugin_data length %d\n", key, (int)l_len); return (l_plugin_data); } typedef struct { guchar color[3]; } t_color; typedef struct { gint color[3]; } t_gint_color; typedef struct t_CML_PARAM { gint function; gint composition; gint arrange; gint cyclic_range; gdouble mod_rate; /* diff / old-value */ gdouble env_sensitivity; /* self-diff : env-diff */ gint diffusion_dist; gdouble ch_sensitivity; gint range_num; gdouble power; gdouble parameter_k; gdouble range_l; gdouble range_h; gdouble mutation_rate; 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 * (were called from the generated procedures) * ---------------------------------------------------------------------- */ static void p_delta_long(long *val, long val_from, long val_to, gint32 total_steps, gdouble current_step) { double delta; if(total_steps < 1) return; delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step); *val = val_from + delta; if(gap_debug) printf("DEBUG: p_delta_long from: %ld to: %ld curr: %ld delta: %f\n", val_from, val_to, *val, delta); } static void p_delta_short(short *val, short val_from, short val_to, gint32 total_steps, gdouble current_step) { double delta; if(total_steps < 1) return; delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step); *val = val_from + delta; } static void p_delta_int(int *val, int val_from, int val_to, gint32 total_steps, gdouble current_step) { double delta; if(total_steps < 1) return; delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step); *val = val_from + delta; } static void p_delta_gint(gint *val, gint val_from, gint val_to, gint32 total_steps, gdouble current_step) { double delta; if(total_steps < 1) return; delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step); *val = val_from + delta; } static void p_delta_guint(guint *val, guint val_from, guint val_to, gint32 total_steps, gdouble current_step) { double delta; if(total_steps < 1) return; delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step); *val = val_from + delta; } static void p_delta_gint32(gint32 *val, gint32 val_from, gint32 val_to, gint32 total_steps, gdouble current_step) { double delta; if(total_steps < 1) return; delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step); *val = val_from + delta; } static void p_delta_guint32(guint32 *val, guint32 val_from, guint32 val_to, gint32 total_steps, gdouble current_step) { double delta; if(total_steps < 1) return; delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step); *val = val_from + delta; } static void p_delta_char(char *val, char val_from, char val_to, gint32 total_steps, gdouble current_step) { double delta; if(total_steps < 1) return; delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step); *val = val_from + delta; } static void p_delta_guchar(guchar *val, char val_from, char val_to, gint32 total_steps, gdouble current_step) { double delta; if(total_steps < 1) return; delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step); *val = val_from + delta; } static void p_delta_gdouble(double *val, double val_from, double val_to, gint32 total_steps, gdouble current_step) { double delta; if(total_steps < 1) return; delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step); *val = val_from + delta; if(gap_debug) printf("DEBUG: p_delta_gdouble total: %d from: %f to: %f curr: %f delta: %f\n", (int)total_steps, val_from, val_to, *val, delta); } static void p_delta_gfloat(gfloat *val, gfloat val_from, gfloat val_to, gint32 total_steps, gdouble current_step) { double delta; if(total_steps < 1) return; delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step); *val = val_from + delta; if(gap_debug) printf("DEBUG: p_delta_gfloat total: %d from: %f to: %f curr: %f delta: %f\n", (int)total_steps, val_from, val_to, *val, delta); } static void p_delta_float(float *val, float val_from, float val_to, gint32 total_steps, gdouble current_step) { double delta; if(total_steps < 1) return; delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step); *val = val_from + delta; if(gap_debug) printf("DEBUG: p_delta_gdouble total: %d from: %f to: %f curr: %f delta: %f\n", (int)total_steps, val_from, val_to, *val, delta); } static void p_delta_color(t_color *val, t_color *val_from, t_color *val_to, gint32 total_steps, gdouble current_step) { double delta; guint l_idx; if(total_steps < 1) return; for(l_idx = 0; l_idx < 3; l_idx++) { delta = ((double)(val_to->color[l_idx] - val_from->color[l_idx]) / (double)total_steps) * ((double)total_steps - current_step); val->color[l_idx] = val_from->color[l_idx] + delta; if(gap_debug) printf("DEBUG: p_delta_color[%d] total: %d from: %d to: %d curr: %d delta: %f current_step: %f\n", (int)l_idx, (int)total_steps, (int)val_from->color[l_idx], (int)val_to->color[l_idx], (int)val->color[l_idx], delta, current_step); } } static void p_delta_gint_color(t_gint_color *val, t_gint_color *val_from, t_gint_color *val_to, gint32 total_steps, gdouble current_step) { double delta; guint l_idx; if(total_steps < 1) return; for(l_idx = 0; l_idx < 3; l_idx++) { delta = ((double)(val_to->color[l_idx] - val_from->color[l_idx]) / (double)total_steps) * ((double)total_steps - current_step); val->color[l_idx] = val_from->color[l_idx] + delta; } } /* --------------------------- * 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_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; l_layers_list = gimp_image_get_layers(images[l_idi], &l_nlayers); if(l_layers_list != NULL) { 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--; } if(images) g_free(images); if(l_found) { return TRUE; /* OK */ } 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_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; } if(p_drawable_is_alive(val_from) != TRUE) { return; } if(p_drawable_is_alive(val_to) != TRUE) { 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_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) { 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 */ /* ------------------------------------- * 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) { 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*/ ); } 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) { gint32 l_val, l_from, l_to; l_val = *val; l_from = val_from; l_to = val_to; p_delta_drawable(&l_val, l_from, l_to, total_steps, current_step); *val = l_val; } /* ----------------------------- * stuff for the common iterator * ----------------------------- */ /* static void p_delta_long(long *val, long val_from, long val_to, gint32 total_steps, gdouble current_step) static void p_delta_short(short *val, short val_from, short val_to, gint32 total_steps, gdouble current_step) static void p_delta_int(int *val, int val_from, int val_to, gint32 total_steps, gdouble current_step) static void p_delta_gint(gint *val, gint val_from, gint val_to, gint32 total_steps, gdouble current_step) static void p_delta_gint32(gint32 *val, gint32 val_from, gint32 val_to, gint32 total_steps, gdouble current_step) static void p_delta_char(char *val, char val_from, char val_to, gint32 total_steps, gdouble current_step) static void p_delta_guchar(guchar *val, char val_from, char val_to, gint32 total_steps, gdouble current_step) static void p_delta_gdouble(double *val, double val_from, double val_to, gint32 total_steps, gdouble current_step) static void p_delta_gfloat(gfloat *val, gfloat val_from, gfloat val_to, gint32 total_steps, gdouble current_step) static void p_delta_float(float *val, float val_from, float val_to, gint32 total_steps, gdouble current_step) static void p_delta_drawable(gint32 *val, gint32 val_from, gint32 val_to, gint32 total_steps, gdouble current_step) static void p_delta_gintdrawable(gint *val, gint val_from, gint val_to, gint32 total_steps, gdouble current_step) */ /* wrapper calls with pointers to value transform * (for those delta procedures that do not already use pointers for val_from and val-to parameters) */ static void gp_delta_long (long *val, long *val_from, long *val_to, gint32 total_steps, gdouble current_step) { p_delta_long(val, *val_from, *val_to, total_steps, current_step); } static void gp_delta_short (short *val, short *val_from, short *val_to, gint32 total_steps, gdouble current_step) { p_delta_short(val, *val_from, *val_to, total_steps, current_step); } static void gp_delta_int (int *val, int *val_from, int *val_to, gint32 total_steps, gdouble current_step) { p_delta_int(val, *val_from, *val_to, total_steps, current_step); } static void gp_delta_gint (gint *val, gint *val_from, gint *val_to, gint32 total_steps, gdouble current_step) { p_delta_gint(val, *val_from, *val_to, total_steps, current_step); } static void gp_delta_guint (guint *val, guint *val_from, guint *val_to, gint32 total_steps, gdouble current_step) { p_delta_guint(val, *val_from, *val_to, total_steps, current_step); } static void gp_delta_gint32 (gint32 *val, gint32 *val_from, gint32 *val_to, gint32 total_steps, gdouble current_step) { p_delta_gint32(val, *val_from, *val_to, total_steps, current_step); } static void gp_delta_guint32 (guint32 *val, guint32 *val_from, guint32 *val_to, gint32 total_steps, gdouble current_step) { p_delta_guint32(val, *val_from, *val_to, total_steps, current_step); } static void gp_delta_char (char *val, char *val_from, char *val_to, gint32 total_steps, gdouble current_step) { p_delta_char(val, *val_from, *val_to, total_steps, current_step); } static void gp_delta_guchar (guchar *val, char *val_from, char *val_to, gint32 total_steps, gdouble current_step) { p_delta_guchar(val, *val_from, *val_to, total_steps, current_step); } static void gp_delta_gdouble (double *val, double *val_from, double *val_to, gint32 total_steps, gdouble current_step) { p_delta_gdouble(val, *val_from, *val_to, total_steps, current_step); } static void gp_delta_gfloat (gfloat *val, gfloat *val_from, gfloat *val_to, gint32 total_steps, gdouble current_step) { p_delta_gfloat(val, *val_from, *val_to, total_steps, current_step); } static void gp_delta_float (float *val, float *val_from, float *val_to, gint32 total_steps, gdouble current_step) { p_delta_float(val, *val_from, *val_to, total_steps, current_step); } static void gp_delta_drawable (gint32 *val, gint32 *val_from, gint32 *val_to, gint32 total_steps, gdouble current_step) { p_delta_drawable(val, *val_from, *val_to, total_steps, current_step); } static void gp_delta_gintdrawable (gint *val, gint *val_from, gint *val_to, gint32 total_steps, gdouble current_step) { p_delta_gintdrawable(val, *val_from, *val_to, total_steps, current_step); } /* wrapper calls of type specific procedure */ void gap_delta_none (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { return; /* this is just a dummy delta procedure for non-taerable members in a LAST_VALUES buffer */ } void gap_delta_long (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { gp_delta_long (val, val_from, val_to, total_steps, current_step); } void gap_delta_short (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { gp_delta_short (val, val_from, val_to, total_steps, current_step); } void gap_delta_int (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { gp_delta_int (val, val_from, val_to, total_steps, current_step); } void gap_delta_gint (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { gp_delta_gint (val, val_from, val_to, total_steps, current_step); } void gap_delta_guint (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { gp_delta_guint (val, val_from, val_to, total_steps, current_step); } void gap_delta_gint32 (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { gp_delta_gint32 (val, val_from, val_to, total_steps, current_step); } void gap_delta_guint32 (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { gp_delta_guint32 (val, val_from, val_to, total_steps, current_step); } void gap_delta_char (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { gp_delta_char (val, val_from, val_to, total_steps, current_step); } void gap_delta_guchar (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { gp_delta_guchar (val, val_from, val_to, total_steps, current_step); } void gap_delta_gdouble (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { gp_delta_gdouble (val, val_from, val_to, total_steps, current_step); } void gap_delta_gfloat (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { gp_delta_gfloat (val, val_from, val_to, total_steps, current_step); } void gap_delta_float (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { gp_delta_float (val, val_from, val_to, total_steps, current_step); } void gap_delta_drawable (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { gp_delta_drawable (val, val_from, val_to, total_steps, current_step); } void gap_delta_gintdrawable (void *val, void *val_from, void *val_to, gint32 total_steps, gdouble current_step) { gp_delta_gintdrawable (val, val_from, val_to, total_steps, current_step); } void p_init_iter_jump_table(void) { static gboolean jmp_table_initialized = FALSE; if(jmp_table_initialized != TRUE) { /* fuction pointers for typespecific delta procedures */ jmp_table[GIMP_LASTVAL_NONE].func_ptr = gap_delta_none; jmp_table[GIMP_LASTVAL_ARRAY].func_ptr = gap_delta_none; jmp_table[GIMP_LASTVAL_STRUCT_BEGIN].func_ptr = gap_delta_none; jmp_table[GIMP_LASTVAL_STRUCT_END].func_ptr = gap_delta_none; jmp_table[GIMP_LASTVAL_LONG].func_ptr = gap_delta_long; jmp_table[GIMP_LASTVAL_SHORT].func_ptr = gap_delta_short; jmp_table[GIMP_LASTVAL_INT].func_ptr = gap_delta_int; jmp_table[GIMP_LASTVAL_GINT].func_ptr = gap_delta_gint; jmp_table[GIMP_LASTVAL_GINT32].func_ptr = gap_delta_gint32; jmp_table[GIMP_LASTVAL_CHAR].func_ptr = gap_delta_char; jmp_table[GIMP_LASTVAL_GCHAR].func_ptr = gap_delta_char; /* gchar uses same as char */ jmp_table[GIMP_LASTVAL_GUCHAR].func_ptr = gap_delta_guchar; jmp_table[GIMP_LASTVAL_GDOUBLE].func_ptr = gap_delta_gdouble; jmp_table[GIMP_LASTVAL_GFLOAT].func_ptr = gap_delta_gfloat; jmp_table[GIMP_LASTVAL_DOUBLE].func_ptr = gap_delta_gdouble; /* double same as gdouble */ jmp_table[GIMP_LASTVAL_FLOAT].func_ptr = gap_delta_float; jmp_table[GIMP_LASTVAL_DRAWABLE].func_ptr = gap_delta_drawable; jmp_table[GIMP_LASTVAL_GINTDRAWABLE].func_ptr = gap_delta_gintdrawable; jmp_table[GIMP_LASTVAL_GBOOLEAN].func_ptr = gap_delta_none; jmp_table[GIMP_LASTVAL_ENUM].func_ptr = gap_delta_none; jmp_table[GIMP_LASTVAL_GUINT].func_ptr = gap_delta_guint; jmp_table[GIMP_LASTVAL_GUINT32].func_ptr = gap_delta_guint32; /* size of one element for the supported basetypes and predefined structs */ jmp_table[GIMP_LASTVAL_NONE].item_size = 0; jmp_table[GIMP_LASTVAL_ARRAY].item_size = 0; jmp_table[GIMP_LASTVAL_STRUCT_BEGIN].item_size = 0; jmp_table[GIMP_LASTVAL_STRUCT_END].item_size = 0; jmp_table[GIMP_LASTVAL_LONG].item_size = sizeof(long); jmp_table[GIMP_LASTVAL_SHORT].item_size = sizeof(short); jmp_table[GIMP_LASTVAL_INT].item_size = sizeof(int); jmp_table[GIMP_LASTVAL_GINT].item_size = sizeof(gint); jmp_table[GIMP_LASTVAL_CHAR].item_size = sizeof(char); jmp_table[GIMP_LASTVAL_GCHAR].item_size = sizeof(gchar); jmp_table[GIMP_LASTVAL_GUCHAR].item_size = sizeof(guchar); jmp_table[GIMP_LASTVAL_GDOUBLE].item_size = sizeof(gdouble); jmp_table[GIMP_LASTVAL_GFLOAT].item_size = sizeof(gfloat); jmp_table[GIMP_LASTVAL_FLOAT].item_size = sizeof(float); jmp_table[GIMP_LASTVAL_DOUBLE].item_size = sizeof(double); jmp_table[GIMP_LASTVAL_DRAWABLE].item_size = sizeof(gint32); jmp_table[GIMP_LASTVAL_GINTDRAWABLE].item_size = sizeof(gint); jmp_table[GIMP_LASTVAL_GBOOLEAN].item_size = sizeof(gboolean); jmp_table[GIMP_LASTVAL_ENUM].item_size = sizeof(gint); jmp_table[GIMP_LASTVAL_GUINT].item_size = sizeof(guint); jmp_table[GIMP_LASTVAL_GUINT32].item_size = sizeof(guint32); jmp_table_initialized = TRUE; } } static gint32 p_stack_offsetsum(IterStackType *iter_stack) { gint32 l_arr_fact; gint32 l_offset_sum; gint32 l_idx; l_arr_fact = 0; l_offset_sum = 0; for(l_idx=0; l_idx <= iter_stack->stack_top; l_idx++) { if(iter_stack->stack_arr[l_idx].lastval_type == GIMP_LASTVAL_ARRAY) { if(l_arr_fact == 0) { l_arr_fact = iter_stack->stack_arr[l_idx].arr_count; } else { l_arr_fact = l_arr_fact * iter_stack->stack_arr[l_idx].arr_count; } } else { /* GIMP_LASTVAL_STRUCT_BEGIN */ l_offset_sum += (l_arr_fact * iter_stack->stack_arr[l_idx].elem_size); l_arr_fact = 0; } } return(l_offset_sum); } static void p_debug_stackprint(IterStackType *iter_stack) { gint l_idx; printf(" p_debug_stackprint stack_top: %d max_elem: %d\n", (int)iter_stack->stack_top, (int)iter_stack->stack_max_elem); for(l_idx=0; l_idx <= iter_stack->stack_top; l_idx++) { printf(" stack[%02d] lastval_type: %d elem_size: %d arr_count: %d idx: %d\n" ,(int)l_idx ,(int)iter_stack->stack_arr[l_idx].lastval_type ,(int)iter_stack->stack_arr[l_idx].elem_size ,(int)iter_stack->stack_arr[l_idx].arr_count ,(int)iter_stack->stack_arr[l_idx].idx ); } } static void p_push_iter(IterStackType *iter_stack, IterStackItemType *stack_item) { iter_stack->stack_top++; if(iter_stack->stack_top < iter_stack->stack_max_elem) { iter_stack->stack_arr[iter_stack->stack_top].lastval_type = stack_item->lastval_type; iter_stack->stack_arr[iter_stack->stack_top].elem_size = stack_item->elem_size; iter_stack->stack_arr[iter_stack->stack_top].arr_count = stack_item->arr_count; iter_stack->stack_arr[iter_stack->stack_top].idx = stack_item->idx; } else { printf("p_push_iter: STACK overflow\n"); } if(1==0 /*gap_debug*/ ) { printf("p_push_iter START\n"); p_debug_stackprint(iter_stack); } } static void p_pop_iter(IterStackType *iter_stack, IterStackItemType *stack_item) { if(1==0 /*gap_debug*/ ) { printf("p_pop_iter START\n"); p_debug_stackprint(iter_stack); } if(iter_stack->stack_top >= 0) { stack_item->lastval_type = iter_stack->stack_arr[iter_stack->stack_top].lastval_type; stack_item->elem_size = iter_stack->stack_arr[iter_stack->stack_top].elem_size; stack_item->arr_count = iter_stack->stack_arr[iter_stack->stack_top].arr_count; stack_item->idx = iter_stack->stack_arr[iter_stack->stack_top].idx; iter_stack->stack_top--; } else { printf("p_pop_iter: STACK underrun\n"); } } void p_debug_print_iter_desc (GimpLastvalDescType *lastval_desc_arr, gint32 arg_cnt) { gint32 l_idx; printf ("p_debug_print_iter_desc START\n"); for(l_idx = 0; l_idx < arg_cnt; l_idx++) { printf("[%03d] lastval_type: %d, offset: %d, elem_size: %d\n" , (int)l_idx , (int)lastval_desc_arr[l_idx].lastval_type , (int)lastval_desc_arr[l_idx].offset , (int)lastval_desc_arr[l_idx].elem_size ); } printf ("p_debug_print_iter_desc END\n\n"); } /* ---------------------------------------------------------------------- * run common iterator * PDB: registered as "plug_in_gap_COMMON_ITERATOR" * ---------------------------------------------------------------------- */ gint gap_common_iterator(const char *c_keyname, GimpRunMode run_mode, gint32 total_steps, gdouble current_step, gint32 len_struct) { gchar *keyname; gchar *key_description; gchar *key_from; gchar *key_to; int buf_size; int desc_size; keyname = g_strdup(c_keyname); if(gap_debug) printf("\ngap_common_iterator START: keyname: %s total_steps: %d, curent_step: %f\n", keyname, (int)total_steps, (float)current_step ); key_description = gimp_lastval_desc_keyname (keyname); key_from = g_strdup_printf("%s%s", keyname, GAP_ITER_FROM_SUFFIX); key_to = g_strdup_printf("%s%s", keyname, GAP_ITER_TO_SUFFIX); buf_size = gimp_get_data_size(keyname); desc_size = gimp_get_data_size(key_description); if (buf_size > 0 && desc_size > 0) { GimpLastvalDescType *lastval_desc_arr; gint arg_cnt; gint l_idx; gint l_idx_next; void *buffer; void *buffer_from; void *buffer_to; IterStackType *stack_iter; IterStackItemType l_stack_item; IterStackItemType l_stack_2_item; lastval_desc_arr = g_malloc(desc_size); arg_cnt = desc_size / sizeof(GimpLastvalDescType); buffer = g_malloc(buf_size); buffer_from = g_malloc(buf_size); buffer_to = g_malloc(buf_size); gimp_get_data(key_description, lastval_desc_arr); gimp_get_data(keyname, buffer); gimp_get_data(key_from, buffer_from); gimp_get_data(key_to, buffer_to); if(gap_debug) { p_debug_print_iter_desc(lastval_desc_arr, arg_cnt); } if ((lastval_desc_arr[0].elem_size != buf_size) || (lastval_desc_arr[0].elem_size != len_struct)) { printf("ERROR: %s stored Data missmatch in size %d != %d\n" , keyname , (int)buf_size , (int)lastval_desc_arr[0].elem_size ); return -1 ; /* NOT OK */ } p_init_iter_jump_table(); /* init IterStack */ stack_iter = g_new(IterStackType, 1); stack_iter->stack_arr = g_new(IterStackItemType, arg_cnt); stack_iter->stack_top = -1; /* stack is empty */ stack_iter->stack_max_elem = arg_cnt; /* stack is empty */ l_idx=0; while(l_idx < arg_cnt) { void *buf_ptr; void *buf_ptr_from; void *buf_ptr_to; gint l_iter_idx; gint32 l_iter_flag; gint32 l_offset; gint32 l_ntimes_arraysize; if(lastval_desc_arr[l_idx].lastval_type == GIMP_LASTVAL_END) { break; } l_iter_idx = (int)lastval_desc_arr[l_idx].lastval_type; l_iter_flag = lastval_desc_arr[l_idx].iter_flag; l_idx_next = l_idx +1; l_stack_item.lastval_type = lastval_desc_arr[l_idx].lastval_type; l_stack_item.iter_flag = lastval_desc_arr[l_idx].iter_flag; l_stack_item.elem_size = lastval_desc_arr[l_idx].elem_size; l_stack_item.arr_count = 0; l_stack_item.idx = l_idx_next; switch(lastval_desc_arr[l_idx].lastval_type) { case GIMP_LASTVAL_ARRAY: p_push_iter(stack_iter, &l_stack_item); break; case GIMP_LASTVAL_STRUCT_BEGIN: p_push_iter(stack_iter, &l_stack_item); break; case GIMP_LASTVAL_STRUCT_END: l_stack_2_item.lastval_type = GIMP_LASTVAL_NONE; if(stack_iter->stack_top >= 0) { /* 1.st pop should always retrieve the STUCTURE BEGIN */ p_pop_iter(stack_iter, &l_stack_2_item); } if(l_stack_2_item.lastval_type != GIMP_LASTVAL_STRUCT_BEGIN) { printf("stack out of balance, STRUCTURE END without begin\n"); return -1; /* ERROR */ } if (stack_iter->stack_top >= 0) { /* 2.nd pop */ p_pop_iter(stack_iter, &l_stack_item); if(l_stack_item.lastval_type == GIMP_LASTVAL_ARRAY) { l_stack_item.elem_size--; if(l_stack_item.elem_size > 0) { p_push_iter(stack_iter, &l_stack_item); p_push_iter(stack_iter, &l_stack_2_item); /* go back to stored index (1st elem of the structure) */ l_idx_next = l_stack_2_item.idx; } } else { p_push_iter(stack_iter, &l_stack_item); } } break; default: l_ntimes_arraysize = 1; while(1==1) { if (stack_iter->stack_top >= 0) { p_pop_iter(stack_iter, &l_stack_item); if(l_stack_item.lastval_type == GIMP_LASTVAL_ARRAY) { l_ntimes_arraysize = l_ntimes_arraysize * l_stack_item.elem_size; } else { p_push_iter(stack_iter, &l_stack_item); break; } } } l_offset = p_stack_offsetsum(stack_iter); /* offest for current array position */ l_offset += lastval_desc_arr[l_idx].offset; /* local offest */ buf_ptr = buffer + l_offset; buf_ptr_from = buffer_from + l_offset; buf_ptr_to = buffer_to + l_offset; if(gap_debug) printf("Using JumpTable jmp index:%d iter_flag:%d\n", (int)l_iter_idx, (int)l_iter_flag); if (l_iter_idx >= 0 && l_iter_idx < (gint)GIMP_LASTVAL_END && (l_iter_flag & GIMP_ITER_TRUE) == GIMP_ITER_TRUE ) { gint32 l_cnt; for(l_cnt=0; l_cnt < l_ntimes_arraysize; l_cnt++) { /* call type specific iterator delta procedure using jmp_table indexed by lastval_type */ jmp_table[l_iter_idx].func_ptr(buf_ptr, buf_ptr_from, buf_ptr_to, total_steps, current_step); buf_ptr += jmp_table[l_iter_idx].item_size; buf_ptr_from += jmp_table[l_iter_idx].item_size; buf_ptr_to += jmp_table[l_iter_idx].item_size; } } break; } l_idx = l_idx_next; } gimp_set_data(keyname, buffer, buf_size); g_free(stack_iter->stack_arr); g_free(stack_iter); } else { printf("ERROR: %s No stored Data/Description found. Datasize: %d, Descriptionsize: %d\n", keyname, (int)buf_size, (int)desc_size ); return -1 ; /* NOT OK */ } g_free(keyname); return 0; /* OK */ } /* end gap_common_iterator */ /* ---------------------------------------------------------------------- * iterator UTILITIES for GimpRGB, GimpVector3, Material and Light Sewttings * ---------------------------------------------------------------------- */ typedef enum { POINT_LIGHT, DIRECTIONAL_LIGHT, SPOT_LIGHT, NO_LIGHT } t_LightType; typedef enum { IMAGE_BUMP, WAVES_BUMP } t_MapType; typedef struct { gdouble ambient_int; gdouble diffuse_int; gdouble diffuse_ref; gdouble specular_ref; gdouble highlight; GimpRGB color; } t_MaterialSettings; typedef struct { t_LightType type; GimpVector3 position; GimpVector3 direction; GimpRGB color; gdouble intensity; } t_LightSettings; static void p_delta_GimpRGB(GimpRGB *val, GimpRGB *val_from, GimpRGB *val_to, gint32 total_steps, gdouble current_step) { double delta; if(total_steps < 1) return; delta = ((double)(val_to->r - val_from->r) / (double)total_steps) * ((double)total_steps - current_step); val->r = val_from->r + delta; delta = ((double)(val_to->g - val_from->g) / (double)total_steps) * ((double)total_steps - current_step); val->g = val_from->g + delta; delta = ((double)(val_to->b - val_from->b) / (double)total_steps) * ((double)total_steps - current_step); val->b = val_from->b + delta; delta = ((double)(val_to->a - val_from->a) / (double)total_steps) * ((double)total_steps - current_step); val->a = val_from->a + delta; } static void p_delta_GimpVector3(GimpVector3 *val, GimpVector3 *val_from, GimpVector3 *val_to, gint32 total_steps, gdouble current_step) { double delta; if(total_steps < 1) return; delta = ((double)(val_to->x - val_from->x) / (double)total_steps) * ((double)total_steps - current_step); val->x = val_from->x + delta; delta = ((double)(val_to->y - val_from->y) / (double)total_steps) * ((double)total_steps - current_step); val->y = val_from->y + delta; delta = ((double)(val_to->z - val_from->z) / (double)total_steps) * ((double)total_steps - current_step); val->z = val_from->z + delta; } static void p_delta_MaterialSettings(t_MaterialSettings *val, t_MaterialSettings *val_from, t_MaterialSettings *val_to, gint32 total_steps, gdouble current_step) { p_delta_gdouble(&val->ambient_int, val_from->ambient_int, val_to->ambient_int, total_steps, current_step); p_delta_gdouble(&val->diffuse_int, val_from->diffuse_int, val_to->diffuse_int, total_steps, current_step); p_delta_gdouble(&val->diffuse_ref, val_from->diffuse_ref, val_to->diffuse_ref, total_steps, current_step); p_delta_gdouble(&val->specular_ref, val_from->specular_ref, val_to->specular_ref, total_steps, current_step); p_delta_gdouble(&val->highlight, val_from->highlight, val_to->highlight, total_steps, current_step); p_delta_GimpRGB(&val->color, &val_from->color, &val_to->color, total_steps, current_step); } static void p_delta_LightSettings(t_LightSettings *val, t_LightSettings *val_from, t_LightSettings *val_to, gint32 total_steps, gdouble current_step) { /* no delta is done for LightType */ p_delta_GimpVector3(&val->position, &val_from->position, &val_to->position, total_steps, current_step); p_delta_GimpVector3(&val->direction, &val_from->direction, &val_to->direction, total_steps, current_step); p_delta_GimpRGB(&val->color, &val_from->color, &val_to->color, total_steps, current_step); p_delta_gdouble(&val->intensity, val_from->intensity, val_to->intensity, total_steps, current_step); } /* for Lighting */ /* since gimp-2.2 MapObject and Lighting Types drifted apart * therefore we need 2 sets of Material and Light Setting Types */ typedef struct { gdouble ambient_int; gdouble diffuse_int; gdouble diffuse_ref; gdouble specular_ref; gdouble highlight; gboolean metallic; GimpRGB color; } t_LightingMaterialSettings; typedef struct { t_LightType type; GimpVector3 position; GimpVector3 direction; GimpRGB color; gdouble intensity; gboolean active; } t_LightingLightSettings; static void p_delta_LightingMaterialSettings(t_LightingMaterialSettings *val, t_LightingMaterialSettings *val_from, t_LightingMaterialSettings *val_to, gint32 total_steps, gdouble current_step) { p_delta_gdouble(&val->ambient_int, val_from->ambient_int, val_to->ambient_int, total_steps, current_step); p_delta_gdouble(&val->diffuse_int, val_from->diffuse_int, val_to->diffuse_int, total_steps, current_step); p_delta_gdouble(&val->diffuse_ref, val_from->diffuse_ref, val_to->diffuse_ref, total_steps, current_step); p_delta_gdouble(&val->specular_ref, val_from->specular_ref, val_to->specular_ref, total_steps, current_step); p_delta_gdouble(&val->highlight, val_from->highlight, val_to->highlight, total_steps, current_step); p_delta_GimpRGB(&val->color, &val_from->color, &val_to->color, total_steps, current_step); } static void p_delta_LightingLightSettings(t_LightingLightSettings *val, t_LightingLightSettings *val_from, t_LightingLightSettings *val_to, gint32 total_steps, gdouble current_step) { /* no delta is done for LightType */ p_delta_GimpVector3(&val->position, &val_from->position, &val_to->position, total_steps, current_step); p_delta_GimpVector3(&val->direction, &val_from->direction, &val_to->direction, total_steps, current_step); p_delta_GimpRGB(&val->color, &val_from->color, &val_to->color, total_steps, current_step); p_delta_gdouble(&val->intensity, val_from->intensity, val_to->intensity, total_steps, current_step); } /* for p_plug_in_cml_explorer_iter_ALT */ static void p_delta_CML_PARAM(t_CML_PARAM *val, t_CML_PARAM *val_from, t_CML_PARAM *val_to, gint32 total_steps, gdouble current_step) { p_delta_gint(&val->function, val_from->function, val_to->function, total_steps, current_step); p_delta_gint(&val->composition, val_from->composition, val_to->composition, total_steps, current_step); p_delta_gint(&val->arrange, val_from->arrange, val_to->arrange, total_steps, current_step); p_delta_gint(&val->cyclic_range, val_from->cyclic_range, val_to->cyclic_range, total_steps, current_step); p_delta_gdouble(&val->mod_rate, val_from->mod_rate, val_to->mod_rate, total_steps, current_step); p_delta_gdouble(&val->env_sensitivity, val_from->env_sensitivity, val_to->env_sensitivity, total_steps, current_step); p_delta_gint(&val->diffusion_dist, val_from->diffusion_dist, val_to->diffusion_dist, total_steps, current_step); p_delta_gdouble(&val->ch_sensitivity, val_from->ch_sensitivity, val_to->ch_sensitivity, total_steps, current_step); p_delta_gint(&val->range_num, val_from->range_num, val_to->range_num, total_steps, current_step); p_delta_gdouble(&val->power, val_from->power, val_to->power, total_steps, current_step); p_delta_gdouble(&val->parameter_k, val_from->parameter_k, val_to->parameter_k, total_steps, current_step); p_delta_gdouble(&val->range_l, val_from->range_l, val_to->range_l, total_steps, current_step); p_delta_gdouble(&val->range_h, val_from->range_h, val_to->range_h, total_steps, current_step); p_delta_gdouble(&val->mutation_rate, val_from->mutation_rate, val_to->mutation_rate, total_steps, current_step); p_delta_gdouble(&val->mutation_dist, val_from->mutation_dist, val_to->mutation_dist, total_steps, current_step); } /* for gimpressionist */ typedef struct gimpressionist_vector { double x, y; double dir; double dx, dy; double str; int type; } t_gimpressionist_vector; typedef struct gimpressionist_smvector { double x, y; double siz; double str; } t_gimpressionist_smvector; static void p_delta_gimpressionist_vector(t_gimpressionist_vector *val, t_gimpressionist_vector *val_from, t_gimpressionist_vector *val_to, gint32 total_steps, gdouble current_step) { if(total_steps < 1) return; p_delta_gdouble(&val->x, val_from->x, val_to->x, total_steps, current_step); p_delta_gdouble(&val->y, val_from->y, val_to->y, total_steps, current_step); p_delta_gdouble(&val->dir, val_from->dir, val_to->dir, total_steps, current_step); p_delta_gdouble(&val->dx, val_from->dx, val_to->dx, total_steps, current_step); p_delta_gdouble(&val->dy, val_from->dy, val_to->dy, total_steps, current_step); p_delta_gdouble(&val->str, val_from->str, val_to->str, total_steps, current_step); p_delta_gint(&val->type, val_from->type, val_to->type, total_steps, current_step); } static void p_delta_gimpressionist_smvector(t_gimpressionist_smvector *val, t_gimpressionist_smvector *val_from, t_gimpressionist_smvector *val_to, gint32 total_steps, gdouble current_step) { if(total_steps < 1) return; p_delta_gdouble(&val->x, val_from->x, val_to->x, total_steps, current_step); p_delta_gdouble(&val->y, val_from->y, val_to->y, total_steps, current_step); p_delta_gdouble(&val->siz, val_from->siz, val_to->siz, total_steps, current_step); p_delta_gdouble(&val->str, val_from->str, val_to->str, total_steps, current_step); } /* for channel_mixer */ typedef struct { gdouble red_gain; gdouble green_gain; gdouble blue_gain; } t_channel_mixer_ch_type; static void p_delta_channel_mixer_ch_type(t_channel_mixer_ch_type *val, t_channel_mixer_ch_type *val_from, t_channel_mixer_ch_type *val_to, gint32 total_steps, gdouble current_step) { if(total_steps < 1) return; p_delta_gdouble(&val->red_gain, val_from->red_gain, val_to->red_gain, total_steps, current_step); p_delta_gdouble(&val->green_gain, val_from->green_gain, val_to->green_gain, total_steps, current_step); p_delta_gdouble(&val->blue_gain, val_from->blue_gain, val_to->blue_gain, total_steps, current_step); } /* ---------------------------------------- 2.nd Section * ---------------------------------------- * INCLUDE the generated p_XXX_iter_ALT procedures * ---------------------------------------- * ---------------------------------------- */ #include "iter_ALT/mod/plug_in_Twist_iter_ALT.inc" #include "iter_ALT/mod/plug_in_alienmap2_iter_ALT.inc" #include "iter_ALT/mod/plug_in_apply_canvas_iter_ALT.inc" #include "iter_ALT/mod/plug_in_applylens_iter_ALT.inc" #include "iter_ALT/mod/plug_in_bump_map_iter_ALT.inc" #include "iter_ALT/mod/plug_in_cartoon_iter_ALT.inc" #include "iter_ALT/mod/plug_in_colortoalpha_iter_ALT.inc" #include "iter_ALT/mod/plug_in_colors_channel_mixer_iter_ALT.inc" #include "iter_ALT/mod/plug_in_convmatrix_iter_ALT.inc" #include "iter_ALT/mod/plug_in_depth_merge_iter_ALT.inc" #include "iter_ALT/mod/plug_in_despeckle_iter_ALT.inc" #include "iter_ALT/mod/plug_in_dog_iter_ALT.inc" #include "iter_ALT/mod/plug_in_emboss_iter_ALT.inc" #include "iter_ALT/mod/plug_in_exchange_iter_ALT.inc" #include "iter_ALT/mod/plug_in_flame_iter_ALT.inc" #include "iter_ALT/mod/plug_in_gauss_iter_ALT.inc" #include "iter_ALT/mod/plug_in_gimpressionist_iter_ALT.inc" #include "iter_ALT/mod/plug_in_illusion_iter_ALT.inc" #include "iter_ALT/mod/plug_in_lic_iter_ALT.inc" #include "iter_ALT/mod/plug_in_lighting_iter_ALT.inc" #include "iter_ALT/mod/plug_in_map_object_iter_ALT.inc" #include "iter_ALT/mod/plug_in_maze_iter_ALT.inc" #include "iter_ALT/mod/plug_in_neon_iter_ALT.inc" #include "iter_ALT/mod/plug_in_nlfilt_iter_ALT.inc" #include "iter_ALT/mod/plug_in_nova_iter_ALT.inc" #include "iter_ALT/mod/plug_in_oilify_iter_ALT.inc" #include "iter_ALT/mod/plug_in_pagecurl_iter_ALT.inc" #include "iter_ALT/mod/plug_in_papertile_iter_ALT.inc" #include "iter_ALT/mod/plug_in_photocopy_iter_ALT.inc" #include "iter_ALT/mod/plug_in_plasma_iter_ALT.inc" #include "iter_ALT/mod/plug_in_polar_coords_iter_ALT.inc" #include "iter_ALT/mod/plug_in_retinex_iter_ALT.inc" #include "iter_ALT/mod/plug_in_sample_colorize_iter_ALT.inc" #include "iter_ALT/mod/plug_in_sel_gauss_iter_ALT.inc" #include "iter_ALT/mod/plug_in_sinus_iter_ALT.inc" #include "iter_ALT/mod/plug_in_small_tiles_iter_ALT.inc" #include "iter_ALT/mod/plug_in_sobel_iter_ALT.inc" #include "iter_ALT/mod/plug_in_softglow_iter_ALT.inc" #include "iter_ALT/mod/plug_in_solid_noise_iter_ALT.inc" #include "iter_ALT/mod/plug_in_sparkle_iter_ALT.inc" #include "iter_ALT/mod/plug_in_unsharp_mask_iter_ALT.inc" #include "iter_ALT/old/plug_in_CentralReflection_iter_ALT.inc" #include "iter_ALT/old/plug_in_anamorphose_iter_ALT.inc" #include "iter_ALT/old/plug_in_blur2_iter_ALT.inc" #include "iter_ALT/old/plug_in_encript_iter_ALT.inc" #include "iter_ALT/old/plug_in_figures_iter_ALT.inc" #include "iter_ALT/old/plug_in_gflare_iter_ALT.inc" #include "iter_ALT/old/plug_in_holes_iter_ALT.inc" #include "iter_ALT/old/plug_in_julia_iter_ALT.inc" #include "iter_ALT/old/plug_in_magic_eye_iter_ALT.inc" #include "iter_ALT/old/plug_in_mandelbrot_iter_ALT.inc" #include "iter_ALT/old/plug_in_randomize_iter_ALT.inc" #include "iter_ALT/old/plug_in_refract_iter_ALT.inc" #include "iter_ALT/old/plug_in_struc_iter_ALT.inc" #include "iter_ALT/old/plug_in_tileit_iter_ALT.inc" #include "iter_ALT/old/plug_in_universal_filter_iter_ALT.inc" #include "iter_ALT/old/plug_in_warp_iter_ALT.inc" #include "iter_ALT/gen/plug_in_CML_explorer_iter_ALT.inc" #include "iter_ALT/gen/plug_in_alpha2color_iter_ALT.inc" #include "iter_ALT/gen/plug_in_blinds_iter_ALT.inc" #include "iter_ALT/gen/plug_in_borderaverage_iter_ALT.inc" #include "iter_ALT/gen/plug_in_checkerboard_iter_ALT.inc" #include "iter_ALT/gen/plug_in_color_map_iter_ALT.inc" #include "iter_ALT/gen/plug_in_colorify_iter_ALT.inc" #include "iter_ALT/gen/plug_in_cubism_iter_ALT.inc" #include "iter_ALT/gen/plug_in_destripe_iter_ALT.inc" #include "iter_ALT/gen/plug_in_diffraction_iter_ALT.inc" #include "iter_ALT/gen/plug_in_displace_iter_ALT.inc" #include "iter_ALT/gen/plug_in_edge_iter_ALT.inc" #include "iter_ALT/gen/plug_in_engrave_iter_ALT.inc" #include "iter_ALT/gen/plug_in_flarefx_iter_ALT.inc" #include "iter_ALT/gen/plug_in_fractal_trace_iter_ALT.inc" #include "iter_ALT/gen/plug_in_glasstile_iter_ALT.inc" #include "iter_ALT/gen/plug_in_grid_iter_ALT.inc" #include "iter_ALT/gen/plug_in_jigsaw_iter_ALT.inc" #include "iter_ALT/gen/plug_in_mblur_iter_ALT.inc" #include "iter_ALT/gen/plug_in_mosaic_iter_ALT.inc" #include "iter_ALT/gen/plug_in_newsprint_iter_ALT.inc" #include "iter_ALT/gen/plug_in_noisify_iter_ALT.inc" #include "iter_ALT/gen/plug_in_pixelize_iter_ALT.inc" #include "iter_ALT/gen/plug_in_randomize_hurl_iter_ALT.inc" #include "iter_ALT/gen/plug_in_randomize_pick_iter_ALT.inc" #include "iter_ALT/gen/plug_in_randomize_slur_iter_ALT.inc" #include "iter_ALT/gen/plug_in_ripple_iter_ALT.inc" #include "iter_ALT/gen/plug_in_scatter_hsv_iter_ALT.inc" #include "iter_ALT/gen/plug_in_sharpen_iter_ALT.inc" #include "iter_ALT/gen/plug_in_shift_iter_ALT.inc" #include "iter_ALT/gen/plug_in_spread_iter_ALT.inc" #include "iter_ALT/gen/plug_in_video_iter_ALT.inc" #include "iter_ALT/gen/plug_in_vpropagate_iter_ALT.inc" #include "iter_ALT/gen/plug_in_waves_iter_ALT.inc" #include "iter_ALT/gen/plug_in_whirl_pinch_iter_ALT.inc" #include "iter_ALT/gen/plug_in_wind_iter_ALT.inc" /* table of proc_names and funtion pointers to iter_ALT procedures */ /* del ... Deleted (does not make sense to animate) * + ... generated code did not work (changed manually) */ static t_iter_ALT_tab g_iter_ALT_tab[] = { { "plug-in-alienmap2", p_plug_in_alienmap2_iter_ALT } , { "plug-in-cml-explorer", p_plug_in_cml_explorer_iter_ALT } , { "plug-in-CentralReflection", p_plug_in_CentralReflection_iter_ALT } , { "plug-in-Twist", p_plug_in_Twist_iter_ALT } /*, { "plug-in-alienmap", p_plug_in_alienmap_iter_ALT } */ /*, { "plug-in-align-layers", p_plug_in_align_layers_iter_ALT } */ , { "plug-in-alpha2color", p_plug_in_alpha2color_iter_ALT } , { "plug-in-anamorphose", p_plug_in_anamorphose_iter_ALT } /*, { "plug-in-animationoptimize", p_plug_in_animationoptimize_iter_ALT } */ /*, { "plug-in-animationplay", p_plug_in_animationplay_iter_ALT } */ /*, { "plug-in-animationunoptimize", p_plug_in_animationunoptimize_iter_ALT } */ , { "plug-in-apply-canvas", p_plug_in_apply_canvas_iter_ALT } , { "plug-in-applylens", p_plug_in_applylens_iter_ALT } /*, { "plug-in-autocrop", p_plug_in_autocrop_iter_ALT } */ /*, { "plug-in-autostretch-hsv", p_plug_in_autostretch_hsv_iter_ALT } */ , { "plug-in-blinds", p_plug_in_blinds_iter_ALT } /*, { "plug-in-blur", p_plug_in_blur_iter_ALT } */ , { "plug-in-blur2", p_plug_in_blur2_iter_ALT } /*, { "plug-in-blur-randomize", p_plug_in_blur_randomize_iter_ALT } */ , { "plug-in-borderaverage", p_plug_in_borderaverage_iter_ALT } , { "plug-in-bump-map", p_plug_in_bump_map_iter_ALT } /*, { "plug-in-c-astretch", p_plug_in_c_astretch_iter_ALT } */ , { "plug-in-cartoon", p_plug_in_cartoon_iter_ALT } , { "plug-in-checkerboard", p_plug_in_checkerboard_iter_ALT } /*, { "plug-in-color-adjust", p_plug_in_color_adjust_iter_ALT } */ , { "plug-in-color-map", p_plug_in_color_map_iter_ALT } , { "plug-in-colorify", p_plug_in_colorify_iter_ALT } , { "plug-in-colortoalpha", p_plug_in_colortoalpha_iter_ALT } , { "plug-in-colors-channel-mixer", p_plug_in_colors_channel_mixer_iter_ALT } /*, { "plug-in-compose", p_plug_in_compose_iter_ALT } */ , { "plug-in-convmatrix", p_plug_in_convmatrix_iter_ALT } , { "plug-in-cubism", p_plug_in_cubism_iter_ALT } /*, { "plug-in-decompose", p_plug_in_decompose_iter_ALT } */ /*, { "plug-in-deinterlace", p_plug_in_deinterlace_iter_ALT } */ , { "plug-in-depth-merge", p_plug_in_depth_merge_iter_ALT } , { "plug-in-despeckle", p_plug_in_despeckle_iter_ALT } , { "plug-in-destripe", p_plug_in_destripe_iter_ALT } , { "plug-in-diffraction", p_plug_in_diffraction_iter_ALT } , { "plug-in-displace", p_plug_in_displace_iter_ALT } /*, { "plug-in-ditherize", p_plug_in_ditherize_iter_ALT } */ , { "plug-in-dog", p_plug_in_dog_iter_ALT } , { "plug-in-edge", p_plug_in_edge_iter_ALT } , { "plug-in-emboss", p_plug_in_emboss_iter_ALT } , { "plug-in-encript", p_plug_in_encript_iter_ALT } , { "plug-in-engrave", p_plug_in_engrave_iter_ALT } , { "plug-in-exchange", p_plug_in_exchange_iter_ALT } /*, { "plug-in-export-palette", p_plug_in_export_palette_iter_ALT } */ , { "plug-in-figures", p_plug_in_figures_iter_ALT } /*, { "plug-in-film", p_plug_in_film_iter_ALT } */ /*, { "plug-in-filter-pack", p_plug_in_filter_pack_iter_ALT } */ , { "plug-in-flame", p_plug_in_flame_iter_ALT } , { "plug-in-flarefx", p_plug_in_flarefx_iter_ALT } , { "plug-in-fractal-trace", p_plug_in_fractal_trace_iter_ALT } , { "plug-in-gauss", p_plug_in_gauss_iter_ALT } /*, { "plug-in-gfig", p_plug_in_gfig_iter_ALT } */ , { "plug-in-gflare", p_plug_in_gflare_iter_ALT } , { "plug-in-gimpressionist", p_plug_in_gimpressionist_iter_ALT } , { "plug-in-glasstile", p_plug_in_glasstile_iter_ALT } /*, { "plug-in-gradmap", p_plug_in_gradmap_iter_ALT } */ , { "plug-in-grid", p_plug_in_grid_iter_ALT } /*, { "plug-in-guillotine", p_plug_in_guillotine_iter_ALT } */ , { "plug-in-holes", p_plug_in_holes_iter_ALT } /*, { "plug-in-hot", p_plug_in_hot_iter_ALT } */ /*, { "plug-in-ifs-compose", p_plug_in_ifs_compose_iter_ALT } */ , { "plug-in-illusion", p_plug_in_illusion_iter_ALT } /*, { "plug-in-image-rot270", p_plug_in_image_rot270_iter_ALT } */ /*, { "plug-in-image-rot90", p_plug_in_image_rot90_iter_ALT } */ /*, { "plug-in-iwarp", p_plug_in_iwarp_iter_ALT } */ , { "plug-in-jigsaw", p_plug_in_jigsaw_iter_ALT } , { "plug-in-julia", p_plug_in_julia_iter_ALT } /*, { "plug-in-laplace", p_plug_in_laplace_iter_ALT } */ /*, { "plug-in-layer-rot270", p_plug_in_layer_rot270_iter_ALT } */ /*, { "plug-in-layer-rot90", p_plug_in_layer_rot90_iter_ALT } */ /*, { "plug-in-layers-import", p_plug_in_layers_import_iter_ALT } */ , { "plug-in-lic", p_plug_in_lic_iter_ALT } , { "plug-in-lighting", p_plug_in_lighting_iter_ALT } , { "plug-in-magic-eye", p_plug_in_magic_eye_iter_ALT } /*, { "plug-in-mail-image", p_plug_in_mail_image_iter_ALT } */ , { "plug-in-mandelbrot", p_plug_in_mandelbrot_iter_ALT } , { "plug-in-map-object", p_plug_in_map_object_iter_ALT } /*, { "plug-in-max-rgb", p_plug_in_max_rgb_iter_ALT } */ , { "plug-in-maze", p_plug_in_maze_iter_ALT } , { "plug-in-mblur", p_plug_in_mblur_iter_ALT } , { "plug-in-mosaic", p_plug_in_mosaic_iter_ALT } , { "plug-in-neon", p_plug_in_neon_iter_ALT } , { "plug-in-newsprint", p_plug_in_newsprint_iter_ALT } , { "plug-in-nlfilt", p_plug_in_nlfilt_iter_ALT } , { "plug-in-rgb-noise", p_plug_in_noisify_iter_ALT } /*, { "plug-in-normalize", p_plug_in_normalize_iter_ALT } */ , { "plug-in-nova", p_plug_in_nova_iter_ALT } , { "plug-in-oilify", p_plug_in_oilify_iter_ALT } , { "plug-in-pagecurl", p_plug_in_pagecurl_iter_ALT } , { "plug-in-papertile", p_plug_in_papertile_iter_ALT } , { "plug-in-photocopy", p_plug_in_photocopy_iter_ALT } , { "plug-in-pixelize", p_plug_in_pixelize_iter_ALT } , { "plug-in-plasma", p_plug_in_plasma_iter_ALT } , { "plug-in-polar-coords", p_plug_in_polar_coords_iter_ALT } /*, { "plug-in-qbist", p_plug_in_qbist_iter_ALT } */ , { "plug-in-randomize", p_plug_in_randomize_iter_ALT } , { "plug-in-randomize-hurl", p_plug_in_randomize_hurl_iter_ALT } , { "plug-in-randomize-pick", p_plug_in_randomize_pick_iter_ALT } , { "plug-in-randomize-slur", p_plug_in_randomize_slur_iter_ALT } , { "plug-in-refract", p_plug_in_refract_iter_ALT } , { "plug-in-retinex", p_plug_in_retinex_iter_ALT } , { "plug-in-ripple", p_plug_in_ripple_iter_ALT } /*, { "plug-in-rotate", p_plug_in_rotate_iter_ALT } */ , { "plug-in-sample-colorize", p_plug_in_sample_colorize_iter_ALT } , { "plug-in-hsv-noise", p_plug_in_scatter_hsv_iter_ALT } , { "plug-in-sel-gauss", p_plug_in_sel_gauss_iter_ALT } /*, { "plug-in-semiflatten", p_plug_in_semiflatten_iter_ALT } */ , { "plug-in-sharpen", p_plug_in_sharpen_iter_ALT } , { "plug-in-shift", p_plug_in_shift_iter_ALT } , { "plug-in-sinus", p_plug_in_sinus_iter_ALT } , { "plug-in-small-tiles", p_plug_in_small_tiles_iter_ALT } /*, { "plug-in-smooth-palette", p_plug_in_smooth_palette_iter_ALT } */ , { "plug-in-sobel", p_plug_in_sobel_iter_ALT } , { "plug-in-softglow", p_plug_in_softglow_iter_ALT } , { "plug-in-solid-noise", p_plug_in_solid_noise_iter_ALT } , { "plug-in-sparkle", p_plug_in_sparkle_iter_ALT } , { "plug-in-spread", p_plug_in_spread_iter_ALT } , { "plug-in-struc", p_plug_in_struc_iter_ALT } /*, { "plug-in-the-egg", p_plug_in_the_egg_iter_ALT } */ /*, { "plug-in-threshold-alpha", p_plug_in_threshold_alpha_iter_ALT } */ /*, { "plug-in-tile", p_plug_in_tile_iter_ALT } */ , { "plug-in-tileit", p_plug_in_tileit_iter_ALT } , { "plug-in-universal-filter", p_plug_in_universal_filter_iter_ALT } , { "plug-in-unsharp-mask", p_plug_in_unsharp_mask_iter_ALT } , { "plug-in-video", p_plug_in_video_iter_ALT } /*, { "plug-in-vinvert", p_plug_in_vinvert_iter_ALT } */ , { "plug-in-vpropagate", p_plug_in_vpropagate_iter_ALT } , { "plug-in-warp", p_plug_in_warp_iter_ALT } , { "plug-in-waves", p_plug_in_waves_iter_ALT } , { "plug-in-whirl-pinch", p_plug_in_whirl_pinch_iter_ALT } , { "plug-in-wind", p_plug_in_wind_iter_ALT } /*, { "plug-in-zealouscrop", p_plug_in_zealouscrop_iter_ALT } */ }; /* end g_iter_ALT_tab */ #define MAX_ITER_ALT ( sizeof(g_iter_ALT_tab) / sizeof(t_iter_ALT_tab) ) /* ---------------------------------------------------------------------- * install (query) iterators_ALT * ---------------------------------------------------------------------- */ static void p_install_proc_iter_ALT(char *name) { gchar *l_iter_proc_name; gchar *l_blurb_text; static GimpParamDef args_iter[] = { {GIMP_PDB_INT32, "run_mode", "non-interactive"}, {GIMP_PDB_INT32, "total_steps", "total number of steps (# of layers-1 to apply the related plug-in)"}, {GIMP_PDB_FLOAT, "current_step", "current (for linear iterations this is the layerstack position, otherwise some value inbetween)"}, {GIMP_PDB_INT32, "len_struct", "length of stored data structure with id is equal to the plug_in proc_name"}, }; static GimpParamDef *return_vals = NULL; static int nreturn_vals = 0; l_iter_proc_name = g_strdup_printf("%s%s", name, GAP_ITERATOR_ALT_SUFFIX); l_blurb_text = g_strdup_printf("This procedure calculates the modified values for one iterationstep for the call of %s", name); gimp_install_procedure(l_iter_proc_name, l_blurb_text, "", "Wolfgang Hofer", "Wolfgang Hofer", "Nov. 2007", NULL, /* do not appear in menus */ NULL, GIMP_PLUGIN, G_N_ELEMENTS (args_iter), nreturn_vals, args_iter, return_vals); g_free(l_iter_proc_name); g_free(l_blurb_text); } void gap_query_iterators_ALT() { guint l_idx; for(l_idx = 0; l_idx < MAX_ITER_ALT; l_idx++) { p_install_proc_iter_ALT (g_iter_ALT_tab[l_idx].proc_name); } } /* ---------------------------------------------------------------------- * run iterators_ALT * ---------------------------------------------------------------------- */ gint gap_run_iterators_ALT(const char *name, GimpRunMode run_mode, gint32 total_steps, gdouble current_step, gint32 len_struct) { gint l_rc; guint l_idx; char *l_name; int l_cut; if(gap_debug) { printf("gap_run_iterators_ALT START for name:%s\n", name); } l_name = g_strdup(name); l_cut = strlen(l_name) - strlen(GAP_ITERATOR_ALT_SUFFIX); if(l_cut < 1) { printf("ERROR: gap_run_iterators_ALT: proc_name ending %s missing%s\n" , GAP_ITERATOR_ALT_SUFFIX , name ); return -1; } if(strcmp(&l_name[l_cut], GAP_ITERATOR_ALT_SUFFIX) != 0) { printf("ERROR: gap_run_iterators_ALT: proc_name ending %s missing%s\n" , GAP_ITERATOR_ALT_SUFFIX , name ); return -1; } l_rc = -1; l_name[l_cut] = '\0'; /* cut off "-Iterator-ALT" from l_name end */ /* allocate from/to plugin_data buffers * as big as needed for the current plugin named l_name */ g_plugin_data_from = p_alloc_plugin_data(l_name); g_plugin_data_to = p_alloc_plugin_data(l_name); if((g_plugin_data_from != NULL) && (g_plugin_data_to != NULL)) { for(l_idx = 0; l_idx < MAX_ITER_ALT; l_idx++) { if (strcmp (l_name, g_iter_ALT_tab[l_idx].proc_name) == 0) { if(gap_debug) printf("DEBUG: gap_run_iterators_ALT: FOUND %s\n", l_name); l_rc = (g_iter_ALT_tab[l_idx].proc_func)(run_mode, total_steps, current_step, len_struct); } } } if(l_rc < 0) fprintf(stderr, "ERROR: gap_run_iterators_ALT: NOT FOUND proc_name=%s (%s)\n", name, l_name); /* free from/to plugin_data buffers */ if(g_plugin_data_from) g_free(g_plugin_data_from); if(g_plugin_data_to) g_free(g_plugin_data_to); return l_rc; } /* end gap_run_iterators_ALT */ gimp-gap-2.6.0+dfsg.orig/gap/gap_pdb_calls.h0000644000175000017500000000477611212030253020455 0ustar thibautthibaut/* gap_pdb_calls.h * * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.25a; 2004/01/20 hof: removed gap_pdb_gimp_file_load_thumbnail * version 1.3.14b; 2003/06/03 hof: gboolean retcode for thumbnail procedures * version 1.3.14a; 2003/05/24 hof: moved vin Procedures to gap_vin module * version 1.3.5a; 2002/04/20 hof: gap_pdb_gimp_layer_new_from_drawable. (removed set_drabale) * version 1.3.4a; 2002/03/12 hof: removed duplicate wrappers that are available in libgimp too. * version 1.2.2b; 2001/12/09 hof: wrappers for tattoo procedures * version 1.1.16a; 2000/02/05 hof: path lockedstaus * version 1.1.15b; 2000/01/30 hof: image parasites * version 1.1.15a; 2000/01/26 hof: pathes, removed gimp 1.0.x support * version 1.1.14a; 2000/01/06 hof: thumbnail save/load, * Procedures for video_info file * version 0.98.00; 1998/11/30 hof: all PDB-calls of GIMP PDB-Procedures */ #ifndef _GAP_PDB_CALLS_H #define _GAP_PDB_CALLS_H #include "libgimp/gimp.h" gint gap_pdb_procedure_available(char *proc_name); gint32 gap_pdb_gimp_rotate_degree(gint32 drawable_id, gboolean interpolation, gdouble angle_deg); gboolean gap_pdb_gimp_displays_reconnect(gint32 old_image_id, gint32 new_image_id); gint32 gap_pdb_gimp_layer_new_from_drawable(gint32 drawable_id, gint32 dst_image_id); gboolean gap_pdb_gimp_file_save_thumbnail(gint32 image_id, char* filename); gboolean gap_pdb_gimp_image_thumbnail(gint32 image_id, gint32 width, gint32 height, gint32 *th_width, gint32 *th_height, gint32 *th_bpp, gint32 *th_data_count, unsigned char **th_data); gboolean gap_pdb_procedure_name_available (const gchar *search_name); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_pview_da.c0000644000175000017500000012765511212030253020325 0ustar thibautthibaut/* gap_pview_da.c * * This module handles GAP drawing_area rendering from thumbnail data buffer * or alternative from a gimp image * (used for video playback preview) */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 2.0.1b; 2004/05/01 hof: dont attempt to render negative (invalid) image_id's * version 1.3.26a; 2004/01/30 hof: added gap_pview_drop_repaint_buffers * version 1.3.25a; 2004/01/22 hof: added gap_pview_render_from_pixbuf * version 1.3.24a; 2004/01/17 hof: speed up gap_pview_render_from_buf * faster rendering of fully opaque pixels * for buffers with alpha channel * version 1.3.16a; 2003/06/26 hof: use aspect_frame instead of simple frame * added gap_pview_render_default_icon * version 1.3.14c; 2003/06/19 hof: created */ #include "config.h" #include #include #include #include #include #include "gap_pview_da.h" #include "gap-intl.h" #include "gap_lib_common_defs.h" extern int gap_debug; /* 1 == print debug infos , 0 dont print debug infos */ #define MIX_CHANNEL(b, a, m) (((a * m) + (b * (255 - m))) / 255) #define PREVIEW_BG_GRAY1 80 #define PREVIEW_BG_GRAY2 180 #define PREVIEW_BG_GRAY1_GDK 0x505050 #define PREVIEW_BG_GRAY2_GDK 0xb4b4b4 static void p_replace_pixbuf_by_flipped_pixbuf(GapPView *pv_ptr, gint32 flip_to_perform); static gint32 p_calculate_flip_request(GapPView *pv_ptr, gint32 flip_request, gint32 flip_status); static void p_render_thdata_as_flipped_pixbuf(GapPView *pv_ptr, gint32 flip_to_perform); static void p_pview_repaint_desaturated(GapPView *pv_ptr); static void p_desaturate(GapPView *pv_ptr, guchar *src_buff, gint src_rowstride); static void p_free_desaturated_area_data(GapPView *pv_ptr); static void p_create_desaturated_buf_from_pixbuf(GapPView *pv_ptr); static void p_create_desaturated_buf_from_area_data(GapPView *pv_ptr); /* ---------------------------------------------------- * p_replace_pixbuf_by_flipped_pixbuf * ---------------------------------------------------- */ static void p_replace_pixbuf_by_flipped_pixbuf(GapPView *pv_ptr, gint32 flip_to_perform) { GdkPixbuf *flipped_pixbuf; gboolean horizontal; if(pv_ptr->pixbuf == NULL) { printf("ERROR cant flip pv_ptr->pixbuf becaus it is NULL\n"); return; } flipped_pixbuf = NULL; switch(flip_to_perform) { case GAP_STB_FLIP_HOR: horizontal = TRUE; flipped_pixbuf = gdk_pixbuf_flip(pv_ptr->pixbuf ,horizontal ); break; case GAP_STB_FLIP_VER: horizontal = FALSE; flipped_pixbuf = gdk_pixbuf_flip(pv_ptr->pixbuf ,horizontal ); break; case GAP_STB_FLIP_BOTH: flipped_pixbuf = gdk_pixbuf_rotate_simple (pv_ptr->pixbuf ,GDK_PIXBUF_ROTATE_UPSIDEDOWN ); break; default: break; } if(flipped_pixbuf) { /* free old (refresh) pixbuf if there is one * and replace by fliped variant */ g_object_unref(pv_ptr->pixbuf); pv_ptr->pixbuf = flipped_pixbuf; } } /* end p_replace_pixbuf_by_flipped_pixbuf */ /* ---------------------------------------------------- * p_calculate_flip_request * ---------------------------------------------------- * return the flip action to be performed on an image * that was already transformed as described by flip_status * and should be transformed as described by flip_request. * * in case both values are equal, no transformation is necessary * different bits require the corresponding transformation. * (XOR delvers the required result) * * request status return * 0 0 0 * 1 0 1 * 2 0 2 * 3 0 3 * * request status return * 0 1 1 * 1 1 0 * 2 1 3 * 3 1 2 * * request status return * 0 2 2 * 1 2 3 * 2 2 0 * 3 2 1 * * request status return * 0 3 3 * 1 3 2 * 2 3 1 * 3 3 0 */ static gint32 p_calculate_flip_request(GapPView *pv_ptr, gint32 flip_request, gint32 flip_status) { pv_ptr->flip_status = flip_request; return ((flip_request ^ flip_status) & 3); } /* end p_calculate_flip_request */ /* ---------------------------------------------------- * p_render_thdata_as_flipped_pixbuf * ---------------------------------------------------- */ static void p_render_thdata_as_flipped_pixbuf(GapPView *pv_ptr , gint32 flip_to_perform ) { if(pv_ptr->pixbuf) { /* free old (refresh) pixbuf if there is one * and replace by fliped variant */ g_object_unref(pv_ptr->pixbuf); } /* create a pixbuf from pv_area_data * use NULL because we dont want to run the destructor notifyer * (g_free of pv_area_data is already handled in gap_pview_reset) */ pv_ptr->pixbuf = gdk_pixbuf_new_from_data(pv_ptr->pv_area_data , GDK_COLORSPACE_RGB , FALSE /* has_alpha */ , 8 /* bits_per_sample */ , pv_ptr->pv_width , pv_ptr->pv_height , pv_ptr->pv_width * pv_ptr->pv_bpp /* rowstride */ , NULL /* GdkPixbufDestroyNotify NULL: dont call destroy_fn */ , pv_ptr->pv_area_data /* gpointer destroy_fn_data */ ); /* clear flag to let gap_pview_repaint procedure know * to use the pixbuf rather than pv_area_data or pixmap for refresh */ pv_ptr->use_pixmap_repaint = FALSE; pv_ptr->use_pixbuf_repaint = TRUE; p_replace_pixbuf_by_flipped_pixbuf(pv_ptr, flip_to_perform); gap_pview_repaint(pv_ptr); } /* end p_render_thdata_as_flipped_pixbuf */ /* ---------------------------------------------------- * p_pview_repaint_desaturated * ---------------------------------------------------- * repaint from the desaturated buffer. */ static void p_pview_repaint_desaturated(GapPView *pv_ptr) { if(gap_debug) { printf("p_pview_repaint_desaturated START\n"); } if(pv_ptr->pv_desaturated_area_data) { gdk_draw_rgb_image ( pv_ptr->da_widget->window , pv_ptr->da_widget->style->white_gc , 0 , 0 , pv_ptr->pv_width , pv_ptr->pv_height , GDK_RGB_DITHER_NORMAL , pv_ptr->pv_desaturated_area_data , pv_ptr->pv_width * 3 ); } } /* end p_pview_repaint_desaturated */ /* ---------------------------------------------------- * p_desaturate * ---------------------------------------------------- * fill the desaturated_area_data with a grayscale copy * of the specified src_buff. * NOTE: both buffers are same size and have bpp 3 (for RGB) * desaturation uses the same gray value for all 3 color channels. */ static void p_desaturate(GapPView *pv_ptr, guchar *src_buff, gint src_rowstride) { gint didx; gint sidx; gint src_bpp; gint row; gint col; gint dst_rowstride; src_bpp = src_rowstride / MAX(1, pv_ptr->pv_width); dst_rowstride = pv_ptr->pv_width * pv_ptr->pv_bpp; if((pv_ptr->pv_desaturated_area_data) && (src_buff)) { sidx = 0; didx = 0; for(row=0; row < pv_ptr->pv_height; row++ ) { sidx = row * src_rowstride; didx = row * dst_rowstride; for(col=0; col < pv_ptr->pv_width; col++) { gdouble grayvalue; grayvalue = ((gdouble)src_buff[sidx] + (gdouble)src_buff[sidx + 1] + (gdouble)src_buff[sidx + 2]) / 3.0; pv_ptr->pv_desaturated_area_data[didx] = (guchar)grayvalue; pv_ptr->pv_desaturated_area_data[didx + 1] = (guchar)grayvalue; pv_ptr->pv_desaturated_area_data[didx + 2] = (guchar)grayvalue; sidx += src_bpp; didx += pv_ptr->pv_bpp; } } } } /* end p_desaturate */ /* ---------------------------------------------------- * p_free_desaturated_area_data * ---------------------------------------------------- */ static void p_free_desaturated_area_data(GapPView *pv_ptr) { if(pv_ptr->pv_desaturated_area_data) { g_free(pv_ptr->pv_desaturated_area_data); pv_ptr->pv_desaturated_area_data = NULL; } } /* end p_free_desaturated_area_data */ /* ---------------------------------------------------- * p_create_desaturated_buf_from_pixbuf * ---------------------------------------------------- */ static void p_create_desaturated_buf_from_pixbuf(GapPView *pv_ptr) { pv_ptr->pv_desaturated_area_data = g_new ( guchar , pv_ptr->pv_height * pv_ptr->pv_width * pv_ptr->pv_bpp ); p_desaturate(pv_ptr , gdk_pixbuf_get_pixels(pv_ptr->pixbuf) , gdk_pixbuf_get_rowstride(pv_ptr->pixbuf) ); } /* end p_create_desaturated_buf_from_pixbuf */ /* ---------------------------------------------------- * p_create_desaturated_buf_from_area_data * ---------------------------------------------------- */ static void p_create_desaturated_buf_from_area_data(GapPView *pv_ptr) { gint l_rowstride; l_rowstride = pv_ptr->pv_width * pv_ptr->pv_bpp; pv_ptr->pv_desaturated_area_data = g_new ( guchar , pv_ptr->pv_height * l_rowstride); p_desaturate(pv_ptr, pv_ptr->pv_area_data, l_rowstride); } /* end p_create_desaturated_buf_from_area_data */ /* ------------------------------ * gap_pview_render_from_buf * ------------------------------ */ gboolean gap_pview_render_from_buf (GapPView *pv_ptr , guchar *src_data , gint src_width , gint src_height , gint src_bpp , gboolean allow_grab_src_data ) { return gap_pview_render_f_from_buf(pv_ptr ,src_data ,src_width ,src_height ,src_bpp ,allow_grab_src_data ,GAP_STB_FLIP_NONE ,GAP_STB_FLIP_NONE ); } /* end gap_pview_render_from_buf */ /* ------------------------------ * gap_pview_render_from_image * ------------------------------ */ void gap_pview_render_from_image (GapPView *pv_ptr, gint32 image_id) { gap_pview_render_f_from_image(pv_ptr ,image_id ,GAP_STB_FLIP_NONE ,GAP_STB_FLIP_NONE ); } /* end gap_pview_render_from_image */ /* ------------------------------------- * gap_pview_render_from_image_duplicate * ------------------------------------- */ void gap_pview_render_from_image_duplicate (GapPView *pv_ptr, gint32 image_id) { gap_pview_render_f_from_image_duplicate(pv_ptr ,image_id ,GAP_STB_FLIP_NONE ,GAP_STB_FLIP_NONE ); } /* end gap_pview_render_from_image_duplicate */ /* ------------------------------ * gap_pview_render_from_pixbuf * ------------------------------ */ void gap_pview_render_from_pixbuf (GapPView *pv_ptr, GdkPixbuf *src_pixbuf) { gap_pview_render_f_from_pixbuf(pv_ptr ,src_pixbuf ,GAP_STB_FLIP_NONE ,GAP_STB_FLIP_NONE ); } /* end gap_pview_render_from_pixbuf */ /* ------------------------------ * gap_pview_drop_repaint_buffers * ------------------------------ */ void gap_pview_drop_repaint_buffers(GapPView *pv_ptr) { if(pv_ptr->pixmap) g_object_unref(pv_ptr->pixmap); if(pv_ptr->pixbuf) g_object_unref(pv_ptr->pixbuf); pv_ptr->pixmap = NULL; pv_ptr->pixbuf = NULL; p_free_desaturated_area_data(pv_ptr); } /* end gap_pview_drop_repaint_buffers */ /* ------------------------------ * gap_pview_reset * ------------------------------ * reset/free precalculated stuff */ void gap_pview_reset(GapPView *pv_ptr) { if(pv_ptr == NULL) { return; } if(pv_ptr->src_col) g_free(pv_ptr->src_col); if(pv_ptr->pv_area_data) g_free(pv_ptr->pv_area_data); gap_pview_drop_repaint_buffers(pv_ptr); pv_ptr->src_col = NULL; pv_ptr->pv_area_data = NULL; pv_ptr->src_width = 0; pv_ptr->src_bpp = 0; pv_ptr->src_rowstride = 0; pv_ptr->use_pixmap_repaint = FALSE; pv_ptr->use_pixbuf_repaint = FALSE; } /* end gap_pview_reset */ /* ------------------------------ * gap_pview_set_size * ------------------------------ * set new preview size * and allocate buffers for src columns and row at previesize */ void gap_pview_set_size(GapPView *pv_ptr, gint pv_width, gint pv_height, gint pv_check_size) { g_return_if_fail (pv_width > 0 && pv_height > 0); if(pv_ptr->da_widget == NULL) { return; } gap_pview_reset(pv_ptr); gtk_widget_set_size_request (pv_ptr->da_widget, pv_width, pv_height); if(pv_ptr->aspect_frame) { gtk_aspect_frame_set (GTK_ASPECT_FRAME(pv_ptr->aspect_frame) ,0.5 /* align x centered */ ,0.5 /* align y centered */ , pv_width / pv_height , TRUE /* obey_child */ ); gtk_widget_set_size_request (pv_ptr->aspect_frame , pv_width+5 , (gdouble)(pv_width+5) * ( (gdouble)pv_height / (gdouble)pv_width) /* pv_height */ ); } pv_ptr->pv_width = pv_width; pv_ptr->pv_height = pv_height; pv_ptr->pv_check_size = pv_check_size; pv_ptr->pv_area_data = g_new ( guchar , pv_ptr->pv_height * pv_ptr->pv_width * pv_ptr->pv_bpp ); pv_ptr->src_col = g_new ( gint, pv_ptr->pv_width ); /* column fetch indexes foreach preview col */ if(pv_ptr->pv_desaturated_area_data) { g_free(pv_ptr->pv_desaturated_area_data); pv_ptr->pv_desaturated_area_data = NULL; } } /* end gap_pview_set_size */ /* ------------------------------ * gap_pview_new * ------------------------------ * pv_check_size is checkboard size in pixels * (for transparent pixels) */ GapPView * gap_pview_new(gint pv_width, gint pv_height, gint pv_check_size, GtkWidget *aspect_frame) { GapPView *pv_ptr; pv_ptr = g_malloc0(sizeof(GapPView)); pv_ptr->pv_bpp = 3; pv_ptr->da_widget = gtk_drawing_area_new (); pv_ptr->aspect_frame = aspect_frame; gap_pview_set_size(pv_ptr, pv_width, pv_height, pv_check_size); pv_ptr->use_pixmap_repaint = FALSE; pv_ptr->use_pixbuf_repaint = FALSE; pv_ptr->flip_status = GAP_STB_FLIP_NONE; pv_ptr->pixmap = NULL; pv_ptr->pixbuf = NULL; pv_ptr->desaturate_request = FALSE; return(pv_ptr); } /* end gap_pview_new */ /* ------------------------------ * gap_pview_repaint * ------------------------------ * Repaint (implicite conversion of gray_pixbuf) */ void gap_pview_repaint(GapPView *pv_ptr) { if(pv_ptr == NULL) { return; } if(pv_ptr->da_widget == NULL) { return; } if(pv_ptr->da_widget->window == NULL) { return; } if((pv_ptr->pixbuf != NULL) && (pv_ptr->use_pixbuf_repaint)) { if(pv_ptr->desaturate_request) { if(pv_ptr->pv_desaturated_area_data == NULL) { p_create_desaturated_buf_from_pixbuf(pv_ptr); } if(pv_ptr->pv_desaturated_area_data) { p_pview_repaint_desaturated(pv_ptr); return; } } gdk_draw_pixbuf( pv_ptr->da_widget->window , pv_ptr->da_widget->style->white_gc , pv_ptr->pixbuf , 0 /* gint src_x */ , 0 /* gint src_y */ , 0 /* gint dest_x */ , 0 /* gint dest_y */ , pv_ptr->pv_width , pv_ptr->pv_height , GDK_RGB_DITHER_NORMAL , 0 /* gint x_dither_offset */ , 0 /* gint y_dither_offset */ ); return; } if((pv_ptr->pv_area_data != NULL) && (!pv_ptr->use_pixmap_repaint)) { if(pv_ptr->desaturate_request) { if(pv_ptr->pv_desaturated_area_data == NULL) { p_create_desaturated_buf_from_area_data(pv_ptr); } if(pv_ptr->pv_desaturated_area_data) { p_pview_repaint_desaturated(pv_ptr); return; } } gdk_draw_rgb_image ( pv_ptr->da_widget->window , pv_ptr->da_widget->style->white_gc , 0 , 0 , pv_ptr->pv_width , pv_ptr->pv_height , GDK_RGB_DITHER_NORMAL , pv_ptr->pv_area_data , pv_ptr->pv_width * 3 ); return; } if(pv_ptr->pixmap != NULL) { gdk_draw_drawable(pv_ptr->da_widget->window ,pv_ptr->da_widget->style->white_gc ,pv_ptr->pixmap ,0 ,0 ,0 ,0 ,pv_ptr->pv_width ,pv_ptr->pv_height ); } } /* end gap_pview_repaint */ /* ------------------------------ * gap_pview_render_f_from_buf * ------------------------------ * render drawing_area widget from src_data buffer * quick scaling without any interpolation * is done to fit into preview size. * the GapPView structure holds * precalculations to allow faster scaling * in multiple calls when the src_data dimensions * do not change. * * IN: allow_grab_src_data * if TRUE, grant permission to grab the src_data for internal (refresh) usage * this is a performance feature with benefit for the case of matching buffer size * without alpha channel. * * return TRUE in case the src_data really was grabbed. * in such a case the caller MUST NOT change the src_data after * the call, and MUST NOT free the src_data buffer. * FALSE src_data was not grabbed, the caller is still responsible * to g_free the src_data * */ gboolean gap_pview_render_f_from_buf (GapPView *pv_ptr , guchar *src_data , gint src_width , gint src_height , gint src_bpp , gboolean allow_grab_src_data , gint32 flip_request , gint32 flip_status ) { register guchar *src, *dest; register gint col; gint row; gint ofs_green, ofs_blue, ofs_alpha; if(pv_ptr == NULL) { return FALSE; } if(pv_ptr->da_widget == NULL) { return FALSE; } if(pv_ptr->da_widget->window == NULL) { if(gap_debug) { printf("gap_pview_render_f_from_buf: drawing_area window pointer is NULL, cant render\n"); } return FALSE; } /* clear flag to let gap_pview_repaint procedure know * to use the pv_area_data rather than the pixmap for refresh */ pv_ptr->use_pixmap_repaint = FALSE; pv_ptr->use_pixbuf_repaint = FALSE; p_free_desaturated_area_data(pv_ptr); /* check for col and area_data buffers (allocate if needed) */ if ((pv_ptr->src_col == NULL) || (pv_ptr->pv_area_data == NULL)) { gint pv_width, pv_height, pv_check_size; pv_width = pv_ptr->pv_width; pv_height = pv_ptr->pv_height; pv_check_size = pv_ptr->pv_check_size; gap_pview_set_size(pv_ptr, pv_width, pv_height, pv_check_size); } /* init column fetch indexes array (only needed on src size changes) */ if((src_width != pv_ptr->src_width) || (src_bpp != pv_ptr->src_bpp)) { pv_ptr->src_width = src_width; pv_ptr->src_bpp = src_bpp; pv_ptr->src_rowstride = src_width * src_bpp; /* array of column fetch indexes for quick access * to the source pixels. (The source row may be larger or smaller than pv_ptr->pv_width) */ for ( col = 0; col < pv_ptr->pv_width; col++ ) { pv_ptr->src_col[ col ] = ( col * src_width / pv_ptr->pv_width ) * src_bpp; } } if(src_data == NULL) { /* if(gap_debug) printf("\n Paint it Black (NO src_data)\n"); */ /* Source is empty: draw a black preview */ memset(pv_ptr->pv_area_data, 0, pv_ptr->pv_height * pv_ptr->pv_width * pv_ptr->pv_bpp); gap_pview_repaint(pv_ptr); return FALSE; } if ((src_width == pv_ptr->pv_width) && (src_height == pv_ptr->pv_height) && (src_bpp == 3) && (flip_request == flip_status)) { /* if(gap_debug) printf("\n\n can use QUICK render\n"); */ /* for RGB src_data with matching size and without Alpha * we can render with just one call (fastest) */ if( allow_grab_src_data ) { /* the calling procedure has permitted to grab the src_data * for internal refresh usage. */ g_free(pv_ptr->pv_area_data); pv_ptr->pv_area_data = src_data; gap_pview_repaint(pv_ptr); return TRUE; } else { /* here we make a clean copy of src_data to pv_ptr->pv_area_data. * beacause the data might be needed * for refresh of the display (for an "expose" event handler procedure) */ memcpy(pv_ptr->pv_area_data, src_data, pv_ptr->pv_height * pv_ptr->pv_width * pv_ptr->pv_bpp); } gap_pview_repaint(pv_ptr); return FALSE; } ofs_green = 1; ofs_blue = 2; ofs_alpha = 3; if(src_bpp < 3) { ofs_green = 0; ofs_blue = 0; ofs_alpha = 1; } if((src_bpp ==3) || (src_bpp == 1)) { guchar *src_row; /* Source is Opaque (has no alpha) draw preview row by row */ dest = pv_ptr->pv_area_data; for ( row = 0; row < pv_ptr->pv_height; row++ ) { src_row = &src_data[CLAMP(((row * src_height) / pv_ptr->pv_height) , 0 , src_height) * pv_ptr->src_rowstride]; for ( col = 0; col < pv_ptr->pv_width; col++ ) { src = &src_row[ pv_ptr->src_col[col] ]; *(dest++) = src[0]; *(dest++) = src[ofs_green]; *(dest++) = src[ofs_blue]; } } } else { guchar *src_row; guchar alpha; gint ii; /* Source has alpha, draw preview row by row * show checkboard as background for transparent pixels */ dest = pv_ptr->pv_area_data; for ( row = 0; row < pv_ptr->pv_height; row++ ) { if ((row / pv_ptr->pv_check_size) & 1) { ii = 0;} else { ii = pv_ptr->pv_check_size; } src_row = &src_data[CLAMP(((row * src_height) / pv_ptr->pv_height) , 0 , src_height) * pv_ptr->src_rowstride]; for ( col = 0; col < pv_ptr->pv_width; col++ ) { src = &src_row[ pv_ptr->src_col[col] ]; alpha = src[ofs_alpha]; if(alpha > 244) { /* copy full (or nearly full opaque) pixels 1:1 * without MIXING with checkerboard background. * (speeds up rendering of opaque pixels) */ *(dest++) = src[0]; *(dest++) = src[ofs_green]; *(dest++) = src[ofs_blue]; } else { if(((col+ii) / pv_ptr->pv_check_size) & 1) { if(alpha < 10) { *(dest++) = PREVIEW_BG_GRAY1; *(dest++) = PREVIEW_BG_GRAY1; *(dest++) = PREVIEW_BG_GRAY1; } else { *(dest++) = MIX_CHANNEL (PREVIEW_BG_GRAY1, src[0], alpha); *(dest++) = MIX_CHANNEL (PREVIEW_BG_GRAY1, src[ofs_green], alpha); *(dest++) = MIX_CHANNEL (PREVIEW_BG_GRAY1, src[ofs_blue], alpha); } } else { if(alpha < 10) { *(dest++) = PREVIEW_BG_GRAY2; *(dest++) = PREVIEW_BG_GRAY2; *(dest++) = PREVIEW_BG_GRAY2; } else { *(dest++) = MIX_CHANNEL (PREVIEW_BG_GRAY2, src[0], alpha); *(dest++) = MIX_CHANNEL (PREVIEW_BG_GRAY2, src[ofs_green], alpha); *(dest++) = MIX_CHANNEL (PREVIEW_BG_GRAY2, src[ofs_blue], alpha); } } } } } } /* check and perform built in flip transformations */ { gint32 l_flip_to_perform; l_flip_to_perform = p_calculate_flip_request(pv_ptr, flip_request, flip_status); if(l_flip_to_perform != GAP_STB_FLIP_NONE) { p_render_thdata_as_flipped_pixbuf(pv_ptr ,l_flip_to_perform ); return FALSE; } } gap_pview_repaint(pv_ptr); return FALSE; } /* end gap_pview_render_f_from_buf */ /* ------------------------------ * gap_pview_render_f_from_image * ------------------------------ * render preview widget from image. * IMPORTANT: the image is scaled to preview size * and the visible layers in the image are merged together ! * If the supplied image shall stay unchanged, * you may use gap_pview_render_f_from_image_duplicate * * hint: call gtk_widget_queue_draw(pv_ptr->da_widget); * after this procedure to make the changes appear on screen. */ void gap_pview_render_f_from_image (GapPView *pv_ptr , gint32 image_id , gint32 flip_request , gint32 flip_status ) { gint32 layer_id; guchar *frame_data; GimpPixelRgn pixel_rgn; GimpDrawable *drawable; if(image_id < 0) { if(gap_debug) { printf("gap_pview_render_f_from_image: have no image, cant render image_id:%d\n" ,(int)image_id ); } return; } p_free_desaturated_area_data(pv_ptr); if((gimp_image_width(image_id) != pv_ptr->pv_width) || ( gimp_image_height(image_id) != pv_ptr->pv_height)) { gimp_image_scale(image_id, pv_ptr->pv_width, pv_ptr->pv_height); } /* workaround: gimp_image_merge_visible_layers * needs at least 2 layers to work without complaining * therefore add 2 full transparent dummy layers */ { gint32 l_layer_id; GimpImageBaseType l_type; l_type = gimp_image_base_type(image_id); l_type = (l_type * 2); /* convert from GimpImageBaseType to GimpImageType */ l_layer_id = gimp_layer_new(image_id, "dummy_01" , 4, 4 , l_type , 0.0 /* Opacity full transparent */ , 0 /* NORMAL */ ); gimp_image_add_layer(image_id, l_layer_id, 0); l_layer_id = gimp_layer_new(image_id, "dummy_02" , 4, 4 , l_type , 0.0 /* Opacity full transparent */ , 0 /* NORMAL */ ); gimp_image_add_layer(image_id, l_layer_id, 0); gimp_layer_resize_to_image_size(l_layer_id); } layer_id = gimp_image_merge_visible_layers (image_id, GIMP_CLIP_TO_IMAGE); drawable = gimp_drawable_get (layer_id); frame_data = g_malloc(drawable->width * drawable->height * drawable->bpp); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0 , drawable->width, drawable->height , FALSE /* dirty */ , FALSE /* shadow */ ); gimp_pixel_rgn_get_rect (&pixel_rgn, frame_data , 0 , 0 , drawable->width , drawable->height); { gboolean frame_data_was_grabbed; frame_data_was_grabbed = gap_pview_render_f_from_buf (pv_ptr , frame_data , drawable->width , drawable->height , drawable->bpp , TRUE /* allow_grab_src_data */ , flip_request , flip_status ); if(!frame_data_was_grabbed) g_free(frame_data); gimp_drawable_detach (drawable); } } /* end gap_pview_render_f_from_image */ /* --------------------------------------- * gap_pview_render_f_from_image_duplicate * --------------------------------------- * render preview widget from image. * This procedure creates a temorary copy of the image * for rendering of the preview. * NOTE: if the caller wants to render a temporary image * that is not needed anymore after the rendering, * the procedure gap_pview_render_f_from_image should be used * to avoid duplicating of the image. * * hint: call gtk_widget_queue_draw(pv_ptr->da_widget); * after this procedure to make the changes appear on screen. */ void gap_pview_render_f_from_image_duplicate (GapPView *pv_ptr , gint32 image_id , gint32 flip_request , gint32 flip_status ) { gint32 dup_image_id; dup_image_id = gimp_image_duplicate(image_id); gimp_image_undo_disable (dup_image_id); gap_pview_render_f_from_image(pv_ptr , dup_image_id , flip_request , flip_status ); gimp_image_delete(dup_image_id); } /* end gap_pview_render_f_from_image_duplicate */ /* ------------------------------ * gap_pview_render_default_icon * ------------------------------ */ void gap_pview_render_default_icon(GapPView *pv_ptr) { GtkWidget *widget; int w, h; int x1, y1, x2, y2; GdkPoint poly[6]; int foldh, foldw; int i; if(pv_ptr == NULL) { return; } if(pv_ptr->da_widget == NULL) { return; } if(pv_ptr->da_widget->window == NULL) { return; } widget = pv_ptr->da_widget; /* the drawing area */ /* set flag to let gap_pview_repaint procedure know * to use the pixmap rather than pv_area_data for refresh */ pv_ptr->use_pixmap_repaint = TRUE; pv_ptr->use_pixbuf_repaint = FALSE; p_free_desaturated_area_data(pv_ptr); if(pv_ptr->pixmap) { gdk_drawable_get_size (pv_ptr->pixmap, &w, &h); if((w != pv_ptr->pv_width) || (h != pv_ptr->pv_height)) { /* drop the old pixmap because of size missmatch */ g_object_unref(pv_ptr->pixmap); pv_ptr->pixmap = NULL; } } w = pv_ptr->pv_width; h = pv_ptr->pv_height; if(pv_ptr->pixmap == NULL) { pv_ptr->pixmap = gdk_pixmap_new (widget->window ,pv_ptr->pv_width ,pv_ptr->pv_height ,-1 /* use same depth as widget->window */ ); } x1 = 2; y1 = h / 8 + 2; x2 = w - w / 8 - 2; y2 = h - 2; gdk_draw_rectangle (pv_ptr->pixmap, widget->style->bg_gc[GTK_STATE_NORMAL], 1, 0, 0, w, h); /* gdk_draw_rectangle (pv_ptr->pixmap, widget->style->black_gc, 0, x1, y1, (x2 - x1), (y2 - y1)); */ foldw = w / 4; foldh = h / 4; x1 = w / 8 + 2; y1 = 2; x2 = w - 2; y2 = h - h / 8 - 2; poly[0].x = x1 + foldw; poly[0].y = y1; poly[1].x = x1 + foldw; poly[1].y = y1 + foldh; poly[2].x = x1; poly[2].y = y1 + foldh; poly[3].x = x1; poly[3].y = y2; poly[4].x = x2; poly[4].y = y2; poly[5].x = x2; poly[5].y = y1; gdk_draw_polygon (pv_ptr->pixmap, widget->style->white_gc, 1, poly, 6); gdk_draw_line (pv_ptr->pixmap, widget->style->black_gc, x1, y1 + foldh, x1, y2); gdk_draw_line (pv_ptr->pixmap, widget->style->black_gc, x1, y2, x2, y2); gdk_draw_line (pv_ptr->pixmap, widget->style->black_gc, x2, y2, x2, y1); gdk_draw_line (pv_ptr->pixmap, widget->style->black_gc, x1 + foldw, y1, x2, y1); for (i = 0; i < foldw; i++) { gdk_draw_line (pv_ptr->pixmap, widget->style->black_gc, x1 + i, y1 + foldh, x1 + i, (foldw == 1) ? y1 : (y1 + (foldh - (foldh * i) / (foldw - 1)))); } gdk_draw_drawable(widget->window ,widget->style->black_gc ,pv_ptr->pixmap ,0 ,0 ,0 ,0 ,w ,h ); } /* end gap_pview_render_default_icon */ #ifdef GAP_PVIEW_USE_GDK_PIXBUF_RENDERING /* ------------------------------ * gap_pview_render_f_from_pixbuf (slow) * ------------------------------ * render drawing_area widget from src_pixbuf buffer * scaling and flattening against checkerboard background * is done implicite using GDK-pixbuf procedures * * Thumbnails at size 128 rendered to Widget Size 256x256 pixels * at my Pentium IV 2600 MHZ * can be Played at Speed of 98 Frames/sec without dropping frames. * * The other Implementation without GDK-pixbuf procedures * is faster (at least on my machine), therefore GAP_PVIEW_USE_GDK_PIXBUF_RENDERING * is NOT defined per default. */ void gap_pview_render_f_from_pixbuf (GapPView *pv_ptr , GdkPixbuf *src_pixbuf , gint32 flip_request , gint32 flip_status ) { static int l_checksize_tab[17] = { 2, 4, 8, 8, 16, 16, 16, 32, 32, 32, 32, 32, 32, 64, 64, 64, 64 }; int l_check_size; /* printf("gap_pview_render_f_from_pixbuf --- USE GDK-PIXBUF procedures\n"); */ if(pv_ptr == NULL) { return; } if(pv_ptr->da_widget == NULL) { return; } if(pv_ptr->da_widget->window == NULL) { if(gap_debug) { printf("gap_pview_render_f_from_pixbuf: drawing_area window pointer is NULL, cant render\n"); } return ; } if(src_pixbuf == NULL) { if(gap_debug) { printf("gap_pview_render_f_from_pixbuf: src_pixbuf is NULL, cant render\n"); } return ; } /* clear flag to let gap_pview_repaint procedure know * to use the pixbuf rather than pv_area_data or pixmap for refresh */ pv_ptr->use_pixmap_repaint = FALSE; pv_ptr->use_pixbuf_repaint = TRUE; p_free_desaturated_area_data(pv_ptr); /* l_check_size must be a power of 2 (using fixed size for 1.st test) */ l_check_size = l_checksize_tab[MIN((pv_ptr->pv_check_size >> 2), 8)]; if(pv_ptr->pixbuf) { /* free old (refresh) pixbuf if there is one */ g_object_unref(pv_ptr->pixbuf); } /* scale and flatten the pixbuf */ pv_ptr->pixbuf = gdk_pixbuf_composite_color_simple( src_pixbuf , (int) pv_ptr->pv_width , (int) pv_ptr->pv_height , GDK_INTERP_NEAREST , 255 /* overall_alpha */ , (int)l_check_size /* power of 2 required */ , PREVIEW_BG_GRAY1_GDK , PREVIEW_BG_GRAY2_GDK ); if(gap_debug) { int nchannels; int rowstride; int width; int height; guchar *pix_data; gboolean has_alpha; width = gdk_pixbuf_get_width(pv_ptr->pixbuf); height = gdk_pixbuf_get_height(pv_ptr->pixbuf); nchannels = gdk_pixbuf_get_n_channels(pv_ptr->pixbuf); pix_data = gdk_pixbuf_get_pixels(pv_ptr->pixbuf); has_alpha = gdk_pixbuf_get_has_alpha(pv_ptr->pixbuf); rowstride = gdk_pixbuf_get_rowstride(pv_ptr->pixbuf); printf("gap_pview_render_f_from_pixbuf (AFTER SCALE/FLATTEN):\n"); printf(" l_check_size: %d (%d)\n", (int)l_check_size, pv_ptr->pv_check_size); printf(" width: %d\n", (int)width ); printf(" height: %d\n", (int)height ); printf(" nchannels: %d\n", (int)nchannels ); printf(" pix_data: %d\n", (int)pix_data ); printf(" has_alpha: %d\n", (int)has_alpha ); printf(" rowstride: %d\n", (int)rowstride ); } { gint32 l_flip_to_perform; l_flip_to_perform = p_calculate_flip_request(pv_ptr, flip_request, flip_status); if(l_flip_to_perform != GAP_STB_FLIP_NONE) { p_replace_pixbuf_by_flipped_pixbuf(pv_ptr, l_flip_to_perform); } } gap_pview_repaint(pv_ptr); } /* end gap_pview_render_f_from_pixbuf */ #else /* ------------------------------ * gap_pview_render_f_from_pixbuf (fast) * ------------------------------ * render drawing_area widget from src_pixbuf buffer. * * scaling and flattening against checkerboard background * is done by calling gap_pview_render_f_from_buf. * * The scaling in gap_pview_render_f_from_buf is optimized for speed * especially when both src and dest sizes are the same as in the * previous call. * * * Thumbnails at size 128 rendered to Widget Size 256x256 pixels * at my Pentium IV 2600 MHZ * can be Played at Speed of 136 Frames/sec without dropping frames * */ void gap_pview_render_f_from_pixbuf (GapPView *pv_ptr , GdkPixbuf *src_pixbuf , gint32 flip_request , gint32 flip_status ) { /* printf("gap_pview_render_f_from_pixbuf >>NO<< USE OF GDK-PIXBUF procedures\n"); */ if(src_pixbuf == NULL) { if(gap_debug) { printf("gap_pview_render_f_from_pixbuf: src_pixbuf is NULL, cant render\n"); } return ; } else { int nchannels; int width; int height; guchar *pix_data; width = gdk_pixbuf_get_width(src_pixbuf); height = gdk_pixbuf_get_height(src_pixbuf); nchannels = gdk_pixbuf_get_n_channels(src_pixbuf); pix_data = gdk_pixbuf_get_pixels(src_pixbuf); gap_pview_render_f_from_buf(pv_ptr , pix_data , width , height , nchannels , FALSE /* DONT allow_grab_src_data */ , flip_request , flip_status ); } } /* end gap_pview_render_f_from_pixbuf */ #endif /* ------------------------------ * p_pixmap_data_destructor * ------------------------------ * a wrapper to g_free * just for printing debug output at testing */ static void p_pixmap_data_destructor(gpointer data) { if(gap_debug) { printf(" -- DESTRUCTOR p_pixmap_data_destructor called\n"); printf(" -- data: %d\n", (int)data); } g_free(data); } /* ------------------------------ * gap_pview_get_repaint_pixbuf * ------------------------------ * return the repaint buffer as GdkPixbuf, * or NULL if no buffer is available. */ GdkPixbuf * gap_pview_get_repaint_pixbuf(GapPView *pv_ptr) { int bits_per_sample; int rowstride; int width; int height; gboolean has_alpha; guchar *pixel_data_src; guchar *pixel_data_copy; if (pv_ptr == NULL) { return(NULL); } bits_per_sample = 8; rowstride = pv_ptr->pv_width * pv_ptr->pv_bpp; has_alpha = FALSE; width = pv_ptr->pv_width; height = pv_ptr->pv_height; pixel_data_src = NULL; if ((pv_ptr->use_pixbuf_repaint) && (pv_ptr->pixbuf)) { pixel_data_src = gdk_pixbuf_get_pixels(pv_ptr->pixbuf); rowstride = gdk_pixbuf_get_rowstride(pv_ptr->pixbuf); bits_per_sample = gdk_pixbuf_get_bits_per_sample(pv_ptr->pixbuf); has_alpha = gdk_pixbuf_get_has_alpha(pv_ptr->pixbuf); } if ((pv_ptr->use_pixmap_repaint) && (pv_ptr->pixmap) && (pixel_data_src == NULL)) { gdk_drawable_get_size (pv_ptr->pixmap, &width, &height); // pixel_data_src = ???; // TODO: how to make duplicate of pixeldata for GdkPixmap ? // not critical, the pixmap is currently used only for the default icon // that is renderd in case no useful pixeldata is available. // The caller has to deal with returned NULL pointer anyway. return(NULL); } if((pv_ptr->pv_area_data) && (pixel_data_src == NULL)) { pixel_data_src = pv_ptr->pv_area_data; } if(pixel_data_src) { size_t pixel_data_size = pv_ptr->pv_height * pv_ptr->pv_width * pv_ptr->pv_bpp; pixel_data_copy = g_new ( guchar, pixel_data_size ); memcpy(pixel_data_copy, pixel_data_src, pixel_data_size); return(gdk_pixbuf_new_from_data( pixel_data_copy , GDK_COLORSPACE_RGB , has_alpha , bits_per_sample , width , height , rowstride , (GdkPixbufDestroyNotify)p_pixmap_data_destructor /* destroy_fn */ , pixel_data_copy /* gpointer destroy_fn_data */ )); } return (NULL); } /* end gap_pview_get_repaint_pixbuf */ /* ------------------------------ * gap_pview_get_repaint_thdata * ------------------------------ * return the repaint buffer as thumbnail data (guchar RGB), * or NULL if no buffer is available. */ guchar * gap_pview_get_repaint_thdata(GapPView *pv_ptr /* IN */ , gint32 *th_size /* OUT */ , gint32 *th_width /* OUT */ , gint32 *th_height /* OUT */ , gint32 *th_bpp /* OUT */ , gboolean *th_has_alpha /* OUT */ ) { int bits_per_sample; int rowstride; int width; int height; gboolean has_alpha; guchar *pixel_data_src; guchar *pixel_data_copy; if (pv_ptr == NULL) { return(NULL); } bits_per_sample = 8; rowstride = pv_ptr->pv_width * pv_ptr->pv_bpp; has_alpha = FALSE; width = pv_ptr->pv_width; height = pv_ptr->pv_height; pixel_data_src = NULL; if ((pv_ptr->use_pixbuf_repaint) && (pv_ptr->pixbuf)) { pixel_data_src = gdk_pixbuf_get_pixels(pv_ptr->pixbuf); rowstride = gdk_pixbuf_get_rowstride(pv_ptr->pixbuf); bits_per_sample = gdk_pixbuf_get_bits_per_sample(pv_ptr->pixbuf); has_alpha = gdk_pixbuf_get_has_alpha(pv_ptr->pixbuf); } if ((pv_ptr->use_pixmap_repaint) && (pv_ptr->pixmap) && (pixel_data_src == NULL)) { gdk_drawable_get_size (pv_ptr->pixmap, &width, &height); // pixel_data_src = ???; // TODO: how to make duplicate of pixeldata for GdkPixmap ? // not critical, the pixmap is currently used only for the default icon // that is renderd in case no useful pixeldata is available. // The caller has to deal with returned NULL pointer anyway. return(NULL); } if((pv_ptr->pv_area_data) && (pixel_data_src == NULL)) { pixel_data_src = pv_ptr->pv_area_data; } if(pixel_data_src) { size_t pixel_data_size = pv_ptr->pv_height * pv_ptr->pv_width * pv_ptr->pv_bpp; pixel_data_copy = g_new ( guchar, pixel_data_size ); memcpy(pixel_data_copy, pixel_data_src, pixel_data_size); *th_size = width * height * pv_ptr->pv_bpp; *th_width = width; *th_height = height; *th_bpp = pv_ptr->pv_bpp; *th_has_alpha = has_alpha; return (pixel_data_copy); } return (NULL); } /* end gap_pview_get_repaint_thdata */ gimp-gap-2.6.0+dfsg.orig/gap/gap_story_render_audio.c0000644000175000017500000015644211212030253022423 0ustar thibautthibaut/* gap_story_render_audio.c * * * GAP storyboard audio rendering. * */ /* * 2006.06.25 hof - created (moved stuff from the former gap_gve_story modules to this new module) * */ #include /* SYTEM (UNIX) includes */ #include #include #include #include #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "gap-intl.h" #include "libgimp/gimp.h" #include "gap_libgapbase.h" #include "gap_libgimpgap.h" #include "gap_audio_util.h" #include "gap_audio_wav.h" #include "gap_story_sox.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 #include "gap_story_file.h" #include "gap_layer_copy.h" #include "gap_story_render_processor.h" #include "gap_lib_common_defs.h" /* if G_BYTE_ORDER == G_BIG_ENDIAN */ #if G_BYTE_ORDER == G_LITTLE_ENDIAN typedef union t_wav_16bit_int { gint16 value; guint16 uvalue; struct { guchar lsb; guchar msb; } bytes; } t_wav_16bit_int; #else typedef union t_wav_16bit_int { gint16 value; struct { guchar msb; guchar lsb; } bytes; } t_wav_16bit_int; #endif #define AUDIO_SEGMENT_SIZE 4000000 #define MAX_AUD_CACHE_ELEMENTS 999 extern int gap_debug; /* 1 == print debug infos , 0 dont print debug infos */ static GapStoryRenderAudioCache *global_audcache = NULL; static void p_drop_audio_cache_elem1(GapStoryRenderAudioCache *audcache); static GapStoryRenderAudioCacheElem *p_load_cache_audio( char* filename, gint32 *audio_id, gint32 *aud_bytelength, gint32 seek_idx); static void p_find_min_max_aud_tracknumbers(GapStoryRenderAudioRangeElem *aud_list , gint32 *lowest_tracknr , gint32 *highest_tracknr); static void p_get_audio_sample(GapStoryRenderVidHandle *vidhand /* IN */ ,gint32 track /* IN */ ,gint32 master_sample_idx /* IN */ ,gdouble *sample_left /* OUT (prescaled at local volume) */ ,gdouble *sample_right /* OUT (prescaled at local volume)*/ ); static void p_mix_audio(FILE *fp /* IN: NULL: dont write to file */ ,gint16 *bufferl /* IN: NULL: dont write to buffer */ ,gint16 *bufferr /* IN: NULL: dont write to buffer */ ,GapStoryRenderVidHandle *vidhand ,gdouble aud_total_sec ,gdouble *mix_scale /* OUT */ ); static void p_check_audio_peaks(GapStoryRenderVidHandle *vidhand ,gdouble aud_total_sec ,gdouble *mix_scale /* OUT */ ); #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT static void p_extract_audioblock(t_GVA_Handle *gvahand , FILE *fp_wav , gdouble samples_to_extract , int audio_channels , int sample_rate , GapStoryRenderVidHandle *vidhand /* for progress */ ); static void p_extract_audiopart(t_GVA_Handle *gvahand , char *wavfilename , gdouble min_play_sec , gdouble max_play_sec , GapStoryRenderVidHandle *vidhand /* for progress */ ); #endif /* ---------------------------------------------------- * p_drop_audio_cache_elem1 * ---------------------------------------------------- */ static void p_drop_audio_cache_elem1(GapStoryRenderAudioCache *audcache) { GapStoryRenderAudioCacheElem *ac_ptr; if(audcache) { ac_ptr = audcache->ac_list; if(ac_ptr) { if(gap_debug) printf("p_drop_audio_cache_elem1 delete:%s (audio_id:%d)\n", ac_ptr->filename, (int)ac_ptr->audio_id); g_free(ac_ptr->aud_data); g_free(ac_ptr->filename); audcache->ac_list = (GapStoryRenderAudioCacheElem *)ac_ptr->next; g_free(ac_ptr); } } } /* end p_drop_audio_cache_elem1 */ /* ---------------------------------------------------- * gap_story_render_drop_audio_cache * ---------------------------------------------------- */ void gap_story_render_drop_audio_cache(void) { GapStoryRenderAudioCache *audcache; if(gap_debug) printf("gap_story_render_drop_audio_cache START\n"); audcache = global_audcache; if(audcache) { while(audcache->ac_list) { p_drop_audio_cache_elem1(audcache); } } if(gap_debug) printf("gap_story_render_drop_audio_cache END\n"); } /* end gap_story_render_drop_audio_cache */ /* ---------------------------------------------------- * gap_story_render_remove_tmp_audiofiles * ---------------------------------------------------- */ void gap_story_render_remove_tmp_audiofiles(GapStoryRenderVidHandle *vidhand) { GapStoryRenderAudioRangeElem *aud_elem; if(gap_debug) { printf("gap_story_render_remove_tmp_audiofiles START\n"); } for(aud_elem = vidhand->aud_list; aud_elem != NULL; aud_elem = (GapStoryRenderAudioRangeElem *)aud_elem->next) { if(aud_elem->tmp_audiofile) { if(gap_debug) { printf("gap_story_render_remove_tmp_audiofiles tmp_audiofile: %s\n" , aud_elem->tmp_audiofile); } /* delete tmp_audiofile if still exists * (more aud_elements may refere to the same tmp_audiofile) */ if(g_file_test(aud_elem->tmp_audiofile, G_FILE_TEST_EXISTS)) { if(gap_debug) { printf("gap_story_render_remove_tmp_audiofiles removing: %s\n" , aud_elem->tmp_audiofile); } g_remove(aud_elem->tmp_audiofile); } g_free(aud_elem->tmp_audiofile); aud_elem->tmp_audiofile = NULL; } } } /* end gap_story_render_remove_tmp_audiofiles */ /* ---------------------------------------------------- * p_load_cache_audio * ---------------------------------------------------- */ static GapStoryRenderAudioCacheElem * p_load_cache_audio( char* filename, gint32 *audio_id, gint32 *aud_bytelength, gint32 seek_idx) { gint32 l_idx; gint32 l_audio_id; GapStoryRenderAudioCacheElem *ac_ptr; GapStoryRenderAudioCacheElem *ac_last; GapStoryRenderAudioCacheElem *ac_new; GapStoryRenderAudioCache *audcache; guchar *aud_data; if(filename == NULL) { printf("p_load_cache_audio: ** ERROR cant load filename == NULL!\n"); return NULL; } if(global_audcache == NULL) { /* init the global_mage cache */ global_audcache = g_malloc0(sizeof(GapStoryRenderAudioCache)); global_audcache->ac_list = NULL; global_audcache->nextval_audio_id = 0; global_audcache->max_aud_cache = MAX_AUD_CACHE_ELEMENTS; } audcache = global_audcache; ac_last = audcache->ac_list; l_idx = 0; for(ac_ptr = audcache->ac_list; ac_ptr != NULL; ac_ptr = (GapStoryRenderAudioCacheElem *)ac_ptr->next) { l_idx++; if(strcmp(filename, ac_ptr->filename) == 0) { /* audio found in cache, can skip load */ *audio_id = ac_ptr->audio_id; *aud_bytelength = ac_ptr->aud_bytelength; return(ac_ptr); } ac_last = ac_ptr; } aud_data = g_malloc(AUDIO_SEGMENT_SIZE); *aud_bytelength = gap_file_get_filesize(filename); ac_new = NULL; if(aud_data != NULL) { l_audio_id = global_audcache->nextval_audio_id; global_audcache->nextval_audio_id++; *audio_id = l_audio_id; ac_new = g_malloc0(sizeof(GapStoryRenderAudioCacheElem)); ac_new->filename = g_strdup(filename); ac_new->audio_id = l_audio_id; ac_new->aud_data = aud_data; ac_new->aud_bytelength = *aud_bytelength; ac_new->segment_startoffset = seek_idx; ac_new->segment_bytelength = gap_file_load_file_segment(filename ,ac_new->aud_data ,seek_idx ,AUDIO_SEGMENT_SIZE ); if(audcache->ac_list == NULL) { audcache->ac_list = ac_new; /* 1.st elem starts the list */ } else { ac_last->next = (GapStoryRenderAudioCacheElem *)ac_new; /* add new elem at end of the cache list */ } if(l_idx > audcache->max_aud_cache) { /* chache list has more elements than desired, * drop the 1.st (oldest) entry in the chache list */ /* p_drop_audio_cache_elem1(audcache); */ /* keep all audio files cached */ } } return(ac_new); } /* end p_load_cache_audio */ /* ---------------------------------------------------- * p_find_min_max_aud_tracknumbers * ---------------------------------------------------- * findout the lowest and highest audio track number used * in the audiorange list */ static void p_find_min_max_aud_tracknumbers(GapStoryRenderAudioRangeElem *aud_list , gint32 *lowest_tracknr , gint32 *highest_tracknr) { GapStoryRenderAudioRangeElem *aud_elem; *lowest_tracknr = GAP_STB_MAX_AUD_TRACKS; *highest_tracknr = -1; for(aud_elem = aud_list; aud_elem != NULL; aud_elem = (GapStoryRenderAudioRangeElem *)aud_elem->next) { if (aud_elem->track > *highest_tracknr) { *highest_tracknr = aud_elem->track; } if (aud_elem->track < *lowest_tracknr) { *lowest_tracknr = aud_elem->track; } } if(gap_debug) printf("p_find_min_aud_vid_tracknumbers: min:%d max:%d\n", (int)*lowest_tracknr, (int)*highest_tracknr); } /* end p_find_min_max_aud_tracknumbers */ /* --------------------------------- * p_get_audio_sample * --------------------------------- * - scann the aud_list to findout * audiofile that is played at desired track * at desired sample_index position. * - return the sample (amplitude) at desired sample_index position * both for left and reight stereo channel. * the sample is already scaled to local input track * volume settings (and loacl fade_in, fade_out effects) */ static void p_get_audio_sample(GapStoryRenderVidHandle *vidhand /* IN */ ,gint32 track /* IN */ ,gint32 master_sample_idx /* IN */ ,gdouble *sample_left /* OUT (prescaled at local volume) */ ,gdouble *sample_right /* OUT (prescaled at local volume)*/ ) { GapStoryRenderAudioRangeElem *aud_elem; GapStoryRenderAudioCacheElem *ac_elem; gint32 l_group_samples; gint32 l_byte_idx; gint32 l_samp_idx; /* local track sepcific sample index */ t_wav_16bit_int l_left; t_wav_16bit_int l_right; gdouble l_vol; gint32 l_range_samples; l_group_samples = 0; /* we are using master_sample_idx to access all other samples. * (this is faster than using time specificaton in secs (gdouble position) * but requires that all samples are using the same samplerate.) */ for(aud_elem = vidhand->aud_list; aud_elem != NULL; aud_elem = (GapStoryRenderAudioRangeElem *)aud_elem->next) { if(aud_elem->track == track) { l_range_samples = aud_elem->range_samples + MAX(0, aud_elem->wait_until_samples - l_group_samples); if (master_sample_idx < l_group_samples + l_range_samples) { if(aud_elem->aud_type == GAP_AUT_SILENCE) { *sample_left = 0.0; *sample_right = 0.0; return; } /* found the range that contains the sample at the requested index and track */ l_samp_idx = master_sample_idx - l_group_samples; /* fetch sample (and convert to 16bit stereo) */ l_byte_idx = aud_elem->byteoffset_rangestart + (l_samp_idx * aud_elem->bytes_per_sample); /* check for audio data (if not already there then load to memory) */ if(aud_elem->aud_data == NULL) { char *l_audiofile; gint32 l_seek_idx; /* make sure segment start is header offset + a multiple of 4 */ l_seek_idx = (l_byte_idx - aud_elem->byteoffset_data) / 4; l_seek_idx = aud_elem->byteoffset_data + (l_seek_idx * 4); l_audiofile = aud_elem->audiofile; if(aud_elem->tmp_audiofile) { l_audiofile = aud_elem->tmp_audiofile; } if(gap_debug) printf("BEFORE p_load_cache_audio %s\n", l_audiofile); ac_elem = p_load_cache_audio(l_audiofile , &aud_elem->audio_id , &aud_elem->aud_bytelength , l_seek_idx ); aud_elem->ac_elem = ac_elem; aud_elem->aud_data = ac_elem->aud_data; if(aud_elem->aud_data == NULL) { char *l_errtxt; l_errtxt = g_strdup_printf(_("cant load: %s to memory"), l_audiofile); gap_story_render_set_stb_error(vidhand->sterr, l_errtxt); g_free(l_errtxt); /* ERROR , audiofile was not loaded ! */ *sample_left = 0.0; *sample_right = 0.0; return; } } /* check if byte_index is in the current segment */ ac_elem = aud_elem->ac_elem; if(ac_elem == NULL) { printf("p_get_audio_sample: ERROR no audiosegement loaded for %s\n", aud_elem->audiofile); return; } if((l_byte_idx < ac_elem->segment_startoffset) || (l_byte_idx >= ac_elem->segment_startoffset + ac_elem->segment_bytelength)) { /* the requested byte_index is outside of the currently loaded segment * we have to load the matching audio segment of the file */ gint32 l_seek_idx; if(gap_debug) printf("SEGM_RELOAD l_byte_idx:%d startoffset:%d segm_size:%d\n", (int)l_byte_idx, (int)ac_elem->segment_startoffset ,(int)ac_elem->segment_bytelength ); /* make sure segment start is header offset + a multiple of 4 */ l_seek_idx = (l_byte_idx - aud_elem->byteoffset_data) / 4; l_seek_idx = aud_elem->byteoffset_data + (l_seek_idx * 4); ac_elem->segment_startoffset = l_seek_idx; ac_elem->segment_bytelength = gap_file_load_file_segment(ac_elem->filename ,ac_elem->aud_data ,l_seek_idx ,AUDIO_SEGMENT_SIZE ); } /* reduce byte_index before accessing audio segmentdata */ l_byte_idx -= ac_elem->segment_startoffset; if((l_byte_idx < 0) || (l_byte_idx >= ac_elem->segment_bytelength /*aud_elem->aud_bytelength */ )) { printf("p_get_audio_sample: **ERROR INDEX OVERFLOW: %d (segment_bytelength: %d aud_bytelength: %d)\n" " file:%s\n" , (int)l_byte_idx , (int)ac_elem->segment_bytelength , (int)aud_elem->aud_bytelength , ac_elem->filename ); return; } if(aud_elem->channels == 2) /* STEREO */ { if(aud_elem->bytes_per_sample == 4) { /* fetch 16bit stereosample (byteorder lLrR lLrR) */ l_left.bytes.lsb = aud_elem->aud_data[l_byte_idx]; l_left.bytes.msb = aud_elem->aud_data[l_byte_idx +1]; l_right.bytes.lsb = aud_elem->aud_data[l_byte_idx +2]; l_right.bytes.msb = aud_elem->aud_data[l_byte_idx +3]; } else { /* fetch 8bit stereosample (byteorder LR LR) */ gap_audio_util_dbl_sample_8_to_16(aud_elem->aud_data[l_byte_idx] ,&l_left.bytes.lsb ,&l_left.bytes.msb ); gap_audio_util_dbl_sample_8_to_16(aud_elem->aud_data[l_byte_idx +1] ,&l_right.bytes.lsb ,&l_right.bytes.msb ); } } else /* MONO */ { if(aud_elem->bytes_per_sample == 2) { /* printf("l_byte_idx: %d %02x %02x\n", (int)l_byte_idx * ,(int)aud_elem->aud_data[l_byte_idx] * ,(int)aud_elem->aud_data[l_byte_idx +1]); */ /* fetch 16bit momosample (byteorder lL lL) */ l_left.bytes.lsb = aud_elem->aud_data[l_byte_idx]; l_left.bytes.msb = aud_elem->aud_data[l_byte_idx +1]; } else { /* fetch 8bit monosample */ gap_audio_util_dbl_sample_8_to_16(aud_elem->aud_data[l_byte_idx] ,&l_left.bytes.lsb ,&l_left.bytes.msb ); } l_right.value = l_left.value; } /* set volume, respecting fade effects */ l_vol = aud_elem->volume; if( aud_elem->fade_in_samples > 0) { if(l_samp_idx < aud_elem->fade_in_samples) { l_vol = ((l_vol - aud_elem->volume_start) * ((gdouble)l_samp_idx / (gdouble)aud_elem->fade_in_samples)) + aud_elem->volume_start; } } if( aud_elem->fade_out_samples > 0) { if(l_samp_idx > (l_range_samples - aud_elem->fade_out_samples)) { l_vol = ((l_vol - aud_elem->volume_end) * ((gdouble)(l_range_samples - l_samp_idx) / (gdouble)aud_elem->fade_out_samples)) + aud_elem->volume_end; } } *sample_left = l_left.value * l_vol; *sample_right = l_right.value * l_vol; return; } l_group_samples += l_range_samples; } } /* the requested position is larger than the length of the requested track. * return silence in this case. */ *sample_left = 0.0; *sample_right = 0.0; return; } /* end p_get_audio_sample */ /* --------------------------------- * p_mix_audio * --------------------------------- * mix all audiotracks to one * composite audio track, * and calculate mix scale (to fit into 16bit int) * optional write the mixed audio to wav file * (bytesrquence LLRRLLRR) * or write to separate buffers for left and right stereo channel * or write nothing at all. */ static void p_mix_audio(FILE *fp /* IN: NULL: dont write to file */ ,gint16 *bufferl /* IN: NULL: dont write to buffer */ ,gint16 *bufferr /* IN: NULL: dont write to buffer */ ,GapStoryRenderVidHandle *vidhand ,gdouble aud_total_sec ,gdouble *mix_scale /* OUT */ ) { gint32 l_track; gint32 l_min_track; gint32 l_max_track; gdouble l_max_peak; gdouble l_peak_posl; gdouble l_peak_posr; gdouble l_peak_negl; gdouble l_peak_negr; gdouble l_mixl; gdouble l_mixr; gdouble l_sample_left; gdouble l_sample_right; gdouble l_master_scale; gint32 l_master_sample_idx; gint32 l_max_sample_idx; l_peak_posl = 0.0; l_peak_posr = 0.0; l_peak_negl = 0.0; l_peak_negr = 0.0; l_sample_left = 0.0; l_sample_right = 0.0; l_master_scale = vidhand->master_volume; if((fp) || (bufferl) || (bufferr)) { l_master_scale = *mix_scale * vidhand->master_volume; } l_max_sample_idx = aud_total_sec * vidhand->master_samplerate; p_find_min_max_aud_tracknumbers(vidhand->aud_list, &l_min_track, &l_max_track); for(l_master_sample_idx = 0; l_master_sample_idx < l_max_sample_idx; l_master_sample_idx++) { l_mixl = 0.0; l_mixr = 0.0; *vidhand->progress = (gdouble)l_master_sample_idx / (gdouble)l_max_sample_idx; /* mix samples of all tracks at current index * (track specific volume scaling is already done in p_get_audio_sample) */ for(l_track=l_min_track; l_track <= l_max_track; l_track++) { p_get_audio_sample(vidhand ,l_track ,l_master_sample_idx ,&l_sample_left ,&l_sample_right ); l_mixl += l_sample_left; l_mixr += l_sample_right; } l_mixl *= l_master_scale; l_mixr *= l_master_scale; if(fp) { /* wav databyte sequence is LLRR LLRR LLRR ... */ gap_audio_wav_write_gint16(fp, (gint16)l_mixl); gap_audio_wav_write_gint16(fp, (gint16)l_mixr); } if(bufferl) { bufferl[l_master_sample_idx] = l_mixl; } if(bufferr) { bufferr[l_master_sample_idx] = l_mixr; } l_peak_posl = MAX(l_mixl,l_peak_posl); l_peak_posr = MAX(l_mixr,l_peak_posr); l_peak_negl = MIN(l_mixl,l_peak_negl); l_peak_negr = MIN(l_mixr,l_peak_negr); } l_max_peak = MAX(l_peak_posl, l_peak_posr); l_max_peak = MAX(l_max_peak, (-1.0 * l_peak_negl)); l_max_peak = MAX(l_max_peak, (-1.0 * l_peak_negr)); if (l_max_peak <= 32767) { /* max peak fits into 16 bit integer, * (we dont need scale down) */ *mix_scale = 1.0; } else { /* must scale down ALL sample amplitudes * to fit into 16 bit integer */ *mix_scale = 32767 / l_max_peak; } } /* end p_mix_audio */ /* --------------------------------- * p_check_audio_peaks * --------------------------------- */ static void p_check_audio_peaks(GapStoryRenderVidHandle *vidhand ,gdouble aud_total_sec ,gdouble *mix_scale /* OUT */ ) { /* perform mix without any output, * to findout peaks and calculate * mix_scale (how to scale to fit the result into 16 bit int) */ p_mix_audio(NULL, NULL, NULL, vidhand, aud_total_sec, mix_scale); } /* end p_check_audio_peaks */ #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* ---------------------------------------------------- * p_extract_audioblock * ---------------------------------------------------- * extract an audio block in size of samples_to_extract of a videofile * if fp_wav is not NULL write the extracted data as 16bit samples to the file */ static void p_extract_audioblock(t_GVA_Handle *gvahand , FILE *fp_wav , gdouble samples_to_extract , int audio_channels , int sample_rate , GapStoryRenderVidHandle *vidhand ) { static unsigned short *left_ptr; static unsigned short *right_ptr; unsigned short *l_lptr; unsigned short *l_rptr; long l_to_read; long l_left_to_read; long l_block_read; gint32 l_ii; if(gap_debug) printf("p_extract_audioblock samples_to_extract:%d\n", (int)samples_to_extract); /* audio block read (blocksize covers playbacktime for 250 frames */ l_left_to_read = (long)samples_to_extract; l_block_read = (double)(250.0) / (double)gvahand->framerate * (double)sample_rate; l_to_read = MIN(l_left_to_read, l_block_read); /* allocate audio buffers */ left_ptr = g_malloc0((sizeof(short) * l_block_read) + 16); right_ptr = g_malloc0((sizeof(short) * l_block_read) + 16); while(l_to_read > 0) { l_lptr = left_ptr; l_rptr = right_ptr; /* read the audio data of channel 0 (left or mono) */ GVA_get_audio(gvahand ,l_lptr /* Pointer to pre-allocated buffer if int16's */ ,1 /* Channel to decode */ ,(gdouble)l_to_read /* Number of samples to decode */ ,GVA_AMOD_CUR_AUDIO /* read from current audio position (and advance) */ ); if(audio_channels > 1) { /* read the audio data of channel 2 (right) * NOTE: GVA_get_audio has advanced the stream position, * so we have to set GVA_AMOD_REREAD to read from * the same startposition as for channel 1 (left). */ GVA_get_audio(gvahand ,l_rptr /* Pointer to pre-allocated buffer if int16's */ ,2 /* Channel to decode */ ,l_to_read /* Number of samples to decode */ ,GVA_AMOD_REREAD /* read from */ ); } l_left_to_read -= l_to_read; if(fp_wav) { /* write 16 bit wave datasamples * sequence mono: (lo, hi) * sequence stereo: (lo_left, hi_left, lo_right, hi_right) */ for(l_ii=0; l_ii < l_to_read; l_ii++) { gap_audio_wav_write_gint16(fp_wav, *l_lptr); l_lptr++; if(audio_channels > 1) { gap_audio_wav_write_gint16(fp_wav, *l_rptr); l_rptr++; } } } l_to_read = MIN(l_left_to_read, l_block_read); /* handle progress */ *vidhand->progress = (gdouble) (MAX((samples_to_extract - l_left_to_read), 0)) / (gdouble) (MAX(samples_to_extract, 1)) ; if(vidhand->status_msg) { if(fp_wav) { g_snprintf(vidhand->status_msg, vidhand->status_msg_len , _("extracting audio to tmp audiofile")); } else { g_snprintf(vidhand->status_msg, vidhand->status_msg_len , _("seeking audio")); } } } /* free audio buffers */ g_free(left_ptr); g_free(right_ptr); if(gap_debug) printf("p_extract_audioblock: END\n"); } /* end p_extract_audioblock */ #endif #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* ---------------------------------------------------- * p_extract_audiopart * ---------------------------------------------------- * extract the audiopart of a videofile as RIFF .WAV file * the extracted audio range is limited by min_play_sec and max_play_sec * * call this procedure with t_GVA_Handle that is NOT NULL (after successful open) */ static void p_extract_audiopart(t_GVA_Handle *gvahand , char *wavfilename , gdouble min_play_sec , gdouble max_play_sec , GapStoryRenderVidHandle *vidhand /* for progress */ ) { static int l_audio_channels; static int l_sample_rate; gdouble samples_to_extract; gdouble samples_to_skip; if(gap_debug) { printf("p_extract_audiopart: START\n"); } l_audio_channels = gvahand->audio_cannels; l_sample_rate = gvahand->samplerate; samples_to_extract = (max_play_sec - min_play_sec) * (gdouble)l_sample_rate; if(samples_to_extract <= 0) { return; } samples_to_skip = min_play_sec * (gdouble)l_sample_rate; GVA_seek_audio(gvahand, 0.0, GVA_UPOS_SECS); if(l_audio_channels > 0) { FILE *fp_wav; fp_wav = g_fopen(wavfilename, "wb"); if(fp_wav) { gint32 l_bytes_per_sample; if(l_audio_channels == 1) { l_bytes_per_sample = 2;} /* mono */ else { l_bytes_per_sample = 4;} /* stereo */ /* write the header */ gap_audio_wav_write_header(fp_wav , (gint32)(samples_to_extract) , l_audio_channels /* cannels 1 or 2 */ , l_sample_rate , l_bytes_per_sample , 16 /* 16 bit sample resolution */ ); if(gap_debug) { printf("samples_to_skip:%d\n", (int)samples_to_skip); } if(samples_to_skip > 0) { p_extract_audioblock(gvahand ,NULL /* dont write to file */ ,samples_to_skip ,l_audio_channels ,l_sample_rate ,vidhand ); } if(gap_debug) { printf("samples_to_extract:%d\n", (int)samples_to_extract); } p_extract_audioblock(gvahand ,fp_wav /* now write to file */ ,samples_to_extract ,l_audio_channels ,l_sample_rate ,vidhand ); /* close wavfile */ fclose(fp_wav); } } if(gap_debug) { printf("p_extract_audiopart: END\n"); } } /* end p_extract_audiopart */ #endif /* ----------------------------------- * gap_story_render_audio_add_aud_list * ----------------------------------- */ void gap_story_render_audio_add_aud_list(GapStoryRenderVidHandle *vidhand, GapStoryRenderAudioRangeElem *aud_elem) { GapStoryRenderAudioRangeElem *aud_listend; if((vidhand) && (aud_elem)) { if(vidhand->parsing_section == NULL) { printf("** INTERNAL ERROR parsing_section is NULL\n"); return; } aud_listend = vidhand->aud_list; if (vidhand->parsing_section->aud_list == NULL) { /* 1. element (or returned list) starts aud_list */ vidhand->parsing_section->aud_list = aud_elem; vidhand->aud_list = aud_elem; } else { /* link aud_elem (that can be a single ement or list) to the end of aud_list */ aud_listend = vidhand->parsing_section->aud_list; while(aud_listend->next != NULL) { aud_listend = (GapStoryRenderAudioRangeElem *)aud_listend->next; } aud_listend->next = (GapStoryRenderAudioRangeElem *)aud_elem; } } } /* end gap_story_render_audio_add_aud_list */ /* ---------------------------------------------------- * gap_story_render_audio_new_audiorange_element * ---------------------------------------------------- * allocate a new GapStoryRenderAudioRangeElem for storyboard processing * - check audiofile * if create_audio_tmp_files == TRUE do audio extract from videofiles * and perform samplerate conversions where the results will be * temporary RIFF Wav format audiofiles. */ GapStoryRenderAudioRangeElem * gap_story_render_audio_new_audiorange_element(GapStoryRenderAudioType aud_type ,gint32 track ,const char *audiofile ,gint32 master_samplerate ,gdouble play_from_sec ,gdouble play_to_sec ,gdouble volume_start ,gdouble volume ,gdouble volume_end ,gdouble fade_in_sec ,gdouble fade_out_sec ,char *util_sox ,char *util_sox_options ,const char *storyboard_file /* IN: NULL if no storyboard file is used */ ,const char *preferred_decoder ,GapStoryRenderAudioRangeElem *known_aud_list /* NULL or list of already known ranges */ ,GapStoryRenderErrors *sterr /* element to store Error/Warning report */ ,gint32 seltrack /* IN: select audiotrack number 1 upto 99 for GAP_AUT_MOVIE */ ,gboolean create_audio_tmp_files ,gdouble min_play_sec ,gdouble max_play_sec ,GapStoryRenderVidHandle *vidhand /* for progress */ ) { GapStoryRenderAudioRangeElem *aud_known; GapStoryRenderAudioRangeElem *aud_elem; gboolean l_audscan_required; if(gap_debug) { printf("\ngap_story_render_audio_new_audiorange_element: START aud_type:%d\n", (int)aud_type); printf(" track:%d:\n", (int)track); printf(" create_audio_tmp_files:%d:\n", (int)create_audio_tmp_files); printf(" play_from_sec:%.4f:\n", (float)play_from_sec); printf(" play_to_sec:%.4f:\n", (float)play_to_sec); printf(" volume_start:%.4f:\n", (float)volume_start); printf(" volume:%.4f:\n", (float)volume); printf(" volume_end:%.4f:\n", (float)volume_end); printf(" fade_in_sec:%.4f:\n", (float)fade_in_sec); printf(" fade_out_sec:%.4f:\n", (float)fade_out_sec); printf(" min_play_sec:%.4f:\n", (float)min_play_sec); printf(" max_play_sec:%.4f:\n", (float)max_play_sec); if(audiofile) printf(" audiofile:%s:\n", audiofile); if(storyboard_file) printf(" storyboard_file:%s:\n", storyboard_file); if(preferred_decoder) printf(" preferred_decoder:%s:\n", preferred_decoder); } l_audscan_required = TRUE; aud_elem = g_malloc0(sizeof(GapStoryRenderAudioRangeElem)); aud_elem->aud_type = aud_type; aud_elem->track = track; aud_elem->tmp_audiofile = NULL; aud_elem->audiofile = NULL; aud_elem->samplerate = master_samplerate; aud_elem->channels = 2; aud_elem->bytes_per_sample = 4; aud_elem->samples = master_samplerate * 9999; aud_elem->max_playtime_sec = 0.0; aud_elem->wait_untiltime_sec = 0.0; aud_elem->wait_until_samples = 0.0; aud_elem->range_playtime_sec = 0.0; aud_elem->play_from_sec = play_from_sec; aud_elem->play_to_sec = play_to_sec; aud_elem->volume_start = volume_start; aud_elem->volume = volume; aud_elem->volume_end = volume_end; aud_elem->fade_in_sec = fade_in_sec; aud_elem->fade_out_sec = fade_out_sec; aud_elem->audio_id = -1; aud_elem->aud_data = NULL; aud_elem->ac_elem = NULL; aud_elem->aud_bytelength = 0; aud_elem->range_samples = 0; aud_elem->fade_in_samples = 0; aud_elem->fade_out_samples = 0; aud_elem->byteoffset_rangestart = 0; aud_elem->byteoffset_data = 44; /* default value, will fit for most WAV files */ aud_elem->gvahand = NULL; aud_elem->seltrack = seltrack; aud_elem->next = NULL; if(audiofile) { aud_elem->audiofile = gap_file_make_abspath_filename(audiofile, storyboard_file); if(!g_file_test(aud_elem->audiofile, G_FILE_TEST_EXISTS)) /* check for regular file */ { char *l_errtxt; l_errtxt = g_strdup_printf(_("file not found: %s for audioinput"), aud_elem->audiofile); gap_story_render_set_stb_error(sterr, l_errtxt); g_free(l_errtxt); return(NULL); } if (known_aud_list == NULL) { if(gap_debug) { printf("gap_story_render_audio_new_audiorange_element: list of known audiofiles is empty (NULL)\n"); } } /* check the list for known audioranges * if audiofile is already known, we can skip the file scan * (that can save lot of time when the file must be converted or resampled) */ for(aud_known = known_aud_list; aud_known != NULL; aud_known = (GapStoryRenderAudioRangeElem *)aud_known->next) { if(aud_known->audiofile) { if(gap_debug) { printf("gap_story_render_audio_new_audiorange_element: check known audio_id:%d audiofile:%s\n" , aud_elem->audio_id , aud_known->audiofile ); } if((strcmp(aud_elem->audiofile, aud_known->audiofile) == 0) && (aud_elem->aud_type == aud_type)) { if(gap_debug) { printf("gap_story_render_audio_new_audiorange_element: Range is already known audiofile:%s\n", aud_known->audiofile); } aud_elem->tmp_audiofile = g_strdup(aud_known->tmp_audiofile); aud_elem->samplerate = aud_known->samplerate; aud_elem->channels = aud_known->channels; aud_elem->bytes_per_sample = aud_known->bytes_per_sample; aud_elem->samples = aud_known->samples; aud_elem->max_playtime_sec = aud_known->max_playtime_sec; aud_elem->byteoffset_data = aud_known->byteoffset_data; l_audscan_required = FALSE; break; } } else { if(gap_debug) { printf("gap_story_render_audio_new_audiorange_element: check known audio_id:%d audiofile: is NULL\n" ,aud_elem->audio_id ); } } } if(l_audscan_required) { #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if(aud_type == GAP_AUT_MOVIE) { t_GVA_Handle *gvahand; if(preferred_decoder) { gvahand = GVA_open_read_pref(aud_elem->audiofile , 1 /*videotrack */ , seltrack , preferred_decoder , FALSE /* use MMX if available (disable_mmx == FALSE) */ ); } else { gvahand = GVA_open_read(aud_elem->audiofile, 1 /*videotrack */, seltrack); } if(gvahand) { GVA_set_fcache_size(gvahand, GAP_STB_RENDER_GVA_FRAMES_TO_KEEP_CACHED); aud_elem->samplerate = gvahand->samplerate; aud_elem->channels = gvahand->audio_cannels; aud_elem->bytes_per_sample = gvahand->audio_cannels * 2; /* API operates with 16 bit per sample */ aud_elem->samples = gvahand->total_aud_samples; /* sometimes this is not an exact value, but just a guess */ aud_elem->byteoffset_data = 0; /* no headeroffset for audiopart loaded from videofiles */ if(gap_debug) { printf("AFTER GVA_open_read: %s\n", aud_elem->audiofile); printf(" samplerate: %d\n", (int)aud_elem->samplerate ); printf(" channels: %d\n", (int)aud_elem->channels ); printf(" bytes_per_sample:%d\n", (int)aud_elem->bytes_per_sample ); printf(" samples: %d\n", (int)aud_elem->samples ); } if(create_audio_tmp_files) { if ((aud_elem->samplerate == master_samplerate) && ((aud_elem->channels == 2) || (aud_elem->channels == 1))) { /* audio part of the video is OK, extract 1:1 as wavfile */ aud_elem->tmp_audiofile = gimp_temp_name("tmp.wav"); if(gap_debug) { printf("Extracting Audiopart as file:%s\n", aud_elem->tmp_audiofile); } p_extract_audiopart(gvahand , aud_elem->tmp_audiofile , min_play_sec , max_play_sec , vidhand ); GVA_close(gvahand); } else { char *l_wavfilename; long samplerate; long channels; long bytes_per_sample; long bits; long samples; int l_rc; /* extract the audiopart for resample */ l_wavfilename = gimp_temp_name("tmp.wav"); aud_elem->tmp_audiofile = gimp_temp_name("tmp.wav"); if(gap_debug) { printf("Resample Audiopart in file:%s outfile: %s\n" , l_wavfilename , aud_elem->tmp_audiofile ); } p_extract_audiopart(gvahand , l_wavfilename , min_play_sec , max_play_sec , vidhand ); GVA_close(gvahand); if(vidhand->status_msg) { g_snprintf(vidhand->status_msg, vidhand->status_msg_len , _("converting audio (via external programm)") ); } /* fake some dummy progress */ *vidhand->progress = 0.05; if(gap_debug) { printf("calling externeal Resample program: %s %s\n" , util_sox , util_sox_options ); } gap_story_sox_exec_resample(l_wavfilename ,aud_elem->tmp_audiofile ,master_samplerate ,util_sox /* the extern converter program */ ,util_sox_options /* options for the converter */ ); /* check again (with the resampled copy in tmp_audiofile * that should have been created by gap_story_sox_exec_resample * (if convert was OK) */ l_rc = gap_audio_wav_file_check(aud_elem->tmp_audiofile , &samplerate, &channels , &bytes_per_sample, &bits, &samples); /* delete the extracted wavfile after resampling (keep just the resampled variant) */ g_remove(l_wavfilename); g_free(l_wavfilename); if((l_rc == 0) && ((bits == 16) || (bits == 8)) && ((channels == 2) || (channels == 1)) && (samplerate == master_samplerate)) { /* audio file is OK */ aud_elem->samplerate = samplerate; aud_elem->channels = channels; aud_elem->bytes_per_sample = bytes_per_sample; aud_elem->samples = samples; aud_elem->byteoffset_data = 44; /* TODO: gap_audio_wav_file_check should return the real offset * of the 1.st audio_sample databyte in the wav file. */ } else { char *l_errtxt; /* conversion failed, cant use that file, delete tmp_audiofile now */ if(aud_elem->tmp_audiofile) { g_remove(aud_elem->tmp_audiofile); g_free(aud_elem->tmp_audiofile); aud_elem->tmp_audiofile = NULL; } if(gap_debug) { printf("AUD 1 channels:%d samplerate:%d master_samplerate:%d\n" ,(int)channels ,(int)samplerate ,(int)master_samplerate ); } l_errtxt = g_strdup_printf(_("cant use file: %s as audioinput"), aud_elem->audiofile); gap_story_render_set_stb_error(sterr, l_errtxt); g_free(l_errtxt); return(NULL); } } } else { GVA_close(gvahand); } /* end if(create_audio_tmp_files) */ } else { char *l_errtxt; l_errtxt = g_strdup_printf(_("ERROR file: %s is not a supported videoformat"), aud_elem->audiofile); gap_story_render_set_stb_error(sterr, l_errtxt); g_free(l_errtxt); } } #endif if(aud_type == GAP_AUT_AUDIOFILE) { if(g_file_test(aud_elem->audiofile, G_FILE_TEST_EXISTS)) { long samplerate; long channels; long bytes_per_sample; long bits; long samples; int l_rc; l_rc = gap_audio_wav_file_check(aud_elem->audiofile , &samplerate, &channels , &bytes_per_sample, &bits, &samples); if(gap_debug) { printf("AFTER gap_audio_wav_file_check: %s\n", aud_elem->audiofile); printf(" samplerate: %d\n", (int)samplerate ); printf(" channels: %d\n", (int)channels ); printf(" bytes_per_sample:%d\n", (int)bytes_per_sample ); printf(" bits: %d\n", (int) bits); printf(" samples: %d\n", (int)samples ); } if(l_rc == 0) { aud_elem->samplerate = samplerate; aud_elem->channels = channels; aud_elem->bytes_per_sample = bytes_per_sample; aud_elem->samples = samples; aud_elem->byteoffset_data = 44; } if((l_rc == 0) && ((bits == 16) || (bits == 8)) && ((channels == 2) || (channels == 1)) && (samplerate == master_samplerate)) { /* audio file is OK */ aud_elem->samplerate = samplerate; aud_elem->channels = channels; aud_elem->bytes_per_sample = bytes_per_sample; aud_elem->samples = samples; aud_elem->byteoffset_data = 44; /* TODO: gap_audio_wav_file_check should return the real offset * of the 1.st audio_sample databyte in the wav file. */ } else { if(create_audio_tmp_files) { if(vidhand->status_msg) { g_snprintf(vidhand->status_msg, vidhand->status_msg_len , _("converting audio (via external programm)") ); } /* fake some dummy progress */ *vidhand->progress = 0.05; /* aud_elem->tmp_audiofile = g_strdup_printf("%s.tmp.wav", aud_elem->audiofile); */ aud_elem->tmp_audiofile = gimp_temp_name("tmp.wav"); gap_story_sox_exec_resample(aud_elem->audiofile ,aud_elem->tmp_audiofile ,master_samplerate ,util_sox /* the extern converter program */ ,util_sox_options /* options for the converter */ ); /* check again (with the resampled copy in tmp_audiofile * that should have been created by gap_story_sox_exec_resample * (if convert was OK) */ l_rc = gap_audio_wav_file_check(aud_elem->tmp_audiofile , &samplerate, &channels , &bytes_per_sample, &bits, &samples); if((l_rc == 0) && ((bits == 16) || (bits == 8)) && ((channels == 2) || (channels == 1)) && (samplerate == master_samplerate)) { /* audio file is OK */ aud_elem->samplerate = samplerate; aud_elem->channels = channels; aud_elem->bytes_per_sample = bytes_per_sample; aud_elem->samples = samples; aud_elem->byteoffset_data = 44; /* TODO: gap_audio_wav_file_check should return the real offset * of the 1.st audio_sample databyte in the wav file. */ } else { char *l_errtxt; /* conversion failed, cant use that file, delete tmp_audiofile now */ if(aud_elem->tmp_audiofile) { g_remove(aud_elem->tmp_audiofile); g_free(aud_elem->tmp_audiofile); aud_elem->tmp_audiofile = NULL; } l_errtxt = g_strdup_printf(_("cant use file: %s as audioinput"), aud_elem->audiofile); gap_story_render_set_stb_error(sterr, l_errtxt); g_free(l_errtxt); if(gap_debug) { printf("gap_story_render_audio_new_audiorange_element CONVERSION FAILED.\n"); } return(NULL); } } } } } } } if((aud_elem->samplerate > 0) && (aud_elem->channels > 0)) { /* calculate playtime of the full audiofile */ aud_elem->max_playtime_sec = (((gdouble)aud_elem->samples / (gdouble)aud_elem->channels) / (gdouble)aud_elem->samplerate); } else { aud_elem->max_playtime_sec = 0.0; } /* from video extracted audio clips are not extracted in full videolength * (the start-part in length of min_play_sec is truncated at extract) * therefore we have to reduce the play range parameters by min_play_sec * to transform for reference in the extracted temp audiofile */ if(min_play_sec > 0.0) { aud_elem->play_from_sec -= min_play_sec; aud_elem->play_to_sec -= min_play_sec; } /* constraint range times to max_playtime_sec (full length of the audiofile in secs) */ /* NO more constraint to max_playtime_sec */ /* aud_elem->play_to_sec = CLAMP(aud_elem->play_to_sec, 0.0, aud_elem->max_playtime_sec);*/ aud_elem->play_from_sec = CLAMP(aud_elem->play_from_sec, 0.0, aud_elem->play_to_sec); aud_elem->range_playtime_sec = aud_elem->play_to_sec - aud_elem->play_from_sec; aud_elem->fade_in_sec = CLAMP(aud_elem->fade_in_sec, 0.0, aud_elem->range_playtime_sec); aud_elem->fade_out_sec = CLAMP(aud_elem->fade_out_sec, 0.0, aud_elem->range_playtime_sec); aud_elem->range_samples = aud_elem->range_playtime_sec * aud_elem->samplerate; aud_elem->fade_in_samples = aud_elem->fade_in_sec * aud_elem->samplerate; aud_elem->fade_out_samples = aud_elem->fade_out_sec * aud_elem->samplerate; { gint32 boff; /* byte offset truncated to bytes_per_sample boundary */ boff = (aud_elem->play_from_sec * aud_elem->samplerate * aud_elem->bytes_per_sample) / aud_elem->bytes_per_sample; aud_elem->byteoffset_rangestart = (boff * aud_elem->bytes_per_sample) + aud_elem->byteoffset_data; } if(gap_debug) { printf("gap_story_render_audio_new_audiorange_element NORMAL END\n"); } return(aud_elem); } /* end gap_story_render_audio_new_audiorange_element */ /* ----------------------------------------- * gap_story_render_audio_calculate_playtime * ----------------------------------------- * - check all audio tracks for audio playtime * set *aud_total_sec to the playtime of the * logest audio track playtime. */ void gap_story_render_audio_calculate_playtime(GapStoryRenderVidHandle *vidhand, gdouble *aud_total_sec) { GapStoryRenderAudioRangeElem *aud_elem; gint32 l_track; gint32 l_min_track; gint32 l_max_track; gdouble l_tracktime; gdouble l_aud_total_sec; l_aud_total_sec = 0; p_find_min_max_aud_tracknumbers(vidhand->aud_list, &l_min_track, &l_max_track); for(l_track=l_min_track; l_track <= l_max_track; l_track++) { l_tracktime = 0; for(aud_elem = vidhand->aud_list; aud_elem != NULL; aud_elem = aud_elem->next) { if(aud_elem->track == l_track) { if(aud_elem->wait_untiltime_sec > 0) { l_tracktime = MAX(l_tracktime, aud_elem->wait_untiltime_sec); } l_tracktime += aud_elem->range_playtime_sec; } } l_aud_total_sec = MAX(l_aud_total_sec, l_tracktime); } *aud_total_sec = l_aud_total_sec; } /* gap_story_render_audio_calculate_playtime */ /* ------------------------------------------------- * gap_story_render_audio_create_composite_audiofile * ------------------------------------------------- * create the composite audio as mix of all audio channels * and write result to file in WAV format. */ gboolean gap_story_render_audio_create_composite_audiofile(GapStoryRenderVidHandle *vidhand , char *comp_audiofile ) { gdouble l_mix_scale; gdouble l_aud_total_sec; FILE *l_fp; gboolean l_retval; if(gap_debug) { printf("gap_story_render_audio_create_composite_audiofile START comp_audiofile: %s\n" , comp_audiofile); } l_retval = FALSE; gap_story_render_audio_calculate_playtime(vidhand, &l_aud_total_sec); if(vidhand->status_msg) { g_snprintf(vidhand->status_msg, vidhand->status_msg_len, _("checking audio peaks")); } *vidhand->progress = 0.0; if(gap_debug) { printf("gap_story_render_audio_create_composite_audiofile CHECKING AUDIO PEAKS %s\n" , comp_audiofile); } p_check_audio_peaks(vidhand, l_aud_total_sec, &l_mix_scale); if(gap_debug) { printf("gap_story_render_audio_create_composite_audiofile WRITE COMPOSITE AUDIO FILE %s\n" , comp_audiofile); } l_fp = g_fopen(comp_audiofile, "wb"); if (l_fp) { gdouble l_nsamples; l_nsamples = l_aud_total_sec * (gdouble)vidhand->master_samplerate; gap_audio_wav_write_header(l_fp , (gint32)l_nsamples , 2 /* cannels */ , vidhand->master_samplerate , 4 /* 4bytes for 16bit stereo */ , 16 /* 16 bit sample resolution */ ); if(vidhand->status_msg) { g_snprintf(vidhand->status_msg, vidhand->status_msg_len, _("writing composite audiofile")); } *vidhand->progress = 0.0; p_mix_audio(l_fp, NULL, NULL, vidhand, l_aud_total_sec, &l_mix_scale); fclose(l_fp); if(gap_debug) { printf("gap_story_render_audio_create_composite_audiofile COMPOSITE AUDIO FILE written OK file:%s\n" , comp_audiofile); } l_retval = TRUE; } else { char *l_errtext; l_errtext = g_strdup_printf(_("cant write audio to file: %s "), comp_audiofile); gap_story_render_set_stb_error(vidhand->sterr, l_errtext); printf("gap_story_render_audio_create_composite_audiofile failed to write COMPOSITE AUDIO FILE file:%s\n **ERROR: %s\n" , comp_audiofile , l_errtext ); g_free(l_errtext); } if(vidhand->status_msg) { g_snprintf(vidhand->status_msg, vidhand->status_msg_len, _("ready")); } return(l_retval); } /* end gap_story_render_audio_create_composite_audiofile */ gimp-gap-2.6.0+dfsg.orig/gap/gap_fmac_base.c0000644000175000017500000005161711212030253020421 0ustar thibautthibaut/* gap_fmac_base.c * 2006.12.11 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * - filtermacro execution backend procedures. * * WARNING: * filtermacros are a temporary solution, useful for animations * but do not expect support for filtermacros in future releases of GIMP-GAP * because GIMP may have real makro features in the future ... * * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* SYTEM (UNIX) includes */ #include #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" #include "libgimp/gimpui.h" /* GAP includes */ #include "config.h" #include "gap-intl.h" #include "gap_lib.h" #include "gap_val_file.h" #include "gap_filter.h" #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" extern int gap_debug; /* ==0 ... dont print debug infos */ typedef struct FMacElem { char *filtername; gboolean assigned_flag; gboolean varying_flag; char *buffer_from; gint32 buffer_from_length; char *buffer_to; char *iteratorname; void *next; } FMacElem; typedef struct FMacLine { char *filtername; char *paramdata; gint32 paramlength; } FMacLine; static void p_print_and_free_msg(char *msg, GimpRunMode run_mode); gint p_fmac_execute(GimpRunMode run_mode, gint32 image_id, gint32 drawable_id , const char *filtermacro_file1 , const char *filtermacro_file2 , gdouble current_step , gint32 total_steps ); /* -------------------- * p_print_and_free_msg * -------------------- */ static void p_print_and_free_msg(char *msg, GimpRunMode run_mode) { if(run_mode == GIMP_RUN_INTERACTIVE) { g_message(msg); } printf("%s\n", msg); g_free(msg); } /* end p_print_and_free_msg */ /* ------------------------ * p_free_fmac_line * ------------------------ */ static void p_free_fmac_line(FMacLine *fmac_line) { if(fmac_line->filtername) { g_free(fmac_line->filtername); } if(fmac_line->paramdata) { g_free(fmac_line->paramdata); } g_free(fmac_line); } /* end p_free_fmac_line */ /* ------------------------ * p_scan_fmac_line * ------------------------ * parse one filtermacro file line * example line: * "plug_in_xyz" 2 0x01 0xF2 * line contains filtername (quotes are mandatory) * length # decimal digits * and databyte_array[length] # hexadecimal digits */ static FMacLine * p_scan_fmac_line(GapValTextFileLines *txf_ptr, GimpRunMode run_mode, const char *filtermacro_file) { gchar *l_buf; FMacLine *fmac_line; if(gap_debug) { printf("p_scan_fmac_line: %s\n" , txf_ptr->line ); } l_buf = txf_ptr->line; fmac_line = NULL; /* handle lines starting with double quotes */ if (l_buf[0] == '"') { char *l_plugin_name; char *l_scan_ptr; char *l_scan_ptr2; gint l_idx; /* scan plugin-name */ l_scan_ptr=&l_buf[0]; l_plugin_name = &l_buf[1]; for(l_idx=1; l_idx < 4000;l_idx++) { if (l_buf[l_idx] == '"') { l_buf[l_idx] = '\0'; l_scan_ptr=&l_buf[l_idx+1]; break; } } if(gap_debug) { printf("p_scan_fmac_line: ##l_plugin_name:%s\n", l_plugin_name); } fmac_line = g_malloc0(sizeof(FMacLine)); fmac_line->filtername = gimp_canonicalize_identifier(l_plugin_name); /* scan for data length */ fmac_line->paramlength = strtol(l_scan_ptr, &l_scan_ptr2, 10); if (l_scan_ptr != l_scan_ptr2) { if(gap_debug) { printf("p_scan_fmac_line: ##paramlength:%d\n" , (int)fmac_line->paramlength ); } fmac_line->paramdata = g_malloc0(fmac_line->paramlength); l_scan_ptr = l_scan_ptr2; for(l_idx=0; l_idx < fmac_line->paramlength;l_idx++) { long int l_data_byte; gchar *l_msg; l_data_byte = strtol(l_scan_ptr, &l_scan_ptr2, 16); /* if(gap_debug) printf("p_fmac_execute: l_data_byte:%d\n", (int)l_data_byte); */ if ((l_data_byte < 0) || (l_data_byte > 255) || (l_scan_ptr == l_scan_ptr2)) { p_free_fmac_line(fmac_line); l_msg = g_strdup_printf (_("filtermacro_file: '%s' is corrupted, could not scan databytes") , filtermacro_file); p_print_and_free_msg(l_msg, run_mode); return (NULL); } fmac_line->paramdata[l_idx] = l_data_byte; l_scan_ptr = l_scan_ptr2; } } } if(gap_debug) { if(fmac_line) { printf("p_scan_fmac_line: END fmac_line:%d filtername:%s paramlength:%d\n" , (int)fmac_line , fmac_line->filtername , (int)fmac_line->paramlength ); } else { printf("p_scan_fmac_line: END fmac_line:%d\n" , (int)fmac_line ); } } return(fmac_line); } /* end p_scan_fmac_line */ /* ------------------------ * p_build_fmac_list * ------------------------ * build the list by loading all records from the 1st filtermacro file. * init both buffer_from and buffer_to with the same set of filter parameters. * 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 * p_build_fmac_list(const char *filtermacro_file, GimpRunMode run_mode) { FMacElem *fmac_root; FMacElem *fmac_tail; gchar *l_msg; GapValTextFileLines *txf_ptr; GapValTextFileLines *txf_ptr_root; fmac_root = NULL; fmac_tail = NULL; if(gap_debug) { printf("p_build_fmac_list: START filtermacro_file:%s\n" ,filtermacro_file ); } if (!gap_fmac_chk_filtermacro_file(filtermacro_file)) { l_msg = g_strdup_printf(_("file: %s is not a filtermacro file !") , filtermacro_file); p_print_and_free_msg(l_msg, run_mode); return NULL; } /* process filtermacro file (scann line by line and add filtername * and params to the fmac_root list) */ txf_ptr_root = gap_val_load_textfile(filtermacro_file); for(txf_ptr = txf_ptr_root; txf_ptr != NULL; txf_ptr = (GapValTextFileLines *) txf_ptr->next) { FMacLine *fmacLine; fmacLine = p_scan_fmac_line(txf_ptr, run_mode, filtermacro_file); if (fmacLine) { FMacElem *fmac_elem; gint l_count; /* create fmac_elem according to scanned fmac line */ fmac_elem = g_malloc0(sizeof(FMacElem)); fmac_elem->filtername = gimp_canonicalize_identifier(fmacLine->filtername); 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->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); p_free_fmac_line(fmacLine); /* add fmac_elem at end of fmac_root list. */ if (fmac_root == NULL) { fmac_root = fmac_elem; fmac_tail = fmac_elem; } else { fmac_tail->next = fmac_elem; fmac_tail = fmac_elem; } } } if(txf_ptr_root) { gap_val_free_textfile_lines(txf_ptr_root); } if(gap_debug) { printf("p_build_fmac_list: END fmac_root:%d filtermacro_file:%s\n" ,(int)fmac_root ,filtermacro_file ); } return fmac_root; } /* end p_build_fmac_list */ /* ------------------------ * p_merge_fmac_list * ------------------------ * 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. * 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) { gchar *l_msg; GapValTextFileLines *txf_ptr; GapValTextFileLines *txf_ptr_root; if(gap_debug) { printf("p_merge_fmac_list: fmac_root:%d filtermacro_file:%s\n" ,(int)fmac_root ,filtermacro_file ); } if (!gap_fmac_chk_filtermacro_file(filtermacro_file)) { l_msg = g_strdup_printf(_("file: %s is not a filtermacro file !") , filtermacro_file); p_print_and_free_msg(l_msg, run_mode); return (FALSE); } /* process filtermacro file (scann line by line and overwrite * the 2nd parameter set where filtername matches */ txf_ptr_root = gap_val_load_textfile(filtermacro_file); for(txf_ptr = txf_ptr_root; txf_ptr != NULL; txf_ptr = (GapValTextFileLines *) txf_ptr->next) { FMacLine *fmacLine; fmacLine = p_scan_fmac_line(txf_ptr, run_mode, filtermacro_file); if (fmacLine) { FMacElem *fmac_elem; for(fmac_elem = fmac_root; fmac_elem != NULL; fmac_elem = (FMacElem *)fmac_elem->next) { if((strcmp(fmac_elem->filtername, fmacLine->filtername) == 0) && (fmac_elem->assigned_flag == FALSE)) { if (fmac_elem->buffer_from_length == fmacLine->paramlength) { /* overwrite param data */ memcpy(fmac_elem->buffer_to, fmacLine->paramdata, fmacLine->paramlength); fmac_elem->assigned_flag = TRUE; if(fmac_elem->iteratorname != NULL) { fmac_elem->varying_flag = TRUE; } } else { printf("ERROR: parmlength %d does not match %d for filter:%s\n" ,(int)fmacLine->paramlength ,(int)fmac_elem->buffer_from_length ,fmacLine->filtername ); } break; } } p_free_fmac_line(fmacLine); } } if(txf_ptr_root) { gap_val_free_textfile_lines(txf_ptr_root); } return (TRUE); } /* end p_merge_fmac_list */ /* ---------------------------- * p_fmac_execute_single_filter * ---------------------------- */ static void p_fmac_execute_single_filter(GimpRunMode run_mode, gint32 image_id, gint32 drawable_id , FMacElem *fmac_elem , gdouble current_step , gint32 total_steps ) { gchar *l_msg; guchar *l_lastvalues_bck_buffer; gint l_bck_len; gint l_rc; l_lastvalues_bck_buffer = NULL; l_bck_len = 0; /* make backup of last values buffer (if available) */ l_bck_len = gimp_get_data_size(fmac_elem->filtername); if(l_bck_len > 0) { if(l_bck_len != fmac_elem->buffer_from_length) { l_msg = g_strdup_printf (_("parameter data buffer for plug-in: '%s' differs in size\n" "actual size: %d\n" "recorded size: %d") , fmac_elem->filtername , (int)l_bck_len , (int)fmac_elem->buffer_from_length ); p_print_and_free_msg(l_msg, run_mode); /* ignore filter call because length missmatch of parameterset was detected * (this can happen if the filtermacro was recorded with a release version * that differs from the currently installed version). * in such a case the filter may crash if called with an incompatible last value * parameter set. */ return; } l_lastvalues_bck_buffer = g_malloc0(l_bck_len); gimp_get_data (fmac_elem->filtername, l_lastvalues_bck_buffer); } if (fmac_elem->iteratorname) { static char l_key_from[512]; static char l_key_to[512]; /* set data. Note that iterators will fail if the filter plugin has never * set a lastvalus buffer in the current gimp session because * the buffer size is derived from an inital filter run. * therefore we set the lastvalus buffer now to simulate an initial run * and let the iterators know about the size of the lastavlues buffer. */ gimp_set_data(fmac_elem->filtername, fmac_elem->buffer_from, fmac_elem->buffer_from_length); /* Note that FROM and TO are swapped, because iterators were initially * desinged for processing layers at inverse order. */ g_snprintf(l_key_from, sizeof(l_key_from), "%s%s", fmac_elem->filtername, GAP_ITER_TO_SUFFIX); gimp_set_data(l_key_from, fmac_elem->buffer_from, fmac_elem->buffer_from_length); g_snprintf(l_key_to, sizeof(l_key_to), "%s%s", fmac_elem->filtername, GAP_ITER_FROM_SUFFIX); gimp_set_data(l_key_to, fmac_elem->buffer_to, fmac_elem->buffer_from_length); if(gap_debug) { 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 * filtername. This is done by mixing iterable parameter values of the * FROM and TO parametersets. */ gap_filter_iterator_call(fmac_elem->iteratorname , total_steps , current_step , fmac_elem->filtername , fmac_elem->buffer_from_length ); } else { if(gap_debug) { printf("p_fmac_execute_single_filter: CONST APPLY %s\n" ,fmac_elem->filtername ); } /* filter without iterator are applied with constant parameterset FROM values * Here we set the last values buffer directly * (the key of the last values buffer is the filtername by GIMP convention) */ gimp_set_data(fmac_elem->filtername, fmac_elem->buffer_from, fmac_elem->buffer_from_length); } if(gap_debug) { guchar *l_exec_buffer; gint l_exec_len; gint l_ii; 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" ,(int)image_id ,(int)drawable_id ,fmac_elem->filtername ,(int)l_exec_len ); l_exec_buffer = g_malloc0(l_exec_len); gimp_get_data (fmac_elem->filtername, l_exec_buffer); printf("exec buffer:"); for(l_ii=0; l_ii < l_exec_len; l_ii++) { printf(" %02X", (int)l_exec_buffer[l_ii]); } printf("\n"); } /* call the filter plugin itself with runmode RUN_WITH_LAST_VALUES */ l_rc = gap_filt_pdb_call_plugin(fmac_elem->filtername , image_id , drawable_id , GIMP_RUN_WITH_LAST_VALS ); /* restore lastvalues buffer (if we have a valid backup) */ if(l_lastvalues_bck_buffer) { gimp_set_data(fmac_elem->filtername, l_lastvalues_bck_buffer, l_bck_len); g_free(l_lastvalues_bck_buffer); l_lastvalues_bck_buffer = NULL; } } /* end p_fmac_execute_single_filter */ /* ------------------------ * p_fmac_execute * ------------------------ * apply filtermacro on the specified drawable_id that must be part of the specified * image_id. * filtermacro_file1 is mandatory parameter (not NULL) * it specifiies the FROM parameterset(s) in case of applying with varying * values. * filtermacro_file2 is optional parameter * caller may pass NULL if applying * with constant parameterset(s) as defined in filtermacro_file1 is required. * * if the parameter filtermacro_file2 is not NULL, it refers to a 2nd * collection of filter parameterset(s). In this case the iterable parameters * are built as mix of parametersets from file1 and file2 according to * ratio of current_step/total_steps. * This is restricted to correlated filternames (that appear in both file1 and file2) * * example: * * # file1: len data * -------------------------------- * 1. plug_in_abc 3 00 01 02 * 2. plug_in_xy 2 00 00 * 3. plug_in_abc 3 00 08 00 * 4. plug_in_xy 2 0A 0A * 5. plug_in_xy 2 02 02 * * # file2: len data * ----------------------------- * 1. plug_in_zzz 1 00 * 2. plug_in_xy 2 00 20 * 3. plug_in_xy 2 00 00 * * In this example the plug_in_zzz is ignored (because there is no correlating * filtercall definition in file1) * file2:line 2.) correlates with file1:line 2.) * file2:line 3.) correlates with file1:line 4.) * */ gint p_fmac_execute(GimpRunMode run_mode, gint32 image_id, gint32 drawable_id , const char *filtermacro_file1 , const char *filtermacro_file2 , gdouble current_step , gint32 total_steps ) { FMacElem *fmac_root; fmac_root = p_build_fmac_list(filtermacro_file1, run_mode); 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) { p_merge_fmac_list(fmac_root, filtermacro_file2, run_mode); } for(fmac_elem = fmac_root; fmac_elem != NULL; fmac_elem = (FMacElem *)fmac_elem->next) { p_fmac_execute_single_filter(run_mode, image_id, drawable_id , fmac_elem , 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 */ } return(0); } /* end p_fmac_execute */ /* ---------------- * gap_fmac_execute * ---------------- */ gint gap_fmac_execute(GimpRunMode run_mode, gint32 image_id, gint32 drawable_id , const char *filtermacro_file1 , const char *filtermacro_file2 , gdouble current_step , gint32 total_steps ) { gint l_rc; if(gap_debug) { printf("gap_fmac_execute: image_id:%d drawable_id:%d total_steps:%d current_step:%f\n" ,(int)image_id ,(int)drawable_id ,(int)total_steps ,(float)current_step ); printf(" macrofile1:%s\n", filtermacro_file1 == 0 ? "null" : filtermacro_file1); printf(" macrofile2:%s\n", filtermacro_file2 == 0 ? "null" : filtermacro_file2); } gimp_image_undo_group_start(image_id); l_rc = p_fmac_execute(run_mode, image_id, drawable_id , filtermacro_file1 , filtermacro_file2 , current_step , total_steps ); gimp_image_undo_group_end(image_id); return (l_rc); } /* end gap_fmac_execute */ gimp-gap-2.6.0+dfsg.orig/gap/gap_filter_main.c0000644000175000017500000002237511212030253021011 0ustar thibautthibaut/* gap_filter_main.c * 1997.12.18 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * - MAIN of GAP_filter foreach: call any Filter (==Plugin Proc) * with varying settings for all * layers within one Image. * - query registration of gap_foreach Procedure * and for the COMMON Iterator Procedures * and for all Iterator_ALT Procedures * - run invoke the gap_foreach procedure by its PDB name * * * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* SYTEM (UNIX) includes */ #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "config.h" #include "gap-intl.h" #include "libgimp/gimp.h" /* GAP includes */ #include "gap_lastvaldesc.h" #include "gap_filter.h" #include "gap_filter_iterators.h" #include "gap_dbbrowser_utils.h" /* revision history: * gimp 1.3.20b; 2003/09/20 hof: update version, minor cleanup * gimp 1.3.12a; 2003/05/02 hof: merge into CVS-gimp-gap project * gimp 1.3.4b; 2002/03/24 hof: support COMMON_ITERATOR, removed support of iter_ALT Procedures * 2000/11/30 v1.1.29b: hof: new e-mail adress * version 0.92.00 hof: set gap_debug from environment * version 0.91.01; Tue Dec 23 hof: 1.st (pre) release */ /* ------------------------ * global gap DEBUG switch * ------------------------ */ /* int gap_debug = 1; */ /* print debug infos */ /* int gap_debug = 0; */ /* 0: dont print debug infos */ int gap_debug = 0; #define PLUG_IN_NAME_ANIMFILTER "plug_in_gap_layers_run_animfilter" static void query(void); static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; MAIN () static void query () { static GimpParamDef args_foreach[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_STRING, "proc_name", "name of plugin procedure to run for each layer"}, {GIMP_PDB_INT32, "varying", "0 .. apply constant, 1..apply varying"}, }; static GimpParamDef *return_vals = NULL; static int nreturn_vals = 0; static GimpParamDef args_com_iter[] = { {GIMP_PDB_INT32, "run_mode", "non-interactive"}, {GIMP_PDB_INT32, "total_steps", "total number of steps (# of layers-1 to apply the related plug-in)"}, {GIMP_PDB_FLOAT, "current_step", "current (for linear iterations this is the layerstack position, otherwise some value inbetween)"}, {GIMP_PDB_INT32, "len_struct", "length of stored data structure with id is equal to the plug_in proc_name"}, {GIMP_PDB_STRING, "plugin_name", "name of the plugin (used as keyname to access LAST_VALUES buffer)"}, }; gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); gimp_install_procedure(PLUG_IN_NAME_ANIMFILTER, "This plugin calls another plugin for each layer of an image, " "optional varying its settings (to produce animated effects). " "The called plugin must work on a single drawable and must be " "able to run in runmode GIMP_RUN_WITH_LAST_VALS and using gimp_set_data " "to store its parameters for this session with its own name as access key. " "plug_in_gap_layers_run_animfilter runs as wizzard (using more dialog steps). " "In Interactive runmode it starts with with a browser dialog where the name of the " "other plug-in (that is to execute) can be selected." "In non-interactive run mode this first browser dialog step is skiped. " "But the selceted plug-in (in this case via parameter plugin_name) is called in " "interactive runmode one time or two times if varying parameter is not 0. " "Those interactive calls are done regardless what runmode is specified here.", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Filter all Layers..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, G_N_ELEMENTS (args_foreach), nreturn_vals, args_foreach, return_vals); /* ------------------ Common Iterator ------------------------------ */ gimp_install_procedure(GIMP_PLUGIN_GAP_COMMON_ITER, "This procedure calculates the modified values in the LAST_VALUES buffer named by plugin_name for one iterationstep", "", "Wolfgang Hofer", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, NULL, /* do not appear in menus */ NULL, GIMP_PLUGIN, G_N_ELEMENTS (args_com_iter), nreturn_vals, args_com_iter, return_vals); /* ------------------ ALTernative Iterators ------------------------------ */ gimp_plugin_menu_register (PLUG_IN_NAME_ANIMFILTER, N_("/Filters/")); gap_query_iterators_ALT(); } /* end query */ static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals) { #define MAX_PLUGIN_NAME_LEN 256 char l_plugin_name[MAX_PLUGIN_NAME_LEN]; static GimpParam values[1]; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; gint32 image_id; gint32 len_struct; gint32 total_steps; gdouble current_step; gint32 l_rc; const char *l_env; *nreturn_vals = 1; *return_vals = values; l_rc = 0; l_env = g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } run_mode = param[0].data.d_int32; INIT_I18N (); if(gap_debug) fprintf(stderr, "\n\ngap_filter_main: debug name = %s\n", name); if (strcmp (name, PLUG_IN_NAME_ANIMFILTER) == 0) { GapFiltPdbApplyMode apply_mode; apply_mode = GAP_PAPP_CONSTANT; if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != 5) { status = GIMP_PDB_CALLING_ERROR; } else { strncpy(l_plugin_name, param[3].data.d_string, MAX_PLUGIN_NAME_LEN -1); l_plugin_name[MAX_PLUGIN_NAME_LEN -1] = '\0'; } if( param[4].data.d_int32 != 0) { apply_mode = GAP_PAPP_VARYING_LINEAR; } } else if(run_mode == GIMP_RUN_WITH_LAST_VALS) { /* probably get last values (name of last plugin) */ gimp_get_data(PLUG_IN_NAME_ANIMFILTER, l_plugin_name); } if (status == GIMP_PDB_SUCCESS) { image_id = param[1].data.d_image; l_rc = gap_proc_anim_apply(run_mode, image_id, l_plugin_name, apply_mode); gimp_set_data(PLUG_IN_NAME_ANIMFILTER, l_plugin_name, sizeof(l_plugin_name)); } } else if(strcmp (name, GIMP_PLUGIN_GAP_COMMON_ITER) == 0) { if ((run_mode == GIMP_RUN_NONINTERACTIVE) && (n_params == 5)) { total_steps = param[1].data.d_int32; current_step = param[2].data.d_float; len_struct = param[3].data.d_int32; l_rc = gap_common_iterator(param[4].data.d_string, run_mode, total_steps, current_step, len_struct); } else status = GIMP_PDB_CALLING_ERROR; } else { if ((run_mode == GIMP_RUN_NONINTERACTIVE) && (n_params == 4)) { total_steps = param[1].data.d_int32; current_step = param[2].data.d_float; len_struct = param[3].data.d_int32; l_rc = gap_run_iterators_ALT(name, run_mode, total_steps, current_step, len_struct); } else { status = GIMP_PDB_CALLING_ERROR; } } if(l_rc < 0) { status = GIMP_PDB_EXECUTION_ERROR; } if (run_mode != GIMP_RUN_NONINTERACTIVE) gimp_displays_flush(); values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; } gimp-gap-2.6.0+dfsg.orig/gap/gap_audio_util.h0000644000175000017500000000146511212030253020660 0ustar thibautthibaut/* gap_audio_util.h * * GAP common encoder audio utility procedures * */ /* 2002.01.05 hof removed p_get_wavparams */ #ifndef GAP_AUDIO_UTIL_H #define GAP_AUDIO_UTIL_H /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" void gap_audio_util_stereo_split16to16(unsigned char *l_left_ptr, unsigned char *l_right_ptr, unsigned char *l_aud_ptr, long l_data_len); void gap_audio_util_dbl_sample_8_to_16(unsigned char insample8, unsigned char *lsb_out, unsigned char *msb_out); void gap_audio_util_stereo_split8to16(unsigned char *l_left_ptr, unsigned char *l_right_ptr, unsigned char *l_aud_ptr, long l_data_len); #endif /* end GAP_AUDIO_UTIL_H */ gimp-gap-2.6.0+dfsg.orig/gap/gap_navi_activtable.c0000644000175000017500000001150111212030253021640 0ustar thibautthibaut/* gap_navi_activtable.c * 2002.04.21 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * */ #include "libgimp/gimp.h" #include "gap_navi_activtable.h" typedef struct t_gap_activdata { gint32 pid; gint32 old_image_id; gint32 new_image_id; } t_gap_activdata; extern int gap_debug; /* ==0 ... dont print debug infos */ #define GAP_NAVID_ACTIVE_IMAGE "plug_in_gap_navid_ACTIVE_IMAGETABLE" /* ============================================================================ * gap_navat_update_active_image * update activ_image table. * - is usually called in gap_lib at change of the current frame. * - The activ_image table contains all the active_images for all * open navigator dialogs. (currently 1 or 0 entries) * ============================================================================ */ /* revision history: * 1.3.5a; 2002/04/21 hof: created (Handle Event: active_image changed id) */ void gap_navat_update_active_image(gint32 old_image_id, gint32 new_image_id) { gint32 l_idx; gint32 l_activsize; gint32 l_nactivs; t_gap_activdata *l_activtab; /* update activtable (all records that match old_image_id) */ l_activsize = gimp_get_data_size (GAP_NAVID_ACTIVE_IMAGE); if (l_activsize > 0) { l_nactivs = l_activsize / (sizeof(t_gap_activdata)); l_activtab = g_new(t_gap_activdata, l_nactivs); gimp_get_data (GAP_NAVID_ACTIVE_IMAGE, l_activtab); for(l_idx=0; l_idx < l_nactivs; l_idx++) { if(l_activtab[l_idx].old_image_id == old_image_id) { l_activtab[l_idx].new_image_id = new_image_id; gimp_set_data(GAP_NAVID_ACTIVE_IMAGE, l_activtab, l_nactivs * sizeof(t_gap_activdata)); } } g_free(l_activtab); } } /* end gap_navat_update_active_image */ /* ============================================================================ * gap_navat_set_active_image * set active image for one (Navigator) Process in the activ_image table. * ============================================================================ */ void gap_navat_set_active_image(gint32 image_id, gint32 pid) { gint32 l_idx; gint32 l_activsize; gint32 l_nactivs; gint32 l_nactivs_old; t_gap_activdata *l_activtab; /* check activtable for empty records */ l_activsize = gimp_get_data_size (GAP_NAVID_ACTIVE_IMAGE); if (l_activsize > 0) { l_nactivs_old = l_activsize / (sizeof(t_gap_activdata)); l_nactivs = l_nactivs_old + 1; l_activtab = g_new(t_gap_activdata, l_nactivs); gimp_get_data (GAP_NAVID_ACTIVE_IMAGE, l_activtab); for(l_idx=0; l_idx < l_nactivs_old; l_idx++) { if (l_activtab[l_idx].pid == pid) { l_nactivs--; break; } } } else { /* create a new tab with 1 entry */ l_nactivs = 1; l_idx = 0; l_activtab = g_new(t_gap_activdata, l_nactivs); } l_activtab[l_idx].old_image_id = image_id; l_activtab[l_idx].new_image_id = image_id; l_activtab[l_idx].pid = pid; gimp_set_data(GAP_NAVID_ACTIVE_IMAGE, l_activtab, l_nactivs * sizeof(t_gap_activdata)); g_free(l_activtab); } /* end gap_navat_set_active_image */ /* ============================================================================ * gap_navat_get_active_image * get new_image_id for the active image (image_id) * for one (Navigator) Process in the activ_image table. * - If the table has information about a change of the old active image_id, * the new_image_id is returned * - If the old active image_id is found in the table, but still is * the same (as new_image_id) then -1 is returned. * - If the active_image table is empty * the input image_id is retuned. * ============================================================================ */ gint32 gap_navat_get_active_image(gint32 image_id, gint32 pid) { gint32 l_idx; gint32 l_activsize; gint32 l_nactivs; gint32 l_new_image_id; t_gap_activdata *l_activtab; l_new_image_id = image_id; /* check activtable for empty records */ l_activsize = gimp_get_data_size (GAP_NAVID_ACTIVE_IMAGE); if (l_activsize > 0) { l_nactivs = l_activsize / (sizeof(t_gap_activdata)); l_activtab = g_new(t_gap_activdata, l_nactivs); gimp_get_data (GAP_NAVID_ACTIVE_IMAGE, l_activtab); for(l_idx=0; l_idx < l_nactivs; l_idx++) { if ((l_activtab[l_idx].pid == pid) && (l_activtab[l_idx].old_image_id == image_id)) { if(l_activtab[l_idx].new_image_id == image_id) { l_new_image_id = -1; } else { l_new_image_id = l_activtab[l_idx].new_image_id; } break; } } g_free(l_activtab); } return (l_new_image_id); } /* end gap_navat_get_active_image */ gimp-gap-2.6.0+dfsg.orig/gap/gap_morph_main.c0000644000175000017500000006363311212030253020653 0ustar thibautthibaut/* gap_morph_main.c * creation of morphing animations (transform source image into des. image) by Wolfgang Hofer * 2004/02/11 */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Revision history * version 1.3.26a; 2004/02/12 hof: created */ #include "config.h" #include #include #include #include #include #include #include "gap_morph_main.h" #include "gap_morph_exec.h" #include "gap_morph_dialog.h" #include "gap_morph_tween_dialog.h" #include "gap_pview_da.h" /* for pointfile loader (workaround) */ #include "gap_mov_dialog.h" #include "gap_mov_exec.h" #include "gap-intl.h" /* Defines */ #define PLUG_IN_NAME "plug_in_gap_morph_layers" #define PLUG_IN_NAME_TWEEN "plug_in_gap_morph_tween" /* render missing tween(s) between frames */ #define PLUG_IN_NAME_ONE_TWEEN "plug_in_gap_morph_one_tween" /* single tween rendering */ #define PLUG_IN_PRINT_NAME "Morph Layers" #define PLUG_IN_IMAGE_TYPES "RGBA, GRAYA" #define PLUG_IN_AUTHOR "Wolfgang Hofer (hof@gimp.org)" #define PLUG_IN_COPYRIGHT "Wolfgang Hofer" int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */ static GapMorphGlobalParams global_params = { GIMP_RUN_INTERACTIVE , -1 /* gint32 image_id */ , 1 /* gint32 tween_steps */ , -1 /* gint32 fdst_layer_id */ , -1 /* gint32 osrc_layer_id */ , NULL /* GapMorphWorkPoint *master_wp_list */ , "\0" /* char workpoint_file_lower[1024] */ , "\0" /* char workpoint_file_upper[1024] */ , TRUE /* gboolean create_tween_layers */ , FALSE /* gboolean have_workpointsets */ , FALSE /* gboolean use_quality_wp_selection */ , FALSE /* gboolean use_gravity */ , 2.0 /* gdouble gravity_intensity */ , 100.0 /* gdouble affect_radius */ , GAP_MORPH_RENDER_MODE_MORPH /* gint32 render_mode */ , FALSE /* gboolean do_progress */ , 0.0 /* gdouble master_progress */ , 0.0 /* gdouble layer_progress_step */ , 0.0 /* gdouble tween_mix_factor */ , -1 /* long range_from */ , -1 /* long range_to */ , FALSE /* gboolean overwrite_flag */ , FALSE /* gboolean do_simple_fade */ }; static void query (void); static void run (const gchar *name, gint nparams, /* number of parameters passed in */ const GimpParam * param, /* parameters passed in */ gint *nreturn_vals, /* number of parameters returned */ GimpParam ** return_vals); /* parameters to be returned */ static gint32 p_handle_PLUG_IN_NAME_TWEEN(GapMorphGlobalParams *mgpp); /* Global Variables */ GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run /* run_proc */ }; static GimpParamDef in_args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, { GIMP_PDB_IMAGE, "image", "Input image" }, { GIMP_PDB_DRAWABLE, "src_drawable", "source drawable (usually a layer)"}, { GIMP_PDB_DRAWABLE, "dst_drawable", "destination drawable (usually a layer)"}, { GIMP_PDB_INT32, "tween_steps", "number of layers to create (or modify) below the dst_layer"}, { GIMP_PDB_INT32, "render_mode", "0: Do Morph transformation, 1: do only Warp transformation"}, { GIMP_PDB_INT32, "create_tween_layers", "TRUE: Do create tween layers, FALSE: operate on existing layers"}, { GIMP_PDB_STRING, "workpoint_file_1", "Name of a Morph/Warp workpointfile" "(create such file(s) with the save button in the GUI at INTERACTIVE runmode)"}, { GIMP_PDB_STRING, "workpoint_file_2", "Name of an optional 2nd Morph/Warp workpointfile." " (pass an empty string or the same name as the 1st file" " if you want to operate with one workpoint file)"}, }; static GimpParamDef in_tween_args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive."}, { GIMP_PDB_IMAGE, "start_image", "from frame image (must be a frame with GIMP-GAP typical number part in the imagefilename)" }, { GIMP_PDB_DRAWABLE, "drawable", "ignored"}, { GIMP_PDB_INT32, "to_frame_nr", "frame number of the next available frame"}, { GIMP_PDB_INT32, "overwrite", "0 == do not overwrite, 1 == overrite existing frames"}, { GIMP_PDB_INT32, "do_simple_fade", "0 == use morph algorithm, 1 == use simple fade operation (ignore the workpoint_file) "}, { GIMP_PDB_STRING, "workpoint_file", "Name of a Morph/Warp workpointfile" "(create such file(s) with the save button in the GUI " "of the plug_in_gap_morph_layers, or specify an emty string" "that starts with 0x00 to operate as simple video fade)"}, }; static GimpParamDef out_tween_args[] = { { GIMP_PDB_DRAWABLE, "tween_drawable", "the last one of the newly created tween(s) (a layer in a newly created frame image)"}, }; static GimpParamDef in_one_tween_args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive."}, { GIMP_PDB_IMAGE, "image", "(not relevant)" }, { GIMP_PDB_DRAWABLE, "src_drawable", "source drawable (usually a layer)"}, { GIMP_PDB_DRAWABLE, "dst_drawable", "destination drawable (usually a layer)"}, { GIMP_PDB_FLOAT, "tween_mix_factor", "a value between 0.0 and 1.0 where 0 delivers a copy of the src layer" "1 delivers a copy of the destination layer," "other value deliver a mix according to morph algortihm" }, { GIMP_PDB_INT32, "do_simple_fade", "0 == use morph algorithm, 1 == use simple fade operation (ignore the workpoint_file) "}, { GIMP_PDB_STRING, "workpoint_file", "Name of a Morph/Warp workpointfile" "(create such file(s) with the save button in the GUI " "of the plug_in_gap_morph_layers, or specify an emty string" "that starts with 0x00 to operate as simple video fade)"}, }; static GimpParamDef out_one_tween_args[] = { { GIMP_PDB_DRAWABLE, "tween_drawable", "newly created tween (a layer in a newly created image)"}, }; MAIN () static void query (void) { gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); /* the actual installation of the plugin */ gimp_install_procedure (PLUG_IN_NAME, "Image Layer Morphing", "This plug-in creates new layers by transforming the src_drawable to dst_drawable, " "the transformation type depends on the render_mode parameter. " "for MORPH render_mode (0) it is a combination of 2 warp deformation actions " "and cross-blending, commonly known as morphing." "The tween_steps parameter controls how much new layers to create. " "(or how much layers to modify depending on the create_tween_layers parameter) " "source and destination may differ in size and can be in different images. " "for WARP render_mode (1) there will be just Move Deformation. " "Deformation is controled by workpoints. Workpoints are created and edited with the help " "of the INTERACTIVE GUI and saved to file(s). " "For the NON-INTERACTIVE runmode you must provide the filename of such a file. " "Provide 2 filenames if you want to operate with multiple workpoint sets. " "In that case your workpoint files can have a 2 digit numberpart. " "This will implicite select all filenames with numbers inbetween as well." , PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("Morph..."), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, G_N_ELEMENTS (in_args), 0, /* G_N_ELEMENTS (out_args) */ in_args, NULL /* out_args */ ); /* the actual installation of the plugin */ gimp_install_procedure (PLUG_IN_NAME_TWEEN, "Render tween frames via morhing", "This plug-in creates and saves image frames that are a mix of the specified image frame and the frame with to_frame_nr, " "The typical usage is to create the frame images of missing frame numbers in a series of anim frame images. " "the overwrite flag allows overwriting of already existing frames between the start frame image " "and the frame with to_frame_nr" "Morphing is controled by workpoints. A Workpoint file can be created and edited with the help " "of the Morph feature in the Video menu. " "Note: without workpoints the resulting tween is calculated as simple fade operation. " , PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("Morph Tweenframes..."), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, G_N_ELEMENTS (in_tween_args), G_N_ELEMENTS (out_tween_args), in_tween_args, out_tween_args ); /* the actual installation of the plugin */ gimp_install_procedure (PLUG_IN_NAME_ONE_TWEEN, "Render one tween via morhing", "This plug-in creates a new image that is a mix of the specified src_drawable and dst_drawable, " "the mixing is done based on a morphing transformation where the tween_mix_factor " "determines how much the result looks like source or destination. " "source and destination may differ in size and can be in different images. " "Morphing is controled by workpoints. A Workpoint file can be created and edited with the help " "of the Morph feature in the Video menu. " "Note: without workpoints the resulting tween is calculated as simple fade operation. " , PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("Morph One Tween..."), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, G_N_ELEMENTS (in_one_tween_args), G_N_ELEMENTS (out_one_tween_args), in_one_tween_args, out_one_tween_args ); { /* Menu names */ const char *menupath_image_video_morph = N_("/Video/Morph/"); //gimp_plugin_menu_branch_register("", "Video/Morph"); gimp_plugin_menu_register (PLUG_IN_NAME, menupath_image_video_morph); gimp_plugin_menu_register (PLUG_IN_NAME_TWEEN, menupath_image_video_morph); gimp_plugin_menu_register (PLUG_IN_NAME_ONE_TWEEN, menupath_image_video_morph); } } /* ---------------------------------- * p_handle_PLUG_IN_NAME_TWEEN * ---------------------------------- * * return the newly created tween morphed layer * */ static gint32 p_handle_PLUG_IN_NAME_TWEEN(GapMorphGlobalParams *mgpp) { gint32 l_tween_layer_id; GapAnimInfo *ainfo_ptr; gboolean l_rc; gboolean l_run_flag; l_tween_layer_id = -1; l_rc = FALSE; l_run_flag = TRUE; ainfo_ptr = gap_lib_alloc_ainfo(mgpp->image_id, mgpp->run_mode); if(ainfo_ptr != NULL) { if (0 == gap_lib_dir_ainfo(ainfo_ptr)) { mgpp->range_from = ainfo_ptr->curr_frame_nr; /* mgpp->range_to is already set at noninteractive call. for interacive cals this is set in the following dialog */ if(mgpp->run_mode == GIMP_RUN_INTERACTIVE) { if(0 != gap_lib_chk_framechange(ainfo_ptr)) { l_run_flag = FALSE; } else { if(*ainfo_ptr->extension == '\0' && ainfo_ptr->frame_cnt == 0) { /* plugin was called on a frame without extension and without framenumer in its name * (typical for new created images named like 'Untitled' */ g_message(_("Operation cancelled.\n" "GAP video plug-ins only work with filenames\n" "that end in numbers like _000001.xcf.\n" "==> Rename your image, then try again.")); return -1; } l_rc = gap_morph_frame_tweens_dialog(ainfo_ptr, mgpp); mgpp->do_progress = TRUE; } if((0 != gap_lib_chk_framechange(ainfo_ptr)) || (!l_rc)) { l_run_flag = FALSE; } } if(l_run_flag == TRUE) { /* render tween frames and write them as framefiles to disc () */ l_tween_layer_id = gap_morph_render_frame_tweens(ainfo_ptr, mgpp); } } gap_lib_free_ainfo(&ainfo_ptr); } return(l_tween_layer_id); } /* end p_handle_PLUG_IN_NAME_TWEEN */ /* ------------------------------------- * run * ------------------------------------- */ static void run (const gchar *name, /* name of plugin */ gint nparams, /* number of in-paramters */ const GimpParam * param, /* in-parameters */ gint *nreturn_vals, /* number of out-parameters */ GimpParam ** return_vals) /* out-parameters */ { const gchar *l_env; gint32 image_id = -1; gint32 drawable_id = -1; GapMorphGlobalParams *mgpp = &global_params; gboolean run_flag; /* Get the runmode from the in-parameters */ GimpRunMode run_mode = param[0].data.d_int32; /* status variable, use it to check for errors in invocation usualy only * during non-interactive calling */ GimpPDBStatusType status = GIMP_PDB_SUCCESS; /* always return at least the status to the caller. */ static GimpParam values[2]; INIT_I18N(); l_env = g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } if(gap_debug) { printf("\n\nDEBUG: run %s RUN_MODE:%d\n", name, (int)run_mode); } run_flag = FALSE; if (strcmp(name, PLUG_IN_NAME_TWEEN) == 0) { run_flag = TRUE; } /* initialize the return of the status */ values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; *nreturn_vals = 1; *return_vals = values; /* get image */ image_id = param[1].data.d_int32; drawable_id = param[2].data.d_drawable; mgpp->do_progress = FALSE; mgpp->image_id = image_id; mgpp->run_mode = run_mode; switch (run_mode) { case GIMP_RUN_INTERACTIVE: if (strcmp(name, PLUG_IN_NAME) == 0) { /* Possibly retrieve data from a previous run */ gimp_get_data (PLUG_IN_NAME, mgpp); mgpp->osrc_layer_id = drawable_id; mgpp->fdst_layer_id = gap_morph_exec_find_dst_drawable(image_id, drawable_id); run_flag = gap_morph_dialog(mgpp); mgpp->do_progress = TRUE; } else if (strcmp(name, PLUG_IN_NAME_ONE_TWEEN) == 0) { mgpp->tween_mix_factor = 0.5; /* Possibly retrieve data from a previous run */ gimp_get_data (PLUG_IN_NAME_ONE_TWEEN, mgpp); mgpp->osrc_layer_id = drawable_id; mgpp->fdst_layer_id = gap_morph_exec_find_dst_drawable(image_id, drawable_id); run_flag = gap_morph_one_tween_dialog(mgpp); mgpp->do_progress = TRUE; } break; case GIMP_RUN_NONINTERACTIVE: /* check to see if invoked with the correct number of parameters */ if ((nparams == G_N_ELEMENTS (in_args)) && (strcmp(name, PLUG_IN_NAME) == 0)) { mgpp->have_workpointsets = TRUE; /* use pointset(s) from file */ /* set defaults for params that may be specified in the workpointfiles * (the defaults will take effect only if the file does not contain such settings) */ mgpp->use_quality_wp_selection = FALSE; mgpp->use_gravity = FALSE; mgpp->gravity_intensity = 2.0; mgpp->affect_radius = 100.0; mgpp->osrc_layer_id = param[2].data.d_drawable; mgpp->fdst_layer_id = param[3].data.d_drawable; mgpp->tween_steps = param[4].data.d_int32; mgpp->render_mode = param[5].data.d_int32; mgpp->create_tween_layers = param[6].data.d_int32; if(param[7].data.d_string != NULL) { if(param[7].data.d_string[0] != '\0') { g_snprintf(mgpp->workpoint_file_lower , sizeof(mgpp->workpoint_file_lower) , "%s", param[7].data.d_string); g_snprintf(mgpp->workpoint_file_upper , sizeof(mgpp->workpoint_file_upper) , "%s", param[7].data.d_string); } else { printf("%s: noninteractive call requires a not-empty workpoint_file_1 parameter\n" , PLUG_IN_NAME ); status = GIMP_PDB_CALLING_ERROR; } } else { printf("%s: noninteractive call requires a not-NULL workpoint_file_1 parameter\n" , PLUG_IN_NAME ); status = GIMP_PDB_CALLING_ERROR; } if(param[8].data.d_string != NULL) { if(param[8].data.d_string[0] != '\0') { g_snprintf(mgpp->workpoint_file_upper , sizeof(mgpp->workpoint_file_upper) , "%s", param[8].data.d_string); } } run_flag = TRUE; } else if ((nparams == G_N_ELEMENTS (in_one_tween_args)) && (strcmp(name, PLUG_IN_NAME_ONE_TWEEN) == 0)) { /* set defaults for params that may be specified in the workpointfiles * (the defaults will take effect only if the file does not contain such settings) */ mgpp->use_quality_wp_selection = FALSE; mgpp->have_workpointsets = FALSE; /* operate with a single workpointfile */ mgpp->use_gravity = FALSE; mgpp->gravity_intensity = 2.0; mgpp->affect_radius = 100.0; mgpp->tween_steps = 1; /* (in this mode always render only one tween) */ mgpp->render_mode = GAP_MORPH_RENDER_MODE_MORPH; mgpp->create_tween_layers = TRUE; mgpp->osrc_layer_id = param[2].data.d_drawable; mgpp->fdst_layer_id = param[3].data.d_drawable; mgpp->tween_mix_factor = param[4].data.d_float; mgpp->do_simple_fade = (param[5].data.d_int32 != 0); if(param[6].data.d_string != NULL) { if(param[6].data.d_string[0] != '\0') { g_snprintf(mgpp->workpoint_file_lower , sizeof(mgpp->workpoint_file_lower) , "%s", param[6].data.d_string); g_snprintf(mgpp->workpoint_file_upper , sizeof(mgpp->workpoint_file_upper) , "%s", param[6].data.d_string); } else { mgpp->have_workpointsets = FALSE; /* no pointset file available */ } run_flag = TRUE; } else { printf("%s: noninteractive call requires a not-NULL workpoint_file parameter\n" , PLUG_IN_NAME_ONE_TWEEN ); status = GIMP_PDB_CALLING_ERROR; } } else if ((nparams == G_N_ELEMENTS (in_one_tween_args)) && (strcmp(name, PLUG_IN_NAME_TWEEN) == 0)) { /* set defaults for params that may be specified in the workpointfiles * (the defaults will take effect only if the file does not contain such settings) */ mgpp->use_quality_wp_selection = FALSE; mgpp->have_workpointsets = FALSE; /* operate with a single workpointfile */ mgpp->use_gravity = FALSE; mgpp->gravity_intensity = 2.0; mgpp->affect_radius = 100.0; mgpp->tween_steps = 1; /* (will be calculated later as difference of handled frame numbers) */ mgpp->render_mode = GAP_MORPH_RENDER_MODE_MORPH; mgpp->create_tween_layers = TRUE; mgpp->osrc_layer_id = -1; /* is created later as merged copy of the specified image */ mgpp->fdst_layer_id = -1; /* is created later as merged copy of the frame rfered by to_frame_nr parameter */ mgpp->range_to = param[3].data.d_int32; mgpp->overwrite_flag = (param[4].data.d_int32 != 0); mgpp->do_simple_fade = (param[5].data.d_int32 != 0); mgpp->tween_mix_factor = 1.0; /* not relevant here */ if(param[6].data.d_string != NULL) { if(param[6].data.d_string[0] != '\0') { g_snprintf(mgpp->workpoint_file_lower , sizeof(mgpp->workpoint_file_lower) , "%s", param[6].data.d_string); g_snprintf(mgpp->workpoint_file_upper , sizeof(mgpp->workpoint_file_upper) , "%s", param[6].data.d_string); } else { mgpp->have_workpointsets = FALSE; /* no pointset file available */ } run_flag = TRUE; } else { printf("%s: noninteractive call requires a not-NULL workpoint_file parameter\n" , PLUG_IN_NAME_TWEEN ); status = GIMP_PDB_CALLING_ERROR; } } else { printf("%s: noninteractive call wrong nuber %d of params were passed. (%d params are required)\n" , PLUG_IN_NAME , (int)nparams , (int)G_N_ELEMENTS (in_args) ); status = GIMP_PDB_CALLING_ERROR; } break; case GIMP_RUN_WITH_LAST_VALS: if (strcmp(name, PLUG_IN_NAME) == 0) { /* Possibly retrieve data from a previous run */ gimp_get_data (PLUG_IN_NAME, mgpp); mgpp->osrc_layer_id = drawable_id; mgpp->fdst_layer_id = gap_morph_exec_find_dst_drawable(image_id, drawable_id); run_flag = gap_morph_dialog(mgpp); mgpp->do_progress = TRUE; } break; default: break; } if ((status == GIMP_PDB_SUCCESS) && (run_flag)) { if (strcmp(name, PLUG_IN_NAME) == 0) { gap_morph_execute(mgpp); /* Store variable states for next run */ if (run_mode == GIMP_RUN_INTERACTIVE) { gimp_set_data (PLUG_IN_NAME, mgpp, sizeof (GapMorphGlobalParams)); } } else if ((strcmp(name, PLUG_IN_NAME_ONE_TWEEN) == 0) || (strcmp(name, PLUG_IN_NAME_TWEEN) == 0)) { gint32 tween_layer_id; if (strcmp(name, PLUG_IN_NAME_ONE_TWEEN) == 0) { tween_layer_id = gap_morph_render_one_tween(mgpp); } else if (strcmp(name, PLUG_IN_NAME_TWEEN) == 0) { tween_layer_id = p_handle_PLUG_IN_NAME_TWEEN(mgpp); } values[1].type = GIMP_PDB_DRAWABLE; values[1].data.d_int32 = tween_layer_id; values[1].data.d_drawable = tween_layer_id; *nreturn_vals = 2; if (tween_layer_id < 0) { status = GIMP_PDB_EXECUTION_ERROR; } else { if (run_mode == GIMP_RUN_INTERACTIVE) { /* Store variable states for next run */ gimp_set_data (name, mgpp, sizeof (GapMorphGlobalParams)); gimp_display_new(gimp_drawable_get_image(tween_layer_id)); } } } } values[0].data.d_status = status; } /* end run */ gimp-gap-2.6.0+dfsg.orig/gap/gap_player_main.c0000644000175000017500000004034211212030253021012 0ustar thibautthibaut/* gap_player_main.c * video (preview) playback of video frames based on thumbnails by Wolfgang Hofer * 2003/06/11 */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Revision history * version 1.3.20d; 2003/10/06 hof: new gpp struct members for resize behaviour * version 1.3.19a; 2003/09/06 hof: audiosupport (based on wavplay, for UNIX only), * version 1.3.16a; 2003/06/26 hof: param types GimpPlugInInfo.run procedure * version 1.3.16a; 2003/06/26 hof: param types GimpPlugInInfo.run procedure * version 1.3.16a; 2003/06/26 hof: updated version * version 1.3.15a; 2003/06/21 hof: created */ #include "config.h" #include #include #include #include #include #include #include "gap_player_main.h" #include "gap_player_cache.h" #include "gap_player_dialog.h" #include "gap_story_file.h" #include "gap_pview_da.h" #include "gap-intl.h" /* Defines */ #define PLUG_IN_NAME "plug_in_gap_videoframes_player" #define PLUG_IN_HELP_ID "plug-in-gap-videoframes-player" #define PLUG_IN_PRINT_NAME "Videopreview Player" #define PLUG_IN_IMAGE_TYPES "RGB*, INDEXED*, GRAY*" #define PLUG_IN_AUTHOR "Wolfgang Hofer (hof@gimp.org)" #define PLUG_IN_COPYRIGHT "Wolfgang Hofer" int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */ static GapPlayerMainGlobalParams global_params = { TRUE /* standalone_mode */ , GIMP_RUN_INTERACTIVE , -1 /* gint32 image_id */ , NULL /* gchar *imagename */ , -1 /* gint32 imagewidth */ , -1 /* gint32 imageheight */ , 0.0 /* gdouble aspect_ratio */ , NULL /* GapAnimInfo *ainfo_ptr */ , NULL /* GapAnimInfo *stb_ptr */ , NULL /* t_GVA_Handle *gvahand */ , NULL /* gchar *gva_videofile */ , -1 /* gint32 mtrace_image_id */ , GAP_PLAYER_MTRACE_OFF /* mtrace_mode */ , NULL /* GapPlayerSetRangeFptr fptr_set_range */ , NULL /* gpointer user_data_ptr */ , FALSE /* gboolean autostart */ , FALSE /* gboolean caller_range_linked */ , TRUE /* gboolean use_thumbnails */ , TRUE /* gboolean exact_timing */ , FALSE /* gboolean play_is_active */ , TRUE /* gboolean play_selection_only */ , TRUE /* gboolean play_loop */ , FALSE /* gboolean play_pingpong */ , FALSE /* gboolean play_backward */ , FALSE /* gboolean request_cancel_video_api */ , FALSE /* gboolean cancel_video_api */ , FALSE /* gboolean gva_lock */ , -1 /* gint32 play_timertag */ , 0 /* gint32 begin_frame */ , 0 /* gint32 end_frame */ , 0 /* gint32 play_current_framenr */ , 0 /* gint32 pb_stepsize */ , 24.0 /* gdouble speed; playback speed fps */ , 24.0 /* gdouble original_speed; playback speed fps */ , 24.0 /* gdouble prev_speed; previous playback speed fps */ , 256 /* gint32 pv_pixelsize 32 upto 512 */ , 256 /* gint32 pv_width 32 upto 512 */ , 256 /* gint32 pv_height 32 upto 512 */ , FALSE /* gboolean in_feedback */ , FALSE /* gboolean in_timer_playback */ , FALSE /* gboolean in_resize */ , 0 /* gint32 go_job_framenr */ , -1 /* gint32 go_timertag */ , -1 /* gint32 go_base_framenr */ , -1 /* gint32 go_base */ , 0 /* gint32 pingpong_count */ , NULL /* GapPView *pv_ptr */ , NULL /* GtkWidget *shell_window */ , NULL /* GtkWidget *docking_container */ , NULL /* GtkWidget *frame_with_name */ , NULL /* GtkObject *from_spinbutton_adj */ , NULL /* GtkObject *to_spinbutton_adj */ , NULL /* GtkWidget *framenr_scale */ , NULL /* GtkObject *framenr_spinbutton_adj */ , NULL /* GtkObject *speed_spinbutton_adj */ , NULL /* GtkObject *size_spinbutton_adj */ , NULL /* GtkWidget *progress_bar */ , NULL /* GtkWidget *status_label */ , NULL /* GtkWidget *timepos_label */ , NULL /* GtkWidget *resize_box */ , NULL /* GtkWidget *size_spinbutton */ , NULL /* GtkWidget *from_button */ , NULL /* GtkWidget *to_button */ , NULL /* GtkWidget *use_thumb_checkbutton */ , NULL /* GtkWidget *exact_timing_checkbutton */ , NULL /* GtkWidget *pinpong_checkbutton */ , NULL /* GtkWidget *selonly_checkbutton */ , NULL /* GtkWidget *loop_checkbutton */ , NULL /* Gtimer *gtimer */ , 0.0 /* gdouble cycle_time_secs */ , 0.0 /* gdouble rest_secs */ , 0.0 /* gdouble delay_secs */ , 0.0 /* gdouble framecnt */ , 1 /* gint32 seltrack */ , 0.0 /* gdouble delace */ , NULL /* gchar *preferred_decoder */ , FALSE /* gboolean force_open_as_video */ , FALSE /* gboolean have_progress_bar */ , NULL /* gchar *progress_bar_idle_txt */ , 0 /* gint32 resize_handler_id */ , 0 /* gint32 old_resize_width */ , 0 /* gint32 old_resize_height */ , TRUE /* gboolean startup */ , -1 /* gint32 shell_initial_width */ , -1 /* gint32 shell_initial_height */ , FALSE /* audio_enable */ , 0 /* audio_resync */ , "\0" /* audiofile */ , "\0" /* audio_wavfile_tmp */ , 0 /* audio_frame_offset */ , 0 /* audio_samplerate */ , 0 /* audio_required_samplerate */ , 0 /* audio_bits */ , 0 /* audio_channels */ , 0 /* audio_samples */ , 0 /* audio_status */ , 1.0 /* audio_volume */ , 0 /* audio_tmp_samplerate */ , 0 /* audio_tmp_samples */ , FALSE /* audio_tmp_resample */ , FALSE /* audio_tmp_dialog_is_open */ , NULL /* audio_filename_entry */ , NULL /* audio_offset_time_label */ , NULL /* audio_total_time_label */ , NULL /* audio_total_frames_label */ , NULL /* audio_samples_label */ , NULL /* audio_samplerate_label */ , NULL /* audio_bits_label */ , NULL /* audio_channels_label */ , NULL /* audio_volume_spinbutton_adj */ , NULL /* audio_frame_offset_spinbutton_adj */ , NULL /* audio_filesel */ , NULL /* audio_table */ , NULL /* audio_status_label */ , NULL /* video_total_time_label */ , NULL /* video_total_frames_label */ , FALSE /* vindex_creation_is_running */ , NULL /* play_n_stop_hbox */ , NULL /* cancel_vindex_button */ , NULL /* help_id */ , FALSE /* onion_delete */ , NULL /* cache_size_spinbutton_adj */ , NULL /* label_current_cache_values */ , NULL /* progress_bar_cache_usage */ , GAP_PLAYER_CACHE_DEFAULT_MAX_BYTESIZE /* max_player_cache */ , GAP_PLAYER_CACHE_COMPRESSION_NONE /* cache_compression */ , 0.86 /* cache_jpeg_quality */ , TRUE /* show_go_buttons */ , TRUE /* show_position_scale */ , NULL /* show_go_buttons_checkbutton */ , NULL /* show_position_scale_checkbutton */ , NULL /* gobutton_hbox */ , NULL /* frame_scale_hbox */ , GAP_STB_FLIP_NONE /* flip_request */ , GAP_STB_FLIP_NONE /* flip_status */ , 1 /* stb_in_track */ ,-1 /* stb_parttype */ ,-1 /* stb_unique_id */ , NULL /* stb_comp_vidhand */ , FALSE /* audio_auto_offset_by_framenr */ , 1 /* audio_otone_atrack */ , NULL /* GtkWidget *audio_auto_offset_by_framenr_checkbutton */ , NULL /* GtkWidget *audio_otone_extract_button */ , NULL /* GtkWidget *audio_otone_atrack_spinbutton */ , NULL /* GtkObject *audio_otone_atrack_spinbutton_adj */ , NULL /* GtkWidget *progress_bar_audio */ , NULL /* GtkWidget *audio_enable_checkbutton */ , NULL /* GapDrawableVideoRef *dvref_ptr */ }; static void query (void); static void run (const gchar *name, gint nparams, /* number of parameters passed in */ const GimpParam * param, /* parameters passed in */ gint *nreturn_vals, /* number of parameters returned */ GimpParam ** return_vals); /* parameters to be returned */ /* Global Variables */ GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run /* run_proc */ }; static GimpParamDef in_args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, { GIMP_PDB_IMAGE, "image", "Input image" }, { GIMP_PDB_DRAWABLE, "drawable", "UNUSED"}, { GIMP_PDB_INT32, "range_from", "framenr begin of selected range"}, { GIMP_PDB_INT32, "range_to", "framenr end of selected range"}, { GIMP_PDB_INT32, "autostart", "(0) FALSE: no autostart, (1) TRUE: automatc playback start"}, { GIMP_PDB_INT32, "use_thumbnails", "(0) FALSE: playback original size frame images, (1) TRUE playback using thumbnails where available (much faster)"}, { GIMP_PDB_INT32, "exact_timing", "(0) FALSE: disable frame dropping, (1) TRUE: allow dropping frames to keep exact timing"}, { GIMP_PDB_INT32, "play_selection_only", "(0) FALSE: play all frames, (1) TRUE: play selected range only"}, { GIMP_PDB_INT32, "play_loop", "(0) FALSE: play once, (1) TRUE: play in loop"}, { GIMP_PDB_INT32, "play_pingpong", "(0) FALSE: normal play, (1) TRUE: bidirectional play"}, { GIMP_PDB_FLOAT, "speed", "-1 use original speed framerate in frames/sec (valid range is 1.0 upto 250.0)"}, { GIMP_PDB_INT32, "size_width", "-1 use standard size"}, { GIMP_PDB_INT32, "size_height", "-1 use standard size"}, { GIMP_PDB_INT32, "audio_enable", "(0) FALSE: NO Audio, (1) TRUE: play audio too (requires UNIX, and intalled wavplay as audio server)"}, { GIMP_PDB_STRING, "audio_filename", "Name of audiofile (must be RIFF WAV fileformat, PCM encoded)"}, { GIMP_PDB_INT32, "audio_frame_offset", "0: audio starts at 1.st videoframe +n: start audio after n silent frames, -n: audio starts 10 frames before the video (this part of the audio is clipped and not played)"}, { GIMP_PDB_FLOAT, "audio_volume", "range is 0.0 upto 1.0"}, }; /* Functions */ MAIN () static void query (void) { gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); /* the actual installation of the plugin */ gimp_install_procedure (PLUG_IN_NAME, "Video Preview Playback", "This plug-in does videoplayback, " "based on thumbnail preview or full sized video frames.", PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("Playback..."), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, G_N_ELEMENTS (in_args), 0, /* G_N_ELEMENTS (out_args) */ in_args, NULL /* out_args */ ); // gimp_plugin_menu_branch_register("", "Video"); gimp_plugin_menu_register (PLUG_IN_NAME, N_("/Video/")); } static void run (const gchar *name, /* name of plugin */ gint nparams, /* number of in-paramters */ const GimpParam * param, /* in-parameters */ gint *nreturn_vals, /* number of out-parameters */ GimpParam ** return_vals) /* out-parameters */ { const gchar *l_env; gint32 image_id = -1; GapPlayerMainGlobalParams *gpp = &global_params; /* Get the runmode from the in-parameters */ GimpRunMode run_mode = param[0].data.d_int32; /* status variable, use it to check for errors in invocation usualy only * during non-interactive calling */ GimpPDBStatusType status = GIMP_PDB_SUCCESS; /* always return at least the status to the caller. */ static GimpParam values[1]; INIT_I18N(); l_env = g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } if(gap_debug) fprintf(stderr, "\n\nDEBUG: run %s\n", name); /* initialize the return of the status */ values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; *nreturn_vals = 1; *return_vals = values; /* get image and drawable */ image_id = param[1].data.d_int32; switch (run_mode) { case GIMP_RUN_INTERACTIVE: /* Possibly retrieve data from a previous run */ gimp_get_data (PLUG_IN_NAME, gpp); gpp->autostart = FALSE; gpp->pv_pixelsize = 256; gpp->pv_width = 256; gpp->pv_height = 256; break; case GIMP_RUN_NONINTERACTIVE: /* check to see if invoked with the correct number of parameters */ if (nparams == G_N_ELEMENTS (in_args)) { gpp->begin_frame = (gint) param[3].data.d_int32; gpp->end_frame = (gint) param[4].data.d_int32; gpp->autostart = (gint) param[5].data.d_int32; gpp->use_thumbnails = (gint) param[6].data.d_int32; gpp->exact_timing = (gint) param[7].data.d_int32; gpp->play_selection_only = (gint) param[8].data.d_int32; gpp->play_loop = (gint) param[9].data.d_int32; gpp->play_pingpong = (gint) param[10].data.d_int32; gpp->speed = (gdouble) param[11].data.d_float; gpp->pv_width = (gint) param[12].data.d_int32; gpp->pv_height = (gint) param[13].data.d_int32; gpp->pv_pixelsize = MAX(gpp->pv_width, gpp->pv_height); gpp->audio_enable = (gboolean) param[14].data.d_int32; if(param[15].data.d_string) { g_snprintf(gpp->audio_filename, sizeof(gpp->audio_filename), "%s" , param[15].data.d_string); } else { gpp->audio_filename[0] = '\0'; gpp->audio_enable = FALSE; } gpp->audio_frame_offset = (gint) param[16].data.d_int32; gpp->audio_volume = (gdouble) param[17].data.d_float; } else { printf("%s: noninteractive call wrong nuber %d of params were passed. (%d params are required)\n" , PLUG_IN_NAME , (int)nparams , (int)G_N_ELEMENTS (in_args) ); status = GIMP_PDB_CALLING_ERROR; } break; case GIMP_RUN_WITH_LAST_VALS: /* Possibly retrieve data from a previous run */ gimp_get_data (PLUG_IN_NAME, gpp); gpp->autostart = FALSE; break; default: break; } if (status == GIMP_PDB_SUCCESS) { gpp->image_id = image_id; gpp->run_mode = run_mode; gpp->stb_ptr = NULL; gpp->help_id = PLUG_IN_HELP_ID; gap_player_dlg_playback_dialog(gpp); /* Store variable states for next run */ if (run_mode == GIMP_RUN_INTERACTIVE) gimp_set_data (PLUG_IN_NAME, gpp, sizeof (GapPlayerMainGlobalParams)); } values[0].data.d_status = status; } /* end run */ gimp-gap-2.6.0+dfsg.orig/gap/gap_audio_wav.h0000644000175000017500000000313411212030253020473 0ustar thibautthibaut/* gap_audio_wav.h * * GAP tool procedures * for RIFF WAVE format audifile handling. * */ /* * 2004.04.10 hof - created * */ #ifndef GAP_AUDIO_WAV_H #define GAP_AUDIO_WAV_H #include "stdio.h" #include "libgimp/gimp.h" void gap_audio_wav_write_gint16(FILE *fp, gint16 val); void gap_audio_wav_write_gint32(FILE *fp, gint32 val); void gap_audio_wav_write_header(FILE *fp , gint32 nsamples , gint32 channels , gint32 samplerate , gint32 bytes_per_sample , gint32 bits ); int gap_audio_wav_file_check(const char *audfile , long *sample_rate , long *channels , long *bytes_per_sample , long *bits , long *samples ); FILE * gap_audio_wav_open_seek_data(const char *filename); int gap_audio_wav_16bit_save(const char *wavfile , int channels , unsigned short *left_ptr , unsigned short *right_ptr , int samplerate , long total_samples); int gap_audio_playlist_wav_file_check(const char *audfile, long *sample_rate, long *channels , long *bytes_per_sample, long *bits, long *samples , long *all_playlist_references , long *valid_playlist_references , long desired_samplerate ); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_name2layer_main.c0000644000175000017500000004071411212030253021560 0ustar thibautthibaut/* gap_name2layer_main.c * create a textlayer from imagename (or ists number part) plug-in by Wolfgang Hofer * 2003/05/15 * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Revision history * (2003/10/10) v1.3.20d hof: sourcecode cleanup * (2003/06/21) v1.3.17a hof: types in GimpPlugInInfo.run procedure * (2003/06/21) v1.3.15a hof: bugfix: MenuPath is language dependent string * (2003/05/15) v1.0 hof: created */ #include "config.h" #include #include #include #include #include #include #include "gap_arr_dialog.h" #include "gap_lastvaldesc.h" #include "gap-intl.h" /* Defines */ #define PLUG_IN_NAME "plug_in_name2layer" #define PLUG_IN_HELP_ID "plug-in-name2layer" #define PLUG_IN_PRINT_NAME "Name to Layer" #define PLUG_IN_IMAGE_TYPES "RGB*, INDEXED*, GRAY*" #define PLUG_IN_AUTHOR "Wolfgang Hofer (hof@gimp.org)" #define PLUG_IN_COPYRIGHT "Wolfgang Hofer" int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */ typedef struct { gint mode; gint fontsize; gchar fontname[500]; gint posx; gint posy; gint antialias; gint create_new_layer; } NamlValues; typedef struct { gint run; } NamlInterface; static NamlValues glob_namlvals = { 0 /* 0 .. mode number only, 1 ..filename, 2..filename with path */ , 48 /* 24 default fontsize (?? is ignored size form fontname is used ) */ , "-*-Charter-*-r-*-*-48-*-*-*-p-*-*-*" /* defaul fontname "-*-Charter-*-r-*-*-24-*-*-*-p-*-*-*" */ , 15 , 15 , FALSE , 0 /* 0 render on input drawable, 1 create new layer */ }; static void query (void); static void run (const gchar *name, /* name of plugin */ gint nparams, /* number of in-paramters */ const GimpParam * param, /* in-parameters */ gint *nreturn_vals, /* number of out-parameters */ GimpParam ** return_vals); /* out-parameters */ static gint p_Naml (gint32 image_id, gint32 drawable_id); static gint Naml_dialog (void); /* Global Variables */ GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run /* run_proc */ }; static GimpParamDef in_args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, { GIMP_PDB_IMAGE, "image", "Input image" }, { GIMP_PDB_DRAWABLE, "drawable", "Input drawable ()"}, { GIMP_PDB_INT32, "mode", "0 ... number only, 1 .. filename 2 .. filename with path"}, { GIMP_PDB_INT32, "fontsize", "fontsize in pixel"}, { GIMP_PDB_STRING, "font", "fontname "}, { GIMP_PDB_INT32, "posx", "x offset in pixel"}, { GIMP_PDB_INT32, "posy", "y offset in pixel"}, { GIMP_PDB_INT32, "antialias", "0 .. OFF, 1 .. antialias on"}, { GIMP_PDB_INT32, "create_new_layer", "0 .. render on input drawable, 1 .. create new layer"}, }; static GimpParamDef out_args[] = { { GIMP_PDB_DRAWABLE, "affected_drawable", "the drawable where the name/number was rendered." } }; static gint global_number_in_args = G_N_ELEMENTS (in_args); static gint global_number_out_args = G_N_ELEMENTS(out_args); /* Functions */ MAIN () static void query (void) { static GimpLastvalDef lastvals[] = { GIMP_LASTVALDEF_GINT (GIMP_ITER_FALSE, glob_namlvals.mode, "mode"), GIMP_LASTVALDEF_GINT (GIMP_ITER_TRUE, glob_namlvals.fontsize, "fontsize"), GIMP_LASTVALDEF_ARRAY (GIMP_ITER_FALSE, glob_namlvals.fontname, "fontname"), GIMP_LASTVALDEF_GCHAR (GIMP_ITER_FALSE, glob_namlvals.fontname[0], "fontname"), GIMP_LASTVALDEF_GINT (GIMP_ITER_TRUE, glob_namlvals.posx, "posx"), GIMP_LASTVALDEF_GINT (GIMP_ITER_TRUE, glob_namlvals.posy, "posy"), GIMP_LASTVALDEF_GINT (GIMP_ITER_FALSE, glob_namlvals.antialias, "antialias"), GIMP_LASTVALDEF_GINT (GIMP_ITER_FALSE, glob_namlvals.create_new_layer, "create_new_layer"), }; gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); /* registration for last values buffer structure (useful for animated filter apply) */ gimp_lastval_desc_register(PLUG_IN_NAME, &glob_namlvals, sizeof(glob_namlvals), G_N_ELEMENTS (lastvals), lastvals); /* the actual installation of the adjust plugin */ gimp_install_procedure (PLUG_IN_NAME, "Render Filename to Layer", "This plug-in renders the imagename, " "or the numberpart of the imagename onto the image. " "if the parameter create_new_layer is 0, the filename is rendered " "to the input drawable, otherwise a new textlayer is created", PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("Filename to Layer..."), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, global_number_in_args, global_number_out_args, in_args, out_args); // gimp_plugin_menu_branch_register("", "Video"); gimp_plugin_menu_register (PLUG_IN_NAME, N_("/Video/")); } /* end query */ static void run (const gchar *name, /* name of plugin */ gint nparams, /* number of in-paramters */ const GimpParam * param, /* in-parameters */ gint *nreturn_vals, /* number of out-parameters */ GimpParam ** return_vals) /* out-parameters */ { const gchar *l_env; gint32 image_id = -1; /* Get the runmode from the in-parameters */ GimpRunMode run_mode = param[0].data.d_int32; /* status variable, use it to check for errors in invocation usualy only during non-interactive calling */ GimpPDBStatusType status = GIMP_PDB_SUCCESS; /* always return at least the status to the caller. */ static GimpParam values[2]; INIT_I18N(); l_env = g_getenv("NUML_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } if(gap_debug) fprintf(stderr, "\n\nDEBUG: run %s\n", name); /* initialize the return of the status */ values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; values[1].type = GIMP_PDB_DRAWABLE; values[1].data.d_drawable = -1; *nreturn_vals = 1; *return_vals = values; /* get image and drawable */ image_id = param[1].data.d_int32; /* how are we running today? */ switch (run_mode) { case GIMP_RUN_INTERACTIVE: /* Possibly retrieve data from a previous run */ gimp_get_data (PLUG_IN_NAME, &glob_namlvals); /* Get information from the dialog */ if (Naml_dialog() != 0) return; break; case GIMP_RUN_NONINTERACTIVE: /* check to see if invoked with the correct number of parameters */ if (nparams == global_number_in_args) { glob_namlvals.mode = (gint) param[3].data.d_int32; glob_namlvals.fontsize = (gint) param[4].data.d_int32; if(param[5].data.d_string != NULL) { g_snprintf(glob_namlvals.fontname, sizeof(glob_namlvals.fontname), "%s", param[5].data.d_string); } glob_namlvals.posx = (gint) param[6].data.d_int32; glob_namlvals.posy = (gint) param[7].data.d_int32; glob_namlvals.antialias = (gint) param[8].data.d_int32; glob_namlvals.create_new_layer = (gint) param[9].data.d_int32; } else { status = GIMP_PDB_CALLING_ERROR; } break; case GIMP_RUN_WITH_LAST_VALS: /* Possibly retrieve data from a previous run */ gimp_get_data (PLUG_IN_NAME, &glob_namlvals); break; default: break; } if (status == GIMP_PDB_SUCCESS) { /* Run the main function */ values[1].data.d_drawable = p_Naml(image_id, param[2].data.d_drawable); if (values[1].data.d_drawable < 0) { status = GIMP_PDB_CALLING_ERROR; } /* If run mode is interactive, flush displays, else (script) don't do it, as the screen updates would make the scripts slow */ if (run_mode != GIMP_RUN_NONINTERACTIVE) gimp_displays_flush (); /* Store variable states for next run */ if (run_mode == GIMP_RUN_INTERACTIVE) gimp_set_data (PLUG_IN_NAME, &glob_namlvals, sizeof (NamlValues)); } values[0].data.d_status = status; } /* end run */ /* ============================================================================ * p_Naml * The main function * ============================================================================ */ static gint p_Naml (gint32 image_id, gint32 drawable_id) { gint32 l_new_layer_id; gint32 l_drawable_id; gchar *l_imagename; gchar *l_text; if(gap_debug) printf("p_Naml START\n"); l_imagename = g_strdup(gimp_image_get_filename(image_id) ); if(l_imagename == NULL) { l_imagename = g_strdup(" 0"); } l_text = l_imagename; if(gap_debug) printf("p_Naml (1) l_imagename:%s\n", l_imagename); l_drawable_id = -1; if(glob_namlvals.create_new_layer == 0) { l_drawable_id = drawable_id; } if (glob_namlvals.mode == 0) { gchar *l_ext; gchar *l_ptr; gint l_digits; l_ext = NULL; l_ptr = &l_imagename[strlen(l_imagename)-1]; while(l_ptr != l_imagename) { if(*l_ptr == '.') { *l_ptr = '\0'; /* cut off extension part */ l_ext = l_ptr; l_ext++; l_ptr--; break; } l_ptr--; } l_digits = 0; if(l_ptr == l_imagename) { /* the imagename had no extension, restart number search at end of string */ l_ptr = &l_imagename[strlen(l_imagename)-1]; } while(l_ptr != l_imagename) { if((*l_ptr >= '0') && (*l_ptr <= '9')) { l_ptr--; l_digits++; } else { l_text = l_ptr; /* pointer to start of number part in the filename */ if(l_digits > 0) { l_text++; } else { l_text = ""; /* no digits found */ } break; } } } else { if (glob_namlvals.mode == 1) { l_text = &l_imagename[strlen(l_imagename)-1]; while(l_text != l_imagename) { if(*l_text == G_DIR_SEPARATOR) { l_text++; break; } l_text--; } } } gimp_image_undo_group_start(image_id); gimp_selection_none(image_id); l_new_layer_id = gimp_text_fontname( image_id , l_drawable_id /* drawable -1 force create of new layer */ , (float)glob_namlvals.posx /* X */ , (float)glob_namlvals.posy /* Y */ , l_text , 0 /* -1 <= border */ , glob_namlvals.antialias , (float)glob_namlvals.fontsize , 0 /* 0 size in pixels, 1: in points */ , glob_namlvals.fontname ); if(l_drawable_id >= 0) { gimp_floating_sel_anchor(l_new_layer_id); } gimp_image_undo_group_end(image_id); if(gap_debug) printf("p_Naml END layer_id: %d\n", (int)l_new_layer_id); return l_new_layer_id; } /* end p_Naml */ /* ------------------ * Naml_dialog * ------------------ * return 0 .. OK * -1 .. in case of Error or cancel */ static gint Naml_dialog(void) { #define VR_NAME2LAYER_DIALOG_ARGC 9 #define VR_MODELIST_SIZE 3 static GapArrArg argv[VR_NAME2LAYER_DIALOG_ARGC]; gint ii; gint ii_mode; gint ii_fontsize; gint ii_posx; gint ii_posy; gint ii_antialias; gint ii_create_new_layer; static char *radio_modes[VR_MODELIST_SIZE] = {"Number Only", "Filename", "Path/Filename" }; ii=0; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_OPTIONMENU); ii_mode = ii; argv[ii].label_txt = _("Mode:"); argv[ii].help_txt = _("Modes to choose entire filename or just parts of the filename"); argv[ii].radio_argc = VR_MODELIST_SIZE; argv[ii].radio_argv = radio_modes; argv[ii].radio_ret = 0; argv[ii].int_default = 0; argv[ii].has_default = TRUE; argv[ii].text_buf_default = g_strdup("\0"); ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_FONTSEL); argv[ii].label_txt = _("Fontname:"); argv[ii].entry_width = 350; /* pixel */ argv[ii].help_txt = _("Select Fontname"); argv[ii].text_buf_len = sizeof(glob_namlvals.fontname); argv[ii].text_buf_ret = &glob_namlvals.fontname[0]; argv[ii].has_default = TRUE; argv[ii].text_buf_default = g_strdup("-*-Charter-*-r-*-*-24-*-*-*-p-*-*-*"); ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_INT); ii_fontsize = ii; argv[ii].constraint = TRUE; argv[ii].label_txt = _("Fontsize:"); argv[ii].help_txt = _("Fontsize in pixels"); argv[ii].int_min = (gint)1; argv[ii].int_max = (gint)1000; argv[ii].int_ret = (gint)glob_namlvals.fontsize; argv[ii].entry_width = 60; argv[ii].has_default = TRUE; argv[ii].int_default = 24; ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_INT); ii_posx = ii; argv[ii].constraint = TRUE; argv[ii].label_txt = _("X:"); argv[ii].help_txt = _("Position X-offset in pixels"); argv[ii].int_min = (gint)-1000; argv[ii].int_max = (gint)10000; argv[ii].int_ret = (gint)glob_namlvals.posx; argv[ii].entry_width = 60; argv[ii].has_default = TRUE; argv[ii].int_default = 15; ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_INT); ii_posy = ii; argv[ii].constraint = TRUE; argv[ii].label_txt = _("Y:"); argv[ii].help_txt = _("Position Y-offset in pixels"); argv[ii].int_min = (gint)-1000; argv[ii].int_max = (gint)10000; argv[ii].int_ret = (gint)glob_namlvals.posy; argv[ii].entry_width = 60; argv[ii].has_default = TRUE; argv[ii].int_default = 15; ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_TOGGLE); ii_antialias = ii; argv[ii].label_txt = _("Antialias:"); argv[ii].help_txt = _("Use antialias"); argv[ii].int_ret = (gint)glob_namlvals.antialias; argv[ii].has_default = TRUE; argv[ii].int_default = 0; ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_TOGGLE); ii_create_new_layer = ii; argv[ii].label_txt = _("Create Layer:"); argv[ii].help_txt = _("ON: Create a new layer.\n" "OFF: Render on active drawable."); argv[ii].int_ret = (gint)glob_namlvals.antialias; argv[ii].has_default = TRUE; argv[ii].int_default = 0; ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_DEFAULT_BUTTON); argv[ii].label_txt = _("Default"); argv[ii].help_txt = _("Reset all parameters to default values"); ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_HELP_BUTTON); argv[ii].help_id = PLUG_IN_HELP_ID; if(TRUE == gap_arr_ok_cancel_dialog(_("Render Filename to Layer"), _("Settings :"), VR_NAME2LAYER_DIALOG_ARGC, argv)) { glob_namlvals.mode = (gint)(argv[ii_mode].radio_ret); glob_namlvals.fontsize = (gint)(argv[ii_fontsize].int_ret); glob_namlvals.posx = (gint)(argv[ii_posx].int_ret); glob_namlvals.posy = (gint)(argv[ii_posy].int_ret); glob_namlvals.antialias = (gint)(argv[ii_antialias].int_ret); glob_namlvals.create_new_layer = (gint)(argv[ii_create_new_layer].int_ret); return 0; } else { return -1; } } /* end Naml_dialog */ gimp-gap-2.6.0+dfsg.orig/gap/gap_filter_codegen.c0000644000175000017500000007762311212030253021477 0ustar thibautthibaut/* gap_filter_codegen.c * * GAP ... Gimp Animation Plugins * * This Module contains: * - GAP_filter codegenerator procedures for _iterator_ALT procedures * * Note: this code is only used in debug mode, * (for developers (Hackers) to generate code templates * for _iterator_ALT or _Iterator procedures.) */ /* revision history: * * 1.3.17a; 2003/07/29 hof: param types of GimpPlugInInfo.run * procedure follow gimp.1.3.17 changes * 1.1.29b; 2000/11/30 hof: used g_snprintf * version 0.99.00 1999.03.14 hof: Codegeneration of File ./gen_filter_iter_code.c * splittet into single Files XX_iter_ALT.inc * bugfixes in code generation * version 0.95.04 1998.06.12 hof: p_delta_drawable (enable use of layerstack anims * in drawable iteration) * version 0.93.00 hof: generate Iterator Source * in one single file (per plugin), ready to compile * version 0.91.01; Tue Dec 23 hof: 1.st (pre) release */ #include "config.h" /* SYTEM (UNIX) includes */ #include #include #ifdef HAVE_UNISTD_H #include #endif #include /* GIMP includes */ #include "libgimp/gimp.h" /* GAP includes */ #include "gap_filter.h" /* int gap_debug = 1; */ /* print debug infos */ /* int gap_debug = 0; */ /* 0: dont print debug infos */ extern int gap_debug; gint gap_codegen_gen_code_iterator(char *proc_name); #define GEN_FORWARDFILE_NAME "gen_filter_iter_forward.c" #define GEN_TABFILE_NAME "gen_filter_iter_tab.c" void gap_codegen_remove_codegen_files() { g_remove(GEN_FORWARDFILE_NAME); g_remove(GEN_TABFILE_NAME); printf("overwrite file: %s\n", GEN_FORWARDFILE_NAME); printf("overwrite file: %s\n", GEN_TABFILE_NAME); } static char* p_type_to_string(GimpPDBArgType t) { switch (t) { case GIMP_PDB_INT32: return "long "; case GIMP_PDB_INT16: return "short "; case GIMP_PDB_INT8: return "char "; case GIMP_PDB_FLOAT: return "gdouble "; case GIMP_PDB_STRING: return "char *"; case GIMP_PDB_INT32ARRAY: return "INT32ARRAY"; case GIMP_PDB_INT16ARRAY: return "INT16ARRAY"; case GIMP_PDB_INT8ARRAY: return "INT8ARRAY"; case GIMP_PDB_FLOATARRAY: return "FLOATARRAY"; case GIMP_PDB_STRINGARRAY: return "STRINGARRAY"; case GIMP_PDB_COLOR: return "t_color "; case GIMP_PDB_REGION: return "REGION"; case GIMP_PDB_DISPLAY: return "gint32 "; case GIMP_PDB_IMAGE: return "gint32 "; case GIMP_PDB_LAYER: return "gint32 "; case GIMP_PDB_CHANNEL: return "gint32 "; case GIMP_PDB_DRAWABLE: return "gint32 "; case GIMP_PDB_SELECTION: return "SELECTION"; case GIMP_PDB_BOUNDARY: return "BOUNDARY"; case GIMP_PDB_PATH: return "PATH"; case GIMP_PDB_STATUS: return "STATUS"; case GIMP_PDB_END: return "END"; default: return "UNKNOWN?"; } } static void p_get_gendate(char *gendate, gint32 sizeof_gendate) { struct tm *l_t; long l_ti; l_ti = time(0L); /* Get UNIX time */ l_t = localtime(&l_ti); /* konvert time to tm struct */ g_snprintf(gendate, sizeof_gendate, "%02d.%02d.%02d %02d:%02d" , l_t->tm_mday , l_t->tm_mon + 1 , l_t->tm_year , l_t->tm_hour , l_t->tm_min); } static void p_clean_name(char *name, char *clean_name) { char *l_ptr; l_ptr = clean_name; while(*name != '\0') { if((*name == '-') || (*name == '+') || (*name == '/') || (*name == '%') || (*name == '*') || (*name == ':') || (*name == '!') || (*name == '=') || (*name == ';') || (*name == '^') || (*name == ',') || (*name == '[') || (*name == ']') || (*name == '{') || (*name == '}') || (*name == '(') || (*name == ')') || (*name == ' ') || (*name == '$') || (*name == '<') || (*name == '|') || (*name == '>') || (*name == '?') || (*name == '~') ) { *l_ptr = '_'; } else { *l_ptr = *name; } name++; l_ptr++; } *l_ptr = '\0'; } gint gap_codegen_gen_code_iter_ALT(char *proc_name) { FILE *l_fp; gint l_idx; gint l_nparams; gint l_nreturn_vals; GimpPDBProcType l_proc_type; gchar *l_proc_blurb; gchar *l_proc_help; gchar *l_proc_author; gchar *l_proc_copyright; gchar *l_proc_date; GimpParamDef *l_params; GimpParamDef *l_return_vals; gint l_rc; gchar l_filename[512]; gchar l_gendate[30]; gchar l_clean_proc_name[256]; gchar l_clean_par_name[256]; l_rc = 0; p_get_gendate(&l_gendate[0], sizeof(l_gendate)); /* Query the gimp application's procedural database * regarding a particular procedure. */ if (gimp_procedural_db_proc_info (proc_name, &l_proc_blurb, &l_proc_help, &l_proc_author, &l_proc_copyright, &l_proc_date, &l_proc_type, &l_nparams, &l_nreturn_vals, &l_params, &l_return_vals)) { p_clean_name(proc_name, &l_clean_proc_name[0]); /* procedure found in PDB */ if(gap_debug) fprintf(stderr, "DEBUG: found in PDB %s author: %s copyright: %s\n", proc_name, l_proc_author, l_proc_copyright); /* check if plugin can be a typical one, that works on one drawable */ if (l_proc_type != GIMP_PLUGIN) { l_rc = -1; } if (l_nparams < 3) { l_rc = -1; } if (l_params[0].type != GIMP_PDB_INT32) { l_rc = -1; } if (l_params[1].type != GIMP_PDB_IMAGE) { l_rc = -1; } if (l_params[2].type != GIMP_PDB_DRAWABLE) { l_rc = -1; } g_snprintf(l_filename, sizeof(l_filename), "%s_iter_ALT.inc", l_clean_proc_name); l_fp = g_fopen(l_filename, "w"); if(l_fp != NULL) { fprintf(l_fp, "/* ----------------------------------------------------------------------\n"); fprintf(l_fp, " * p_%s_iter_ALT \n", l_clean_proc_name); fprintf(l_fp, " * ----------------------------------------------------------------------\n"); fprintf(l_fp, " */\n"); fprintf(l_fp, "gint p_%s_iter_ALT(GimpRunMode run_mode, gint32 total_steps, gdouble current_step, gint32 len_struct) \n", l_clean_proc_name); fprintf(l_fp, "{\n"); fprintf(l_fp, " typedef struct t_%s_Vals \n", l_clean_proc_name); fprintf(l_fp, " {\n"); for(l_idx = 3; l_idx < l_nparams; l_idx++) { p_clean_name(l_params[l_idx].name, &l_clean_par_name[0]); fprintf(l_fp, " %s %s;\n", p_type_to_string(l_params[l_idx].type), l_clean_par_name); } fprintf(l_fp, " } t_%s_Vals; \n", l_clean_proc_name); fprintf(l_fp, "\n"); fprintf(l_fp, " t_%s_Vals buf, *buf_from, *buf_to; \n", l_clean_proc_name); fprintf(l_fp, "\n"); fprintf(l_fp, " if(len_struct != sizeof(t_%s_Vals)) \n", l_clean_proc_name); fprintf(l_fp, " {\n"); fprintf(l_fp, " printf(\"ERROR: p_\%s_iter_ALT stored Data missmatch in size %%d != %%d\\n\", \n", l_clean_proc_name); fprintf(l_fp, " (int)len_struct, sizeof(t_%s_Vals) ); \n", l_clean_proc_name); fprintf(l_fp, " return -1; /* ERROR */ \n"); fprintf(l_fp, " }\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " gimp_get_data(\"%s%s\", g_plugin_data_from); \n", l_clean_proc_name, GAP_ITER_FROM_SUFFIX); fprintf(l_fp, " gimp_get_data(\"%s%s\", g_plugin_data_to); \n", l_clean_proc_name, GAP_ITER_TO_SUFFIX); fprintf(l_fp, "\n"); fprintf(l_fp, " buf_from = (t_%s_Vals *)&g_plugin_data_from[0]; \n", l_clean_proc_name); fprintf(l_fp, " buf_to = (t_%s_Vals *)&g_plugin_data_to[0]; \n", l_clean_proc_name); fprintf(l_fp, " memcpy(&buf, buf_from, sizeof(buf));\n"); fprintf(l_fp, "\n"); for(l_idx = 3; l_idx < l_nparams; l_idx++) { p_clean_name(l_params[l_idx].name, &l_clean_par_name[0]); switch(l_params[l_idx].type) { case GIMP_PDB_INT32: fprintf(l_fp, " p_delta_long(&buf.%s, buf_from->%s, buf_to->%s, total_steps, current_step);\n", l_clean_par_name, l_clean_par_name, l_clean_par_name); break; case GIMP_PDB_INT16: fprintf(l_fp, " p_delta_short(&buf.%s, buf_from->%s, buf_to->%s, total_steps, current_step);\n", l_clean_par_name, l_clean_par_name, l_clean_par_name); break; case GIMP_PDB_INT8: fprintf(l_fp, " p_delta_char(&buf.%s, buf_from->%s, buf_to->%s, total_steps, current_step);\n", l_clean_par_name, l_clean_par_name, l_clean_par_name); break; case GIMP_PDB_FLOAT: fprintf(l_fp, " p_delta_gdouble(&buf.%s, buf_from->%s, buf_to->%s, total_steps, current_step);\n", l_clean_par_name, l_clean_par_name, l_clean_par_name); break; case GIMP_PDB_COLOR: fprintf(l_fp, " p_delta_color(&buf.%s, &buf_from->%s, &buf_to->%s, total_steps, current_step);\n", l_clean_par_name, l_clean_par_name, l_clean_par_name); break; case GIMP_PDB_DRAWABLE: fprintf(l_fp, " p_delta_drawable(&buf.%s, buf_from->%s, buf_to->%s, total_steps, current_step);\n", l_clean_par_name, l_clean_par_name, l_clean_par_name); break; default: break; } } fprintf(l_fp, "\n"); fprintf(l_fp, " gimp_set_data(\"%s\", &buf, sizeof(buf)); \n", l_clean_proc_name); fprintf(l_fp, "\n"); fprintf(l_fp, " return 0; /* OK */\n"); fprintf(l_fp, "}\n"); fclose(l_fp); } /* free the query information */ g_free (l_proc_blurb); g_free (l_proc_help); g_free (l_proc_author); g_free (l_proc_copyright); g_free (l_proc_date); g_free (l_params); g_free (l_return_vals); } else { return -1; } gap_codegen_gen_code_iterator(proc_name); return l_rc; } /* gap_codegen_gen_code_iter_ALT */ gint gap_codegen_gen_forward_iter_ALT(char *proc_name) { FILE *l_fp; char l_clean_proc_name[256]; p_clean_name(proc_name, &l_clean_proc_name[0]); l_fp = g_fopen(GEN_FORWARDFILE_NAME, "a"); if(l_fp != NULL) { fprintf(l_fp, "static gint p_%s_iter_ALT (GimpRunMode run_mode, gint32 total_steps, gdouble current_step, gint32 len_struct);\n", l_clean_proc_name); fclose(l_fp); } return 0; } gint gap_codegen_gen_tab_iter_ALT(char *proc_name) { FILE *l_fp; char l_clean_proc_name[256]; p_clean_name(proc_name, &l_clean_proc_name[0]); l_fp = g_fopen(GEN_TABFILE_NAME, "a"); if(l_fp != NULL) { fprintf(l_fp, " , { \"%s\", p_%s_iter_ALT }\n", l_clean_proc_name, l_clean_proc_name); fclose(l_fp); } return 0; } /* Generate _Itrerator Procedure all in one .c file, * ready to compile */ gint gap_codegen_gen_code_iterator(char *proc_name) { FILE *l_fp; gint l_idx; gint l_nparams; gint l_nreturn_vals; GimpPDBProcType l_proc_type; gchar *l_proc_blurb; gchar *l_proc_help; gchar *l_proc_author; gchar *l_proc_copyright; gchar *l_proc_date; GimpParamDef *l_params; GimpParamDef *l_return_vals; gint l_rc; gchar l_filename[512]; gchar l_gendate[30]; gchar l_clean_proc_name[256]; gchar l_clean_par_name[256]; l_rc = 0; p_get_gendate(&l_gendate[0], sizeof(l_gendate)); /* Query the gimp application's procedural database * regarding a particular procedure. */ if (gimp_procedural_db_proc_info (proc_name, &l_proc_blurb, &l_proc_help, &l_proc_author, &l_proc_copyright, &l_proc_date, &l_proc_type, &l_nparams, &l_nreturn_vals, &l_params, &l_return_vals)) { p_clean_name(proc_name, &l_clean_proc_name[0]); /* procedure found in PDB */ if(gap_debug) fprintf(stderr, "DEBUG: found in PDB %s\n", proc_name); /* check if plugin can be a typical one, that works on one drawable */ if (l_proc_type != GIMP_PLUGIN) { l_rc = -1; } if (l_nparams < 3) { l_rc = -1; } if (l_params[0].type != GIMP_PDB_INT32) { l_rc = -1; } if (l_params[1].type != GIMP_PDB_IMAGE) { l_rc = -1; } if (l_params[2].type != GIMP_PDB_DRAWABLE) { l_rc = -1; } g_snprintf(l_filename, sizeof(l_filename), "%s_iter.c", l_clean_proc_name); l_fp = g_fopen(l_filename, "w"); if(l_fp != NULL) { fprintf(l_fp, "/* %s\n", l_filename); fprintf(l_fp, " * generated by gap_filter_codegen.c\n"); fprintf(l_fp, " * generation date: %s\n", l_gendate); fprintf(l_fp, " *\n"); fprintf(l_fp, " * generation source Gimp PDB entry name: %s\n", l_clean_proc_name); fprintf(l_fp, " * version : %s\n", l_proc_date); fprintf(l_fp, " *\n"); fprintf(l_fp, " * The generated code will not work if the internal data stucture\n"); fprintf(l_fp, " * (used to store and retrieve \"LastValues\") is different to the\n"); fprintf(l_fp, " * PDB Calling Interface.\n"); fprintf(l_fp, " *\n"); fprintf(l_fp, " * In that case you will get an Error message like that:\n"); fprintf(l_fp, " * ERROR: xxxx_Iterator stored Data missmatch in size N != M\n"); fprintf(l_fp, " * if the Iterator is called. \n"); fprintf(l_fp, " * (via \"Filter all Layers\" using \"Apply Varying\" Button)\n"); fprintf(l_fp, " *\n"); fprintf(l_fp, " * When you get this Error, you should change this generated code.\n"); fprintf(l_fp, " * \n"); fprintf(l_fp, " */\n"); fprintf(l_fp, "\n"); fprintf(l_fp, "/* SYTEM (UNIX) includes */ \n"); fprintf(l_fp, "#include \n"); fprintf(l_fp, "#include \n"); fprintf(l_fp, "#include \n"); fprintf(l_fp, "\n"); fprintf(l_fp, "/* GIMP includes */\n"); fprintf(l_fp, "#include \"gtk/gtk.h\"\n"); fprintf(l_fp, "#include \"libgimp/gimp.h\"\n"); fprintf(l_fp, "\n"); fprintf(l_fp, "typedef struct { guchar color[3]; } t_color; \n"); fprintf(l_fp, "typedef struct { gint color[3]; } t_gint_color; \n"); fprintf(l_fp, "\n"); fprintf(l_fp, "static void query(void); \n"); fprintf(l_fp, "static void run(const gchar *name, gint nparam, const GimpParam *param, gint *nretvals, GimpParam **retvals); \n"); fprintf(l_fp, "\n"); fprintf(l_fp, "GimpPlugInInfo PLUG_IN_INFO = \n"); fprintf(l_fp, "{\n"); fprintf(l_fp, " NULL, /* init_proc */ \n"); fprintf(l_fp, " NULL, /* quit_proc */ \n"); fprintf(l_fp, " query, /* query_proc */ \n"); fprintf(l_fp, " run, /* run_proc */ \n"); fprintf(l_fp, "}; \n"); fprintf(l_fp, "\n"); fprintf(l_fp, "/* ----------------------------------------------------------------------\n"); fprintf(l_fp, " * iterator functions for basic datatypes \n"); fprintf(l_fp, " * ----------------------------------------------------------------------\n"); fprintf(l_fp, " */\n"); fprintf(l_fp, "\n"); fprintf(l_fp, "static void p_delta_long(long *val, long val_from, long val_to, gint32 total_steps, gdouble current_step)\n"); fprintf(l_fp, "{\n"); fprintf(l_fp, " double delta;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " if(total_steps < 1) return;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step);\n"); fprintf(l_fp, " *val = val_from + delta; \n"); fprintf(l_fp, "}\n"); fprintf(l_fp, "static void p_delta_short(short *val, short val_from, short val_to, gint32 total_steps, gdouble current_step)\n"); fprintf(l_fp, "{\n"); fprintf(l_fp, " double delta;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " if(total_steps < 1) return;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step);\n"); fprintf(l_fp, " *val = val_from + delta;\n"); fprintf(l_fp, "}\n"); fprintf(l_fp, "static void p_delta_gint(gint *val, gint val_from, gint val_to, gint32 total_steps, gdouble current_step)\n"); fprintf(l_fp, "{\n"); fprintf(l_fp, " double delta;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " if(total_steps < 1) return;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step);\n"); fprintf(l_fp, " *val = val_from + delta;\n"); fprintf(l_fp, "}\n"); fprintf(l_fp, "static void p_delta_char(char *val, char val_from, char val_to, gint32 total_steps, gdouble current_step)\n"); fprintf(l_fp, "{\n"); fprintf(l_fp, " double delta;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " if(total_steps < 1) return;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step);\n"); fprintf(l_fp, " *val = val_from + delta;\n"); fprintf(l_fp, "}\n"); fprintf(l_fp, "static void p_delta_gdouble(double *val, double val_from, double val_to, gint32 total_steps, gdouble current_step)\n"); fprintf(l_fp, "{\n"); fprintf(l_fp, " double delta;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " if(total_steps < 1) return;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step);\n"); fprintf(l_fp, " *val = val_from + delta;\n"); fprintf(l_fp, "}\n"); fprintf(l_fp, "static void p_delta_float(float *val, float val_from, float val_to, gint32 total_steps, gdouble current_step)\n"); fprintf(l_fp, "{\n"); fprintf(l_fp, " double delta;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " if(total_steps < 1) return;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step);\n"); fprintf(l_fp, " *val = val_from + delta;\n"); fprintf(l_fp, "}\n"); fprintf(l_fp, "static void p_delta_color(t_color *val, t_color *val_from, t_color *val_to, gint32 total_steps, gdouble current_step)\n"); fprintf(l_fp, "{\n"); fprintf(l_fp, " double delta;\n"); fprintf(l_fp, " int l_idx;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " if(total_steps < 1) return;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " for(l_idx = 0; l_idx < 3; l_idx++)\n"); fprintf(l_fp, " {\n"); fprintf(l_fp, " delta = ((double)(val_to->color[l_idx] - val_from->color[l_idx]) / (double)total_steps) * ((double)total_steps - current_step);\n"); fprintf(l_fp, " val->color[l_idx] = val_from->color[l_idx] + delta;\n"); fprintf(l_fp, " }\n"); fprintf(l_fp, "}\n"); fprintf(l_fp, "static void p_delta_gint_color(t_gint_color *val, t_gint_color *val_from, t_gint_color *val_to, gint32 total_steps, gdouble current_step)\n"); fprintf(l_fp, "{\n"); fprintf(l_fp, " double delta;\n"); fprintf(l_fp, " int l_idx;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " if(total_steps < 1) return;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " for(l_idx = 0; l_idx < 3; l_idx++)\n"); fprintf(l_fp, " {\n"); fprintf(l_fp, " delta = ((double)(val_to->color[l_idx] - val_from->color[l_idx]) / (double)total_steps) * ((double)total_steps - current_step);\n"); fprintf(l_fp, " val->color[l_idx] = val_from->color[l_idx] + delta;\n"); fprintf(l_fp, " }\n"); fprintf(l_fp, "}\n"); fprintf(l_fp, "static void p_delta_drawable(gint32 *val, gint32 val_from, gint32 val_to, gint32 total_steps, gdouble current_step)\n"); fprintf(l_fp, "{\n"); fprintf(l_fp, " gint l_nlayers;\n"); fprintf(l_fp, " gint32 *l_layers_list;\n"); fprintf(l_fp, " gint32 l_tmp_image_id;\n"); fprintf(l_fp, " gint l_idx, l_idx_from, l_idx_to;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " l_tmp_image_id = gimp_drawable_get_image(val_from);\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " /* check if from and to values are both valid drawables within the same image */\n"); fprintf(l_fp, " if ((l_tmp_image_id > 0)\n"); fprintf(l_fp, " && (l_tmp_image_id = gimp_drawable_get_image(val_to)))\n"); fprintf(l_fp, " {\n"); fprintf(l_fp, " l_idx_from = -1;\n"); fprintf(l_fp, " l_idx_to = -1;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " /* check the layerstack index of from and to drawable */\n"); fprintf(l_fp, " l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers);\n"); fprintf(l_fp, " for (l_idx = l_nlayers -1; l_idx >= 0; l_idx--)\n"); fprintf(l_fp, " {\n"); fprintf(l_fp, " if( l_layers_list[l_idx] == val_from ) l_idx_from = l_idx;\n"); fprintf(l_fp, " if( l_layers_list[l_idx] == val_to ) l_idx_to = l_idx;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " if((l_idx_from != -1) && (l_idx_to != -1))\n"); fprintf(l_fp, " {\n"); fprintf(l_fp, " /* OK found both index values, iterate the index (proceed to next layer) */\n"); fprintf(l_fp, " p_delta_gint(&l_idx, l_idx_from, l_idx_to, total_steps, current_step);\n"); fprintf(l_fp, " *val = l_layers_list[l_idx];\n"); fprintf(l_fp, " break;\n"); fprintf(l_fp, " }\n"); fprintf(l_fp, " }\n"); fprintf(l_fp, " g_free (l_layers_list);\n"); fprintf(l_fp, " }\n"); fprintf(l_fp, "}\n"); fprintf(l_fp, "\n"); fprintf(l_fp, "/* ----------------------------------------------------------------------\n"); fprintf(l_fp, " * p_%s_iter \n", l_clean_proc_name); fprintf(l_fp, " * ----------------------------------------------------------------------\n"); fprintf(l_fp, " */\n"); fprintf(l_fp, "gint p_%s_iter(GimpRunMode run_mode, gint32 total_steps, gdouble current_step, gint32 len_struct) \n", l_clean_proc_name); fprintf(l_fp, "{\n"); fprintf(l_fp, " typedef struct t_%s_Vals \n", l_clean_proc_name); fprintf(l_fp, " {\n"); for(l_idx = 3; l_idx < l_nparams; l_idx++) { p_clean_name(l_params[l_idx].name, &l_clean_par_name[0]); fprintf(l_fp, " %s %s;\n", p_type_to_string(l_params[l_idx].type), l_clean_par_name); } fprintf(l_fp, " } t_%s_Vals; \n", l_clean_proc_name); fprintf(l_fp, "\n"); fprintf(l_fp, " t_%s_Vals buf, buf_from, buf_to; \n", l_clean_proc_name); fprintf(l_fp, "\n"); fprintf(l_fp, " if(len_struct != sizeof(t_%s_Vals)) \n", l_clean_proc_name); fprintf(l_fp, " {\n"); fprintf(l_fp, " fprintf(stderr, \"ERROR: p_\%s_iter stored Data missmatch in size %%d != %%d\\n\", \n", l_clean_proc_name); fprintf(l_fp, " (int)len_struct, sizeof(t_%s_Vals) ); \n", l_clean_proc_name); fprintf(l_fp, " return -1; /* ERROR */ \n"); fprintf(l_fp, " }\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " gimp_get_data(\"%s%s\", &buf_from); \n", l_clean_proc_name, GAP_ITER_FROM_SUFFIX); fprintf(l_fp, " gimp_get_data(\"%s%s\", &buf_to); \n", l_clean_proc_name, GAP_ITER_TO_SUFFIX); fprintf(l_fp, " memcpy(&buf, &buf_from, sizeof(buf));\n"); fprintf(l_fp, "\n"); for(l_idx = 3; l_idx < l_nparams; l_idx++) { p_clean_name(l_params[l_idx].name, &l_clean_par_name[0]); switch(l_params[l_idx].type) { case GIMP_PDB_INT32: fprintf(l_fp, " p_delta_long(&buf.%s, buf_from.%s, buf_to.%s, total_steps, current_step);\n", l_clean_par_name, l_clean_par_name, l_clean_par_name); break; case GIMP_PDB_INT16: fprintf(l_fp, " p_delta_short(&buf.%s, buf_from.%s, buf_to.%s, total_steps, current_step);\n", l_clean_par_name, l_clean_par_name, l_clean_par_name); break; case GIMP_PDB_INT8: fprintf(l_fp, " p_delta_char(&buf.%s, buf_from.%s, buf_to.%s, total_steps, current_step);\n", l_clean_par_name, l_clean_par_name, l_clean_par_name); break; case GIMP_PDB_FLOAT: fprintf(l_fp, " p_delta_gdouble(&buf.%s, buf_from.%s, buf_to.%s, total_steps, current_step);\n", l_clean_par_name, l_clean_par_name, l_clean_par_name); break; case GIMP_PDB_COLOR: fprintf(l_fp, " p_delta_color(&buf.%s, &buf_from.%s, &buf_to.%s, total_steps, current_step);\n", l_clean_par_name, l_clean_par_name, l_clean_par_name); break; case GIMP_PDB_DRAWABLE: fprintf(l_fp, " p_delta_drawable(&buf.%s, buf_from.%s, buf_to.%s, total_steps, current_step);\n", l_clean_par_name, l_clean_par_name, l_clean_par_name); break; default: break; } } fprintf(l_fp, "\n"); fprintf(l_fp, " gimp_set_data(\"%s\", &buf, sizeof(buf)); \n", l_clean_proc_name); fprintf(l_fp, "\n"); fprintf(l_fp, " return 0; /* OK */\n"); fprintf(l_fp, "}\n"); fprintf(l_fp, "MAIN ()\n"); fprintf(l_fp, "\n"); fprintf(l_fp, "/* ----------------------------------------------------------------------\n"); fprintf(l_fp, " * install (query) %s\n", GAP_ITERATOR_SUFFIX); fprintf(l_fp, " * ----------------------------------------------------------------------\n"); fprintf(l_fp, " */\n"); fprintf(l_fp, "\n"); fprintf(l_fp, "static void query ()\n"); fprintf(l_fp, "{\n"); fprintf(l_fp, " char l_blurb_text[300];\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " static GimpParamDef args_iter[] =\n"); fprintf(l_fp, " {\n"); fprintf(l_fp, " {GIMP_PDB_INT32, \"run_mode\", \"non-interactive\"},\n"); fprintf(l_fp, " {GIMP_PDB_INT32, \"total_steps\", \"total number of steps (# of layers-1 to apply the related plug-in)\"},\n"); fprintf(l_fp, " {GIMP_PDB_FLOAT, \"current_step\", \"current (for linear iterations this is the layerstack position, otherwise some value inbetween)\"},\n"); fprintf(l_fp, " {GIMP_PDB_INT32, \"len_struct\", \"length of stored data structure with id is equal to the plug_in proc_name\"},\n"); fprintf(l_fp, " };\n"); fprintf(l_fp, " static int nargs_iter = G_N_ELEMENTS (args_iter);\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " static GimpParamDef *return_vals = NULL;\n"); fprintf(l_fp, " static int nreturn_vals = 0;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " g_snprintf(l_blurb_text, sizeof(l_blurb_text), \"This procedure calculates the modified values for one iterationstep for the call of %s\");\n", l_clean_proc_name); fprintf(l_fp, "\n"); fprintf(l_fp, " gimp_install_procedure(\"%s%s\",\n", l_clean_proc_name, GAP_ITERATOR_SUFFIX); fprintf(l_fp, " l_blurb_text,\n"); fprintf(l_fp, " \"\",\n"); fprintf(l_fp, " \"Wolfgang Hofer\",\n"); fprintf(l_fp, " \"Wolfgang Hofer\",\n"); fprintf(l_fp, " \"%s\",\n", l_gendate); /* generation date */ fprintf(l_fp, " NULL, /* do not appear in menus */\n"); fprintf(l_fp, " NULL,\n"); fprintf(l_fp, " GIMP_PLUGIN,\n"); fprintf(l_fp, " nargs_iter, nreturn_vals,\n"); fprintf(l_fp, " args_iter, return_vals);\n"); fprintf(l_fp, "\n"); fprintf(l_fp, "}\n"); fprintf(l_fp, "\n"); fprintf(l_fp, "\n"); fprintf(l_fp, "/* ----------------------------------------------------------------------\n"); fprintf(l_fp, " * run Iterator\n"); fprintf(l_fp, " * ----------------------------------------------------------------------\n"); fprintf(l_fp, " */\n"); fprintf(l_fp, "\n"); fprintf(l_fp, "\n"); fprintf(l_fp, "static void\n"); fprintf(l_fp, "run (const gchar *name,\n"); fprintf(l_fp, " gint n_params,\n"); fprintf(l_fp, " const GimpParam *param,\n"); fprintf(l_fp, " gint *nreturn_vals,\n"); fprintf(l_fp, " GimpParam **return_vals)\n"); fprintf(l_fp, "{\n"); fprintf(l_fp, " static GimpParam values[1];\n"); fprintf(l_fp, " GimpRunMode run_mode;\n"); fprintf(l_fp, " GimpPDBStatusType status = GIMP_PDB_SUCCESS;\n"); fprintf(l_fp, " gint32 image_id;\n"); fprintf(l_fp, " gint32 len_struct;\n"); fprintf(l_fp, " gint32 total_steps;\n"); fprintf(l_fp, " gdouble current_step;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " gint32 l_rc;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " *nreturn_vals = 1;\n"); fprintf(l_fp, " *return_vals = values;\n"); fprintf(l_fp, " l_rc = 0;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " run_mode = param[0].data.d_int32;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " if ((run_mode == GIMP_RUN_NONINTERACTIVE) && (n_params == 4))\n"); fprintf(l_fp, " {\n"); fprintf(l_fp, " total_steps = param[1].data.d_int32;\n"); fprintf(l_fp, " current_step = param[2].data.d_float;\n"); fprintf(l_fp, " len_struct = param[3].data.d_int32;\n"); fprintf(l_fp, " l_rc = p_%s_iter(run_mode, total_steps, current_step, len_struct);\n", l_clean_proc_name); fprintf(l_fp, " if(l_rc < 0)\n"); fprintf(l_fp, " {\n"); fprintf(l_fp, " status = GIMP_PDB_EXECUTION_ERROR;\n"); fprintf(l_fp, " }\n"); fprintf(l_fp, " }\n"); fprintf(l_fp, " else status = GIMP_PDB_CALLING_ERROR;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, " values[0].type = GIMP_PDB_STATUS;\n"); fprintf(l_fp, " values[0].data.d_status = status;\n"); fprintf(l_fp, "\n"); fprintf(l_fp, "}\n"); fclose(l_fp); } /* free the query information */ g_free (l_proc_blurb); g_free (l_proc_help); g_free (l_proc_author); g_free (l_proc_copyright); g_free (l_proc_date); g_free (l_params); g_free (l_return_vals); } else { return -1; } return l_rc; } /* gap_codegen_gen_code_iterator */ gimp-gap-2.6.0+dfsg.orig/gap/gap_vex_exec.h0000644000175000017500000000235111212030253020323 0ustar thibautthibaut/* * gap_vex_exec.h * Video Extract worker procedures * based on gap_vid_api (GVA) */ /* * Changelog: * 2003/02/11 v1.2.1a: hof created */ /* * Copyright * * 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_VEX_EXEC #define GAP_VEX_EXEC #include "config.h" /* SYTEM (UNIX) includes */ #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" #include "gap_vex_main.h" /* -------- PRODUCTIVE WORKER PROCEDURES -----------*/ void gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_resi_dialog.h0000644000175000017500000000306411212030253021000 0ustar thibautthibaut/* gap_resi_dialog.h * 1998.07.01 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains the resize and scale Dialog for video frames. * (It just is a shell to call Gimp's resize / scale Dialog ) */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history * gimp 1.3.14a; 2003/05/18 hof: reincarnation of gap_resi_dialog.h * 0.96.00; 1998/07/01 hof: first release */ #ifndef _RESI_DIALOG_H #define _RESI_DIALOG_H /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" /* GAP includes */ #include "gap_range_ops.h" gint gap_resi_dialog (gint32 image_id, GapRangeOpsAsiz asiz_mode, char *title_text, long *size_x, long *size_y, long *offs_x, long *offs_y); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_range_ops.c0000644000175000017500000021547311212030253020500 0ustar thibautthibaut/* gap_range_ops.c * 1997.11.06 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains implementation of range based frame operations. * - gap_range_to_multilayer * - gap_range_flatten * - gap_range_layer_del * - gap_range_conv * - gap_anim_scale * - gap_anim_resize * - gap_anim_crop * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history * 2.1.0a; 2004/11/12 hof: added help buttons * 2.1.0a; 2004/04/26 hof: frames_to_multilayer: do not force save of current image * and use gimp_image_duplicate for the current frame * works faster, and avoid the "not using xcf" dialog (# 125977) * for this plug-in when working with other imagefile formats. * 1.3.25a; 2004/01/21 hof: message text fixes (# 132030) * 1.3.20d; 2003/10/09 hof: sourcecode cleanup, * extended p_frames_to_multilayer to handle selected regions * 1.3.17b; 2003/07/31 hof: message text fixes for translators (# 118392) * 1.3.15a; 2003/06/21 hof: textspacing * 1.3.14a; 2003/05/18 hof: again using gap_resi_dialog (now based on GimpOffsetArea widget) * 1.3.12a; 2003/05/01 hof: merge into CVS-gimp-gap project * 1.3.11a; 2003/01/18 hof: Conditional frame save, added Default Button (p_anim_sizechange_dialog) * 1.3.5a; 2002/04/20 hof: API cleanup * 1.3.5a; 2002/04/06 hof: p_type_convert: use only gimp-1.3.5 supported dither modes (removed GIMP_NODESTRUCT_DITHER) * 1.3.4a; 2002/03/12 hof: removed calls to old resize widget * 1.1.28a; 2000/11/05 hof: check for GIMP_PDB_SUCCESS (not for FALSE) * 1.1.24a 2000/07/01 hof: bugfix: flatten of singlelayer images has to remove alpha channel * 1.1.17b 2000/02/26 hof: bugfixes * 1.1.14a 2000/01/06 hof: gap_range_to_multilayer: use framerate (from video info file) in framenames * bugfix: gap_range_to_multilayer: first save current frame * 1.1.10a 1999/10/22 hof: bugfix: have to use the changed PDB-Interface * for gimp_convert_indexed * (with extended dither options and extra dialog window) * 1.1.9a 1999/09/21 hof: bugfix GIMP_RUN_NONINTERACTIVE did not work in * plug_in_gap_range_convert * plug_in_gap_range_layer_del * plug_in_gap_range_flatten * 1.1.8 1999/08/31 hof: frames convert: save subsequent frames * with rumode GIMP_RUN_WITH_LAST_VALS * 0.97.00; 1998/10/19 hof: gap_range_to_multilayer: extended layer selection * 0.96.03; 1998/08/31 hof: gap_range_to_multilayer: all params available * in non-interactive runmode * 0.96.02; 1998/08/05 hof: - p_frames_to_multilayer added framerate support * 0.96.00; 1998/07/01 hof: - added scale, resize and crop * (affects full range == all video frames) * - now using gap_arr_dialog.h * 0.94.01; 1998/04/28 hof: added flatten_mode to plugin: gap_range_to_multilayer * 0.92.00 1998.01.10 hof: bugfix in p_frames_to_multilayer * layers need alpha (to be raise/lower able) * 0.90.00 first development release */ #include "config.h" /* SYTEM (UNIX) includes */ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif /* GIMP includes */ #include "gtk/gtk.h" #include "config.h" #include "gap-intl.h" #include "libgimp/gimp.h" /* GAP includes */ #include "gap_layer_copy.h" #include "gap_lib.h" #include "gap_pdb_calls.h" #include "gap_match.h" #include "gap_arr_dialog.h" #include "gap_resi_dialog.h" #include "gap_mod_layer.h" #include "gap_image.h" #include "gap_range_ops.h" #include "gap_vin.h" extern int gap_debug; /* ==0 ... dont print debug infos */ #define GAP_HELP_ID_FLATTEN "plug-in-gap-range-flatten" #define GAP_HELP_ID_LAYER_DEL "plug-in-gap-range-layer-del" #define GAP_HELP_ID_CONVERT "plug-in-gap-range-convert" #define GAP_HELP_ID_TO_MULTILAYER "plug-in-gap-range-to-multilayer" /* ============================================================================ * p_anim_sizechange_dialog * dialog window with 2 (or 4) entry fields * where the user can select the new video frame (Image)-Size * (if cnt == 4 additional Inputfields for offests are available) * return -1 in case of cancel or any error * (include check for change of current frame) * return positve (0 or layerstack position) if everythig OK * ============================================================================ */ static int p_anim_sizechange_dialog(GapAnimInfo *ainfo_ptr, GapRangeOpsAsiz asiz_mode, long *size_x, long *size_y, long *offs_x, long *offs_y) { static GapArrArg argv[5]; gint cnt; gchar *title; gchar *hline; gint l_width; gint l_height; gint l_rc; /* get info about the image (size is common to all frames) */ l_width = gimp_image_width(ainfo_ptr->image_id); l_height = gimp_image_height(ainfo_ptr->image_id); gap_arr_arg_init(&argv[0], GAP_ARR_WGT_INT_PAIR); argv[0].label_txt = _("New Width:"); argv[0].constraint = FALSE; argv[0].int_min = 1; argv[0].int_max = 1024; argv[0].umin = 1; argv[0].umax = 10000; argv[0].int_ret = l_width; argv[0].has_default = TRUE; argv[0].int_default = l_width; gap_arr_arg_init(&argv[1], GAP_ARR_WGT_INT_PAIR); argv[1].label_txt = _("New Height:"); argv[1].constraint = FALSE; argv[1].int_min = 1; argv[1].int_max = 1024; argv[1].umin = 1; argv[1].umax = 10000; argv[1].int_ret = l_height; argv[1].has_default = TRUE; argv[1].int_default = l_height; gap_arr_arg_init(&argv[2], GAP_ARR_WGT_INT_PAIR); argv[2].label_txt = _("Offset X:"); argv[2].constraint = FALSE; argv[2].int_min = 0; argv[2].int_max = l_width; argv[2].umin = 0; argv[2].umax = 10000; argv[2].int_ret = 0; argv[2].has_default = TRUE; argv[2].int_default = 0; gap_arr_arg_init(&argv[3], GAP_ARR_WGT_INT_PAIR); argv[3].label_txt = _("Offset Y:"); argv[3].constraint = FALSE; argv[3].int_min = 0; argv[3].int_max = l_height; argv[3].umin = 0; argv[3].umax = 10000; argv[3].int_ret = 0; argv[3].has_default = TRUE; argv[3].int_default = 0; switch(asiz_mode) { case GAP_ASIZ_CROP: title = _("Crop Video Frames (all)"); hline = g_strdup_printf (_("Crop (original %dx%d)"), l_width, l_height); argv[0].int_max = l_width; argv[0].constraint = TRUE; argv[1].int_max = l_height; argv[1].constraint = TRUE; argv[2].constraint = TRUE; argv[3].constraint = TRUE; cnt = 4; break; case GAP_ASIZ_RESIZE: title = _("Resize Video Frames (all)"); hline = g_strdup_printf (_("Resize (original %dx%d)"), l_width, l_height); argv[2].int_min = -l_width; argv[3].int_min = -l_height; cnt = 4; break; default: title = _("Scale Video Frames (all)"); hline = g_strdup_printf (_("Scale (original %dx%d)"), l_width, l_height); cnt = 2; break; } gap_arr_arg_init(&argv[cnt], GAP_ARR_WGT_DEFAULT_BUTTON); argv[cnt].label_txt = _("Reset"); /* should use GIMP_STOCK_RESET if possible */ argv[cnt].help_txt = _("Reset parameters to original size"); cnt++; if(0 != gap_lib_chk_framerange(ainfo_ptr)) return -1; if(1==0) { /* array dialog is a primitive GUI to CROP SCALE or RESIZE Frames. * In gimp-1.2 GAP used a copy of the old gimp RESIZE and SCALE dialog-widget code. */ l_rc = gap_arr_ok_cancel_dialog(title, hline, cnt, argv); *size_x = (long)(argv[0].int_ret); *size_y = (long)(argv[1].int_ret); *offs_x = (long)(argv[2].int_ret); *offs_y = (long)(argv[3].int_ret); if(asiz_mode == GAP_ASIZ_CROP) { /* Clip size down to image borders */ if((*size_x + *offs_x) > l_width) { *size_x = l_width - *offs_x; } if((*size_y + *offs_y) > l_height) { *size_y = l_height - *offs_y; } } } else { /* better GUI (analog to GIMP-core) is not finished YET */ l_rc = gap_resi_dialog(ainfo_ptr->image_id, asiz_mode, title, size_x, size_y, offs_x, offs_y); } g_free (hline); if(l_rc == TRUE) { if(0 != gap_lib_chk_framechange(ainfo_ptr)) { return -1; } return 0; /* OK */ } else { return -1; } } /* end p_anim_sizechange_dialog */ /* ============================================================================ * p_range_dialog * dialog window with 2 (or 3) entry fields * where the user can select a frame range (FROM TO) * (if cnt == 3 additional Layerstackposition) * return -1 in case of cancel or any error * (include check for change of current frame) * return positve (0 or layerstack position) if everythig OK * ============================================================================ */ static int p_range_dialog(GapAnimInfo *ainfo_ptr, long *range_from, long *range_to, char *title, char *hline, gint cnt, const char *help_id) { static GapArrArg argv[4]; gint argc; argc = 0; gap_arr_arg_init(&argv[argc], GAP_ARR_WGT_INT_PAIR); argv[argc].label_txt = _("From Frame:"); argv[argc].help_txt = _("First handled frame"); argv[argc].constraint = TRUE; argv[argc].int_min = (gint)ainfo_ptr->first_frame_nr; argv[argc].int_max = (gint)ainfo_ptr->last_frame_nr; argv[argc].int_ret = (gint)ainfo_ptr->curr_frame_nr; argc++; gap_arr_arg_init(&argv[argc], GAP_ARR_WGT_INT_PAIR); argv[argc].label_txt = _("To Frame:"); argv[argc].help_txt = _("Last handled frame"); argv[argc].constraint = TRUE; argv[argc].int_min = (gint)ainfo_ptr->first_frame_nr; argv[argc].int_max = (gint)ainfo_ptr->last_frame_nr; argv[argc].int_ret = (gint)ainfo_ptr->last_frame_nr; argc++; if(cnt == 3) { gap_arr_arg_init(&argv[argc], GAP_ARR_WGT_INT_PAIR); argv[argc].label_txt = _("Layerstack:"); argv[argc].help_txt = _("Layerstack position where 0 is the top layer"); argv[argc].constraint = FALSE; argv[argc].int_min = 0; argv[argc].int_max = 99; argv[argc].umin = 0; argv[argc].umax = 999999; argv[argc].int_ret = 0; argc++; } if(help_id) { gap_arr_arg_init(&argv[argc], GAP_ARR_WGT_HELP_BUTTON); argv[argc].help_id = help_id; argc++; } if(0 != gap_lib_chk_framerange(ainfo_ptr)) return -1; if(TRUE == gap_arr_ok_cancel_dialog(title, hline, argc, argv)) { *range_from = (long)(argv[0].int_ret); *range_to = (long)(argv[1].int_ret); if(0 != gap_lib_chk_framechange(ainfo_ptr)) { return -1; } return (int)(argv[2].int_ret); } else { return -1; } } /* end p_range_dialog */ /* ============================================================================ * p_convert_indexed_dialog * * extra dialog with dither options (when converting to indexed image type) * return 0 .. OK * -1 .. in case of Error or cancel * ============================================================================ */ static long p_convert_indexed_dialog(gint32 *dest_colors, gint32 *dest_dither, gint32 *palette_type, gint32 *alpha_dither, gint32 *remove_unused, char *palette, gint len_palette) { #define ARGC_INDEXED 6 static GapArrArg argv[ARGC_INDEXED]; static char *radio_paltype[4] = { N_("Generate Optimal Palette") , N_("WEB Palette") , N_("Use Custom Palette") , N_("Use Black/White (1-Bit) Palette") }; static char *radio_dither[4] = { N_("Floyd-Steinberg Color Dithering (Normal)") , N_("Floyd-Steinberg Color Dithering (Reduced Color Bleeding)") , N_("Positioned Color Dithering") , N_("No Color Dithering") }; static int gettextize_loop = 0; for (;gettextize_loop < 4; gettextize_loop++) radio_paltype[gettextize_loop] = gettext(radio_paltype[gettextize_loop]); for (;gettextize_loop < 4; gettextize_loop++) radio_dither[gettextize_loop] = gettext(radio_dither[gettextize_loop]); gap_arr_arg_init(&argv[0], GAP_ARR_WGT_RADIO); argv[0].label_txt = _("Palette Type"); argv[0].help_txt = NULL; argv[0].radio_argc = 4; argv[0].radio_argv = radio_paltype; argv[0].radio_ret = 0; gap_arr_arg_init(&argv[1], GAP_ARR_WGT_TEXT); argv[1].label_txt = _("Custom Palette"); argv[1].help_txt = _("Name of a custom palette (ignored if palette type is not custom)"); argv[1].text_buf_len = len_palette; argv[1].text_buf_ret = palette; gap_arr_arg_init(&argv[2], GAP_ARR_WGT_TOGGLE); argv[2].label_txt = _("Remove Unused"); argv[2].help_txt = _("Remove unused or double colors (ignored if palette type is not custom)"); argv[2].int_ret = 1; gap_arr_arg_init(&argv[3], GAP_ARR_WGT_INT_PAIR); argv[3].constraint = TRUE; argv[3].label_txt = _("Number of Colors"); argv[3].help_txt = _("Number of resulting colors (ignored if palette type is not generate optimal palette)"); argv[3].int_min = 2; argv[3].int_max = 256; argv[3].int_ret = 255; gap_arr_arg_init(&argv[4], GAP_ARR_WGT_RADIO); argv[4].label_txt = _("Dither Options"); argv[4].help_txt = NULL; argv[4].radio_argc = 4; argv[4].radio_argv = radio_dither; argv[4].radio_ret = 0; gap_arr_arg_init(&argv[5], GAP_ARR_WGT_TOGGLE); argv[5].label_txt = _("Enable Transparency"); argv[5].help_txt = _("Enable dithering of transparency"); argv[5].int_ret = 0; if(TRUE == gap_arr_ok_cancel_dialog( _("Convert Frames to Indexed"), _("Palette and Dither Settings"), ARGC_INDEXED, argv)) { switch(argv[0].radio_ret) { case 3: *palette_type = GIMP_MONO_PALETTE; break; case 2: *palette_type = GIMP_CUSTOM_PALETTE; break; case 1: *palette_type = GIMP_WEB_PALETTE; break; default: *palette_type = GIMP_MAKE_PALETTE; break; } *remove_unused = (gint32)(argv[2].int_ret);; *dest_colors = (gint32)(argv[3].int_ret); switch(argv[4].radio_ret) { case 3: *dest_dither = GIMP_NO_DITHER; /* 0 */ break; case 2: *dest_dither = GIMP_FIXED_DITHER; /* 3 */ break; case 1: *dest_dither = GIMP_FSLOWBLEED_DITHER; /* 2 */ break; default: *dest_dither = GIMP_FS_DITHER; /* 1 */ break; } *alpha_dither = (gint32)(argv[5].int_ret); return 0; } else { return -1; } } /* ============================================================================ * p_convert_dialog * * return 0 .. OK * -1 .. in case of Error or cancel * ============================================================================ */ static long p_convert_dialog(GapAnimInfo *ainfo_ptr, long *range_from, long *range_to, long *flatten, GimpImageBaseType *dest_type, gint32 *dest_colors, gint32 *dest_dither, char *basename, gint len_base, char *extension, gint len_ext, gint32 *palette_type, gint32 *alpha_dither, gint32 *remove_unused, char *palette, gint len_palette) { static GapArrArg argv[8]; static char *radio_args[4] = { N_("Keep Type"), N_("Convert to RGB"), N_("Convert to Gray"), N_("Convert to Indexed") }; static int gettextize_loop = 0; for (;gettextize_loop < 4; gettextize_loop++) radio_args[gettextize_loop] = gettext(radio_args[gettextize_loop]); gap_arr_arg_init(&argv[0], GAP_ARR_WGT_INT_PAIR); argv[0].constraint = TRUE; argv[0].label_txt = _("From Frame:"); argv[0].help_txt = _("First handled frame"); argv[0].int_min = (gint)ainfo_ptr->first_frame_nr; argv[0].int_max = (gint)ainfo_ptr->last_frame_nr; argv[0].int_ret = (gint)ainfo_ptr->curr_frame_nr; gap_arr_arg_init(&argv[1], GAP_ARR_WGT_INT_PAIR); argv[1].constraint = TRUE; argv[1].label_txt = _("To Frame:"); argv[1].help_txt = _("Last handled frame"); argv[1].int_min = (gint)ainfo_ptr->first_frame_nr; argv[1].int_max = (gint)ainfo_ptr->last_frame_nr; argv[1].int_ret = (gint)ainfo_ptr->last_frame_nr; gap_arr_arg_init(&argv[2], GAP_ARR_WGT_LABEL); argv[2].label_txt = " "; gap_arr_arg_init(&argv[3], GAP_ARR_WGT_FILESEL); argv[3].label_txt = _("Basename:"); argv[3].help_txt = _("basename of the resulting frames. The number part and extension " "(000001.ext) is added automatically to all converted frames."); argv[3].text_buf_len = len_base; argv[3].text_buf_ret = basename; gap_arr_arg_init(&argv[4], GAP_ARR_WGT_TEXT); argv[4].label_txt = _("Extension:"); argv[4].help_txt = _("The extension of resulting frames is also used to define the fileformat. " "Please note that fileformats differ in capabilities to store information for " "multiple layers and other things. " "Some fileformats may require converting to another imagetype " "and/or flattening the frames."); argv[4].text_buf_len = len_ext; argv[4].text_buf_ret = extension; gap_arr_arg_init(&argv[5], GAP_ARR_WGT_OPTIONMENU); argv[5].label_txt = _("Imagetype:"); argv[5].help_txt = _("Convert to another imagetype, or keep imagetype as it is. " "Most fileformats can't handle all types and may require a conversion." "Example: GIF can not handle RGB and requires convert to indexed imagetype."); argv[5].radio_argc = 4; argv[5].radio_argv = radio_args; argv[5].radio_ret = 0; gap_arr_arg_init(&argv[6], GAP_ARR_WGT_TOGGLE); argv[6].label_txt = _("Flatten:"); argv[6].help_txt = _("Flatten all resulting frames. Most fileformats can not handle multiple layers " "and need flattened frames (flattening does melt down all layers to one composite layer)." "Example: JPEG can not handle multiple layers and requires flattened frames."); argv[6].int_ret = 1; gap_arr_arg_init(&argv[7], GAP_ARR_WGT_HELP_BUTTON); argv[7].help_id = GAP_HELP_ID_CONVERT; if(0 != gap_lib_chk_framerange(ainfo_ptr)) return -1; if(TRUE == gap_arr_ok_cancel_dialog( _("Convert Frames to other Formats"), _("Convert Settings"), 8, argv)) { *range_from = (long)(argv[0].int_ret); *range_to = (long)(argv[1].int_ret); switch(argv[5].radio_ret) { case 1: *dest_type = GIMP_RGB; break; case 2: *dest_type = GIMP_GRAY; break; case 3: *dest_type = GIMP_INDEXED; break; default: *dest_type = 9444; /* huh ?? */ break; } *flatten = (long)(argv[6].int_ret); *dest_colors = 255; *dest_dither = 0; *palette_type = 2; /* WEB palette */ *alpha_dither = 0; *remove_unused = 0; if(*dest_type == GIMP_INDEXED) { /* Open a 2.nd dialog for the Dither Options */ if(0 != p_convert_indexed_dialog(dest_colors, dest_dither, palette_type, alpha_dither, remove_unused, palette, len_palette )) { return -1; } } if(0 != gap_lib_chk_framechange(ainfo_ptr)) { return -1; } return 0; } else { return -1; } } /* end p_convert_dialog */ /* ============================================================================ * p_range_to_multilayer_dialog * dialog window with 4 entry fields * where the user can select a frame range (FROM TO) * return -1 in case of cancel or any error * (include check for change of current frame) * return positve (0 or layerstack position) if everythig OK * ============================================================================ */ static int p_range_to_multilayer_dialog(GapAnimInfo *ainfo_ptr, long *range_from, long *range_to, long *flatten_mode, long *bg_visible, long *framrate, char *frame_basename, gint len_frame_basename, char *title, char *hline, gint32 *layersel_mode, gint32 *layersel_case, gint32 *sel_invert, char *sel_pattern, gint32 *selection_mode) { static GapArrArg argv[13]; int argc; static char *radio_args[4] = { N_("Expand as necessary"), N_("Clipped to image"), N_("Clipped to bottom layer"), N_("Flattened image") }; static char *radio_help[4] = { N_("Resulting layer size is made of the outline-rectangle of all visible layers (may differ from frame to frame)"), N_("Resulting layer size is the frame size"), N_("Resulting layer size is the size of the bottom layer (may differ from frame to frame)"), N_("Resulting layer size is the frame size and transparent parts are filled with the background color") }; /* Layer select modes */ static char *layersel_args[7] = { N_("Pattern is equal to layer name"), N_("Pattern is start of layer name"), N_("Pattern is end of layer name"), N_("Pattern is a part of layer name"), N_("Pattern is a list of layerstack numbers"), N_("Pattern is a list of reverse layerstack numbers"), N_("All visible (ignore pattern)") }; static char *layersel_help[7] = { N_("Select all layers where layername is equal to pattern"), N_("Select all layers where layername starts with pattern"), N_("Select all layers where layername ends up with pattern"), N_("Select all layers where layername contains pattern"), N_("Select layerstack positions where 0 is the top layer.\nExample: 0, 4-5, 8"), N_("Select layerstack positions where 0 is the background layer.\nExample: 0, 4-5, 8"), N_("Select all visible layers") }; /* Selection modes */ static char *selection_args[3] = { N_("Ignore"), N_("Initial frame"), N_("Frame specific") }; static char *selection_help[3] = { N_("Pick layers at full size. " "Ignore all pixel selections in all frames"), N_("Pick only the selected pixels. " "Use the selection from the invoking frame " "as fixed selection in all handled frames."), N_("Pick only the selected pixels. " "Use the individual selection " "as it is in each handled frame.") }; static int gettextize_radio = 0, gettextize_layersel = 0, gettextize_sel = 0; for (;gettextize_radio < 4; gettextize_radio++) { radio_args[gettextize_radio] = gettext(radio_args[gettextize_radio]); radio_help[gettextize_radio] = gettext(radio_help[gettextize_radio]); } for (;gettextize_layersel < 4; gettextize_layersel++) { layersel_args[gettextize_layersel] = gettext(layersel_args[gettextize_layersel]); layersel_help[gettextize_layersel] = gettext(layersel_help[gettextize_layersel]); } for (;gettextize_sel < 4; gettextize_sel++) { layersel_args[gettextize_sel] = gettext(layersel_args[gettextize_sel]); layersel_help[gettextize_sel] = gettext(layersel_help[gettextize_sel]); } gap_arr_arg_init(&argv[0], GAP_ARR_WGT_INT_PAIR); argv[0].constraint = TRUE; argv[0].label_txt = _("From Frame:"); argv[0].help_txt = _("First handled frame"); argv[0].int_min = (gint)ainfo_ptr->first_frame_nr; argv[0].int_max = (gint)ainfo_ptr->last_frame_nr; argv[0].int_ret = (gint)ainfo_ptr->curr_frame_nr; gap_arr_arg_init(&argv[1], GAP_ARR_WGT_INT_PAIR); argv[1].constraint = TRUE; argv[1].label_txt = _("To Frame:"); argv[1].help_txt = _("Last handled frame"); argv[1].int_min = (gint)ainfo_ptr->first_frame_nr; argv[1].int_max = (gint)ainfo_ptr->last_frame_nr; argv[1].int_ret = (gint)ainfo_ptr->last_frame_nr; gap_arr_arg_init(&argv[2], GAP_ARR_WGT_TEXT); argv[2].label_txt = _("Layer Basename:"); argv[2].help_txt = _("Basename for all layers where the string '[######]' is replaced by the frame number"); argv[2].text_buf_len = len_frame_basename; argv[2].text_buf_ret = frame_basename; /* Framerate is not used any longer */ /* gap_arr_arg_init(&argv[3], GAP_ARR_WGT_INT_PAIR); argv[3].constraint = FALSE; argv[3].label_txt = "Framerate :"; argv[3].help_txt = "Framedelay in ms"; argv[3].int_min = (gint)0; argv[3].int_max = (gint)300; argv[3].int_ret = (gint)50; */ gap_arr_arg_init(&argv[3], GAP_ARR_WGT_LABEL); argv[3].label_txt = " "; gap_arr_arg_init(&argv[4], GAP_ARR_WGT_RADIO); argv[4].label_txt = _("Layer Mergemode:"); argv[4].radio_argc = 4; argv[4].radio_argv = radio_args; argv[4].radio_help_argv = radio_help; argv[4].radio_ret = 1; gap_arr_arg_init(&argv[5], GAP_ARR_WGT_TOGGLE); argv[5].label_txt = _("Exclude BG-Layer:"); argv[5].help_txt = _("Exclude the background layer in all handled frames, " "regardless to the other settings of layer selection."); argv[5].int_ret = 0; /* 1: exclude BG Layer from all selections */ /* Layer select mode RADIO buttons */ gap_arr_arg_init(&argv[6], GAP_ARR_WGT_RADIO); argv[6].label_txt = _("Layer Selection:"); argv[6].radio_argc = 7; argv[6].radio_argv = layersel_args; argv[6].radio_help_argv = layersel_help; argv[6].radio_ret = 6; /* Layer select pattern string */ g_snprintf (sel_pattern, 2, "0"); gap_arr_arg_init(&argv[7], GAP_ARR_WGT_TEXT); argv[7].label_txt = _("Layer Pattern:"); argv[7].entry_width = 140; /* pixel */ argv[7].help_txt = _("String to identify layer(s) by name or by layerstack position numbers. " "Example: 0,3-5"); argv[7].text_buf_len = MAX_LAYERNAME; argv[7].text_buf_ret = sel_pattern; /* case sensitive checkbutton */ gap_arr_arg_init(&argv[8], GAP_ARR_WGT_TOGGLE); argv[8].label_txt = _("Case sensitive:"); argv[8].help_txt = _("Lowercase and uppercase letters are considered as different"); argv[8].int_ret = 1; /* invert selection checkbutton */ gap_arr_arg_init(&argv[9], GAP_ARR_WGT_TOGGLE); argv[9].label_txt = _("Invert Layer Selection:"); argv[9].help_txt = _("Use all unselected layers"); argv[9].int_ret = 0; /* selection mode */ gap_arr_arg_init(&argv[10], GAP_ARR_WGT_RADIO); argv[10].label_txt = _("Pixel Selection:"); argv[10].radio_argc = 3; argv[10].radio_argv = selection_args; argv[10].radio_help_argv = selection_help; argv[10].radio_ret = GAP_RANGE_OPS_SEL_IGNORE; gap_arr_arg_init(&argv[11], GAP_ARR_WGT_HELP_BUTTON); argv[11].help_id = GAP_HELP_ID_TO_MULTILAYER; argc = 12; if (gimp_image_base_type(ainfo_ptr->image_id) == GIMP_INDEXED) { gap_arr_arg_init(&argv[12], GAP_ARR_WGT_LABEL); argv[12].label_txt = _("You are using INDEXED frames. please note that the result will be an RGB image"); argc = 13; } if(0 != gap_lib_chk_framerange(ainfo_ptr)) return -1; if(TRUE == gap_arr_ok_cancel_dialog(title, hline, argc, argv)) { *range_from = (long)(argv[0].int_ret); *range_to = (long)(argv[1].int_ret); *framrate = (long)(argv[3].int_ret); *flatten_mode = (long)(argv[4].int_ret); if (argv[5].int_ret == 0) *bg_visible = 1; /* 1: use BG like any Layer */ else *bg_visible = 0; /* 0: exclude (ignore) BG Layer */ *layersel_mode = argv[6].int_ret; /* [7] sel_pattern */ *layersel_case = argv[8].int_ret; *sel_invert = argv[9].int_ret; *selection_mode = argv[10].int_ret; if(0 != gap_lib_chk_framechange(ainfo_ptr)) { return -1; } return 0; } else { return -1; } } /* end p_range_to_multilayer_dialog */ /* ============================================================================ * p_frames_to_multilayer * returns image_id of the new created multilayer image * (or -1 on error) * ============================================================================ */ static gint32 p_frames_to_multilayer(GapAnimInfo *ainfo_ptr, long range_from, long range_to, long flatten_mode, long bg_visible, long framerate, char *frame_basename, gint32 layersel_mode, gint32 layersel_case, gint32 sel_invert, char *sel_pattern, gint32 selection_mode) { GimpImageBaseType l_type; guint l_width, l_height; long l_cur_frame_nr; long l_step, l_begin, l_end; long l_vidx; gint32 l_tmp_image_id; gint32 l_new_image_id; gint32 l_cp_layer_id; gint32 l_tmp_layer_id; gint l_src_offset_x, l_src_offset_y; /* layeroffsets as they were in src_image */ gint l_nlayers; gint32 *l_layers_list; gint l_visible; gint l_nvisible; gint l_nlayers_result; gdouble l_percentage, l_percentage_step; static char l_layername[256]; GapModLayliElem *l_layli_ptr; gint32 l_sel_cnt; gboolean l_clear_selected_area; gint32 calling_image_id; gint32 calling_frame_nr; gdouble l_xresoulution, l_yresoulution; gint32 l_unit; calling_image_id = ainfo_ptr->image_id; calling_frame_nr = ainfo_ptr->curr_frame_nr; l_percentage = 0.0; l_nlayers_result = 0; if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE) { gimp_progress_init( _("Creating layer-animated image...")); } l_tmp_layer_id = -1; /* get info about the image (size type and resolution is common to all frames) */ l_width = gimp_image_width(ainfo_ptr->image_id); l_height = gimp_image_height(ainfo_ptr->image_id); l_type = gimp_image_base_type(ainfo_ptr->image_id); l_unit = gimp_image_get_unit(ainfo_ptr->image_id); gimp_image_get_resolution(ainfo_ptr->image_id, &l_xresoulution, &l_yresoulution); if (l_type == GIMP_INDEXED) { l_type = GIMP_RGB; } l_new_image_id = gimp_image_new(l_width, l_height,l_type); gimp_image_set_resolution(l_new_image_id, l_xresoulution, l_yresoulution); gimp_image_set_unit(l_new_image_id, l_unit); l_visible = TRUE; /* only the 1.st layer should be visible */ l_clear_selected_area = FALSE; l_begin = range_from; l_end = range_to; if(range_from > range_to) { l_step = -1; /* operate in descending (reverse) order */ l_percentage_step = 1.0 / ((1.0 + range_from) - range_to); if(range_to < ainfo_ptr->first_frame_nr) { l_begin = ainfo_ptr->first_frame_nr; } if(range_from > ainfo_ptr->last_frame_nr) { l_end = ainfo_ptr->last_frame_nr; } } else { l_step = 1; /* operate in ascending order */ l_percentage_step = 1.0 / ((1.0 + range_to) - range_from); if(range_from < ainfo_ptr->first_frame_nr) { l_begin = ainfo_ptr->first_frame_nr; } if(range_to > ainfo_ptr->last_frame_nr) { l_end = ainfo_ptr->last_frame_nr; } } if(selection_mode == GAP_RANGE_OPS_SEL_INITIAL) { if(!gimp_selection_is_empty(ainfo_ptr->image_id)) { gint32 l_initial_selection_channel_id; gint32 l_new_selection_channel_id; gimp_selection_all(l_new_image_id); l_new_selection_channel_id = gimp_image_get_selection(l_new_image_id); /* get the initial selection from the image * (from where this plugin was invoked) */ l_initial_selection_channel_id = gimp_image_get_selection(ainfo_ptr->image_id); /* copy the initial selection to the newly create image */ gap_layer_copy_content(l_new_selection_channel_id /* dst_drawable_id */ , l_initial_selection_channel_id /* src_drawable_id */ ); /* invert the (copied initial selection) in the newly create image */ gimp_selection_invert(l_new_image_id); l_clear_selected_area = TRUE; } } l_cur_frame_nr = l_begin; while(1) { /* build the frame name */ if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename); ainfo_ptr->new_filename = gap_lib_alloc_fname(ainfo_ptr->basename, l_cur_frame_nr, ainfo_ptr->extension); if(ainfo_ptr->new_filename == NULL) goto error; if(l_cur_frame_nr == calling_frame_nr) { /* for the current image use duplicate */ l_tmp_image_id = gimp_image_duplicate(calling_image_id); } else { /* load current frame into temporary image */ l_tmp_image_id = gap_lib_load_image(ainfo_ptr->new_filename); } if(l_tmp_image_id < 0) goto error; gimp_image_undo_disable(l_tmp_image_id); if (gimp_image_base_type(l_tmp_image_id) == GIMP_INDEXED) { /* INDEXED frame images are converted to RGB * - the resulting multilayer image has no loss in quality * (regardless if the frames have different palettes.) * - some of the following processing steps would not * work with INDEXED images. */ gimp_image_convert_rgb(l_tmp_image_id); } /* get informations (id, visible, selected) about all layers */ l_layli_ptr = gap_mod_alloc_layli(l_tmp_image_id, &l_sel_cnt, &l_nlayers, layersel_mode, layersel_case, sel_invert, sel_pattern); if(l_layli_ptr == NULL) goto error; l_nvisible = l_sel_cnt; /* count visible Layers == all selected layers */ for(l_vidx=0; l_vidx < l_nlayers; l_vidx++) { /* set all selected layers visible, all others invisible */ l_tmp_layer_id = l_layli_ptr[l_vidx].layer_id; gimp_drawable_set_visible(l_tmp_layer_id, l_layli_ptr[l_vidx].selected); if((bg_visible == 0) && (l_vidx == (l_nlayers -1))) { /* set BG_Layer invisible */ gimp_drawable_set_visible(l_tmp_layer_id, FALSE); if(l_layli_ptr[l_vidx].selected) { l_nvisible--; } } } g_free(l_layli_ptr); if((flatten_mode >= GAP_RANGE_OPS_FLAM_MERG_EXPAND) && (flatten_mode <= GAP_RANGE_OPS_FLAM_MERG_CLIP_BG)) { if(gap_debug) fprintf(stderr, "p_frames_to_multilayer: %d MERGE visible layers=%d\n", (int)flatten_mode, (int)l_nvisible); /* merge all visible Layers */ if(l_nvisible > 1) gimp_image_merge_visible_layers (l_tmp_image_id, flatten_mode); } else { if(gap_debug) fprintf(stderr, "p_frames_to_multilayer: %d FLATTEN\n", (int)flatten_mode); /* flatten temporary image (reduce to single layer) */ gimp_image_flatten (l_tmp_image_id); } /* copy (the only visible) layer from temporary image */ l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers); if(l_layers_list != NULL) { for(l_vidx=0; l_vidx < l_nlayers; l_vidx++) { l_tmp_layer_id = l_layers_list[l_vidx]; /* stop at 1.st visible layer (this should be the only visible layer) */ if(gimp_drawable_get_visible(l_tmp_layer_id)) break; /* stop at 1.st layer if image was flattened */ if((flatten_mode < GAP_RANGE_OPS_FLAM_MERG_EXPAND) || (flatten_mode > GAP_RANGE_OPS_FLAM_MERG_CLIP_BG)) break; } g_free (l_layers_list); if(selection_mode == GAP_RANGE_OPS_SEL_FRAME_SPECIFIC) { if(!gimp_selection_is_empty(l_tmp_image_id)) { gimp_selection_invert(l_tmp_image_id); gimp_edit_clear(l_tmp_layer_id); } } if(l_vidx < l_nlayers) { l_cp_layer_id = gap_layer_copy_to_dest_image(l_new_image_id, l_tmp_layer_id, 100.0, /* Opacity */ 0, /* NORMAL */ &l_src_offset_x, &l_src_offset_y); /* add the copied layer to current destination image */ gimp_image_add_layer(l_new_image_id, l_cp_layer_id, 0); gimp_layer_set_offsets(l_cp_layer_id, l_src_offset_x, l_src_offset_y); if(l_clear_selected_area) { gimp_edit_clear(l_cp_layer_id); } l_nlayers_result++; /* add aplha channel to all layers * (without alpha raise and lower would not work on that layers) */ gimp_layer_add_alpha(l_cp_layer_id); /* set name and visibility */ if (frame_basename == NULL) frame_basename = "frame_[######]"; if (*frame_basename == '\0') frame_basename = "frame_[######]"; gap_match_substitute_framenr(&l_layername[0], sizeof(l_layername), frame_basename, (long)l_cur_frame_nr); gimp_drawable_set_name(l_cp_layer_id, &l_layername[0]); gimp_drawable_set_visible(l_cp_layer_id, l_visible); l_visible = FALSE; /* all further layers are set invisible */ } /* else: tmp image has no visible layers, ignore that frame */ } /* destroy the tmp image */ gimp_image_delete(l_tmp_image_id); if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE) { l_percentage += l_percentage_step; gimp_progress_update (l_percentage); } /* advance to next frame */ if(l_cur_frame_nr == l_end) break; l_cur_frame_nr += l_step; } gap_image_prevent_empty_image(l_new_image_id); return l_new_image_id; error: gimp_image_delete(l_new_image_id); return -1; } /* end p_frames_to_multilayer */ /* ============================================================================ * gap_range_to_multilayer * ============================================================================ */ gint32 gap_range_to_multilayer(GimpRunMode run_mode, gint32 image_id, long range_from, long range_to, long flatten_mode, long bg_visible, long framerate, char *frame_basename, int frame_basename_len, gint32 layersel_mode, gint32 layersel_case, gint32 sel_invert, char *sel_pattern, gint32 selection_mode) { gint32 new_image_id; gint32 l_rc; long l_from, l_to; GapAnimInfo *ainfo_ptr; GapVinVideoInfo *vin_ptr; gint32 l_layersel_mode; gint32 l_selection_mode; gint32 l_layersel_case; gint32 l_sel_invert; gdouble l_framerate; char l_sel_pattern[MAX_LAYERNAME]; l_rc = -1; ainfo_ptr = gap_lib_alloc_ainfo(image_id, run_mode); if(ainfo_ptr != NULL) { if (0 == gap_lib_dir_ainfo(ainfo_ptr)) { if(run_mode == GIMP_RUN_INTERACTIVE) { l_framerate = 24.0; vin_ptr = gap_vin_get_all(ainfo_ptr->basename); if(vin_ptr) { if(vin_ptr->framerate > 0) l_framerate = vin_ptr->framerate; g_free(vin_ptr); } g_snprintf(frame_basename, frame_basename_len, "frame_[######] (%dms)", (int)(1000/l_framerate)); framerate = 0; l_rc = p_range_to_multilayer_dialog (ainfo_ptr, &l_from, &l_to, &flatten_mode, &bg_visible, &framerate, frame_basename, frame_basename_len, _("Frames to Image"), _("Create Multilayer-Image from Frames"), &l_layersel_mode, &layersel_case, &sel_invert, &l_sel_pattern[0], &l_selection_mode ); } else { l_from = range_from; l_to = range_to; l_rc = 0; l_layersel_mode = layersel_mode; l_layersel_case = layersel_case; l_sel_invert = sel_invert; l_selection_mode = selection_mode; strncpy(&l_sel_pattern[0], sel_pattern, sizeof(l_sel_pattern) -1); l_sel_pattern[sizeof(l_sel_pattern) -1] = '\0'; } if(l_rc >= 0) { new_image_id = p_frames_to_multilayer(ainfo_ptr, l_from, l_to, flatten_mode, bg_visible, framerate, frame_basename, l_layersel_mode, layersel_case, sel_invert, &l_sel_pattern[0], l_selection_mode); gimp_display_new(new_image_id); l_rc = new_image_id; } } gap_lib_free_ainfo(&ainfo_ptr); } return(l_rc); } /* end gap_range_to_multilayer */ /* ============================================================================ * p_type_convert * convert image to desired type (reduce to dest_colors for INDEXED type) * ============================================================================ */ static int p_type_convert(gint32 image_id, GimpImageBaseType dest_type, gint32 dest_colors, gint32 dest_dither, gint32 palette_type, gint32 alpha_dither, gint32 remove_unused, char *palette) { gboolean l_rc; gboolean l_alpha_dither; gboolean l_remove_unused; GimpConvertDitherType l_dither_type; GimpConvertPaletteType l_palette_type; l_rc = TRUE; switch(dest_type) { case GIMP_INDEXED: if(gap_debug) fprintf(stderr, "DEBUG: p_type_convert to INDEXED ncolors=%d, palette_type=%d palette_name=%s'\n", (int)dest_colors, (int)palette_type, palette); switch(dest_dither) { case 1: l_dither_type = GIMP_FS_DITHER; break; case 2: l_dither_type = GIMP_FSLOWBLEED_DITHER; break; case 3: l_dither_type = GIMP_FIXED_DITHER; break; default: l_dither_type = GIMP_NO_DITHER; break; } switch(palette_type) { case 1: l_palette_type = GIMP_REUSE_PALETTE; break; case 2: l_palette_type = GIMP_WEB_PALETTE; break; case 3: l_palette_type = GIMP_MONO_PALETTE; break; case 4: l_palette_type = GIMP_CUSTOM_PALETTE; break; default: l_palette_type = GIMP_MAKE_PALETTE; break; } l_alpha_dither = (alpha_dither != 0); l_remove_unused = (remove_unused != 0); l_rc = gimp_image_convert_indexed(image_id, l_dither_type, l_palette_type, /* value 0: MAKE_PALETTE, 2: WEB_PALETTE 4:CUSTOM_PALETTE */ dest_colors, l_alpha_dither, l_remove_unused, palette /* name of custom palette */ ); break; case GIMP_GRAY: if(gap_debug) fprintf(stderr, "DEBUG: p_type_convert to GRAY'\n"); l_rc = gimp_image_convert_grayscale(image_id); break; case GIMP_RGB: if(gap_debug) fprintf(stderr, "DEBUG: p_type_convert to RGB'\n"); l_rc = gimp_image_convert_rgb(image_id); break; default: if(gap_debug) fprintf(stderr, "DEBUG: p_type_convert AS_IT_IS (dont convert)'\n"); return 0; break; } if (l_rc) return 0; return -1; } /* end p_type_convert */ /* ============================================================================ * p_frames_convert * convert frames (multiple images) into desired fileformat and type * (flatten the images if desired) * * if save_proc_name == NULL * then use xcf save (and flatten image) * and new_basename and new_extension * else * save in specified fileformat * and return image_id of the frame with lowest frame number * (all other frames were deleted after successful save) * * returns value >= 0 if all is ok * (or -1 on error) * ============================================================================ */ static gint32 p_frames_convert(GapAnimInfo *ainfo_ptr, long range_from, long range_to, char *save_proc_name, char *new_basename, char *new_extension, int flatten, GimpImageBaseType dest_type, gint32 dest_colors, gint32 dest_dither, gint32 palette_type, gint32 alpha_dither, gint32 remove_unused, char *palette) { GimpRunMode l_run_mode; gint32 l_tmp_image_id; gint32 l_start_image_id; long l_cur_frame_nr; long l_step, l_begin, l_end; gint l_nlayers; gint l_img_already_flat; gint32 *l_layers_list; gdouble l_percentage, l_percentage_step; char *l_sav_name; gint32 l_rc; gint l_overwrite_mode; static GapArrButtonArg l_argv[3]; l_rc = 0; l_overwrite_mode = 0; l_percentage = 0.0; l_start_image_id = -1; l_run_mode = ainfo_ptr->run_mode; if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE) { if(save_proc_name == NULL) gimp_progress_init( _("Flattening frames...")); else gimp_progress_init( _("Converting frames...")); } l_begin = range_from; l_end = range_to; if(range_from > range_to) { l_step = -1; /* operate in descending (reverse) order */ l_percentage_step = 1.0 / ((1.0 + range_from) - range_to); if(range_to < ainfo_ptr->first_frame_nr) { l_begin = ainfo_ptr->first_frame_nr; } if(range_from > ainfo_ptr->last_frame_nr) { l_end = ainfo_ptr->last_frame_nr; } } else { l_step = 1; /* operate in ascending order */ l_percentage_step = 1.0 / ((1.0 + range_to) - range_from); if(range_from < ainfo_ptr->first_frame_nr) { l_begin = ainfo_ptr->first_frame_nr; } if(range_to > ainfo_ptr->last_frame_nr) { l_end = ainfo_ptr->last_frame_nr; } } l_cur_frame_nr = l_begin; while(l_rc >= 0) { /* build the frame name */ if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename); ainfo_ptr->new_filename = gap_lib_alloc_fname(ainfo_ptr->basename, l_cur_frame_nr, ainfo_ptr->extension); if(ainfo_ptr->new_filename == NULL) return -1; /* load current frame */ l_tmp_image_id = gap_lib_load_image(ainfo_ptr->new_filename); if(l_tmp_image_id < 0) return -1; l_img_already_flat = FALSE; /* an image without any layer is considered as not flattend */ l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers); if(l_layers_list != NULL) { if( (l_nlayers == 1) && (! gimp_drawable_has_alpha(l_layers_list[0])) && (! gimp_drawable_get_visible(l_layers_list[0]))) { l_img_already_flat = TRUE; } g_free (l_layers_list); } if((l_img_already_flat == FALSE) && (flatten != 0)) { gint32 l_dummy_layer_id; if(gap_debug) fprintf(stderr, "DEBUG: p_frames_convert flatten tmp image'\n"); /* hof: * we add dummy layers to make sure that flatten works on any kind of image. * even if the image had no layer at all, or all its layers were invisible. * (flatten need at least 2 layers and at least one visible layer to work. * if just invisible layers are flattened * we do not get a resulting layer (returned l_layer_id == -1) */ l_dummy_layer_id = gimp_layer_new(l_tmp_image_id, "dummy", 1, 1, ((gint)(gimp_image_base_type(l_tmp_image_id)) * 2), 100.0, /* Opacity full opaque */ 0); /* NORMAL */ gimp_image_add_layer(l_tmp_image_id, l_dummy_layer_id, 0); gimp_layer_set_offsets(l_dummy_layer_id, -1, -1); if(l_nlayers == 0) { /* on empty images we need 2 dummies to make flatten happy */ l_dummy_layer_id = gimp_layer_new(l_tmp_image_id, "dummy2", 1, 1, ((gint)(gimp_image_base_type(l_tmp_image_id)) * 2), 100.0, /* Opacity full opaque */ 0); /* NORMAL */ gimp_image_add_layer(l_tmp_image_id, l_dummy_layer_id, 0); gimp_layer_set_offsets(l_dummy_layer_id, -1, -1); } /* flatten current frame image (reduce to single layer) */ gimp_image_flatten (l_tmp_image_id); /* save back the current frame with same name */ if(save_proc_name == NULL) { l_rc = gap_lib_save_named_frame(l_tmp_image_id, ainfo_ptr->new_filename); } } if(save_proc_name != NULL) { if(dest_type != gimp_image_base_type(l_tmp_image_id)) { /* have to convert to desired type (RGB, INDEXED, GRAYSCALE) */ p_type_convert(l_tmp_image_id, dest_type, dest_colors, dest_dither, palette_type, alpha_dither, remove_unused, palette); } /* build the name for output image */ l_sav_name = gap_lib_alloc_fname(new_basename, l_cur_frame_nr, new_extension); if(l_sav_name != NULL) { if(1 == gap_lib_file_exists(l_sav_name)) { if (l_overwrite_mode < 1) { l_argv[0].but_txt = _("Overwrite Frame"); l_argv[0].but_val = 0; l_argv[1].but_txt = _("Overwrite All"); l_argv[1].but_val = 1; l_argv[2].but_txt = GTK_STOCK_CANCEL; l_argv[2].but_val = -1; l_overwrite_mode = gap_arr_buttons_dialog ( _("GAP Question"), l_sav_name, 3, l_argv, -1); } } gimp_image_set_filename(l_tmp_image_id, l_sav_name); if(l_cur_frame_nr == MIN(range_from, range_to)) { l_start_image_id = l_tmp_image_id; } if(l_overwrite_mode < 0) { l_rc = -1; } else { /* save with selected save procedure * (regardless if image was flattened or not) */ l_rc = gap_lib_save_named_image(l_tmp_image_id, l_sav_name, l_run_mode); if(l_rc < 0) { gap_arr_msg_win(ainfo_ptr->run_mode, _("Convert Frames: Save operation failed.\n" "Desired save plugin can't handle type\n" "or desired save plugin not available.")); } } if(l_run_mode == GIMP_RUN_INTERACTIVE) { l_run_mode = GIMP_RUN_WITH_LAST_VALS; /* for all further calls */ } g_free(l_sav_name); } } if(l_start_image_id != l_tmp_image_id) { /* destroy the tmp image */ gimp_image_delete(l_tmp_image_id); } if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE) { l_percentage += l_percentage_step; gimp_progress_update (l_percentage); } /* break on error */ if(l_rc < 0) { break; } /* break at last handled frame */ if(l_cur_frame_nr == l_end) { if(save_proc_name == NULL) { l_rc = 0; } else { l_rc = l_start_image_id; } break; } /* advance to next frame */ l_cur_frame_nr += l_step; } return l_rc; } /* end p_frames_convert */ /* ============================================================================ * p_image_sizechange * scale, resize or crop one image * ============================================================================ */ static int p_image_sizechange(gint32 image_id, GapRangeOpsAsiz asiz_mode, long size_x, long size_y, long offs_x, long offs_y ) { gboolean l_rc; if(gap_debug) { printf("p_image_sizechange: image_id: %d\n", (int)image_id); printf("size_x:%d size_y: %d\n", (int)size_x , (int)size_y ); printf("size_x:%d size_y: %d\n", (int)size_x , (int)size_y ); if(asiz_mode != GAP_ASIZ_SCALE) { printf("offs_x: %d\n", (int)offs_x); printf("offs_y: %d\n", (int)offs_y); } } switch(asiz_mode) { case GAP_ASIZ_CROP: l_rc = gimp_image_crop(image_id, size_x, size_y, offs_x, offs_y); break; case GAP_ASIZ_RESIZE: l_rc = gimp_image_resize(image_id, size_x, size_y, offs_x, offs_y); break; default: l_rc = gimp_image_scale(image_id, size_x, size_y); break; } if(l_rc) return 0; return -1; } /* end p_image_sizechange */ /* ============================================================================ * p_anim_sizechange * scale, resize or crop all frames in the animation * ============================================================================ */ static gint32 p_anim_sizechange(GapAnimInfo *ainfo_ptr, GapRangeOpsAsiz asiz_mode, long size_x, long size_y, long offs_x, long offs_y ) { guint l_width, l_height; long l_cur_frame_nr; long l_step, l_begin, l_end; gint32 l_tmp_image_id; gdouble l_percentage, l_percentage_step; GimpParam *l_params; int l_rc; l_rc = 0; l_params = NULL; l_percentage = 0.0; if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE) { switch(asiz_mode) { case GAP_ASIZ_CROP: gimp_progress_init( _("Cropping all video frames...")); break; case GAP_ASIZ_RESIZE: gimp_progress_init( _("Resizing all video frames...")); break; default: gimp_progress_init( _("Scaling all video frames...")); break; } } /* get info about the image (size and type is common to all frames) */ l_width = gimp_image_width(ainfo_ptr->image_id); l_height = gimp_image_height(ainfo_ptr->image_id); l_begin = ainfo_ptr->first_frame_nr; l_end = ainfo_ptr->last_frame_nr; l_step = 1; /* operate in ascending order */ l_percentage_step = 1.0 / ((1.0 + l_end) - l_begin); l_cur_frame_nr = l_begin; while(1) { /* build the frame name */ if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename); ainfo_ptr->new_filename = gap_lib_alloc_fname(ainfo_ptr->basename, l_cur_frame_nr, ainfo_ptr->extension); if(ainfo_ptr->new_filename == NULL) return -1; /* load current frame into temporary image */ l_tmp_image_id = gap_lib_load_image(ainfo_ptr->new_filename); if(l_tmp_image_id < 0) return -1; l_rc = p_image_sizechange(l_tmp_image_id, asiz_mode, size_x, size_y, offs_x, offs_y); if(l_rc < 0) break; /* save back the current frame with same name */ l_rc = gap_lib_save_named_frame(l_tmp_image_id, ainfo_ptr->new_filename); if(l_rc < 0) break; /* destroy the tmp image */ gimp_image_delete(l_tmp_image_id); if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE) { l_percentage += l_percentage_step; gimp_progress_update (l_percentage); } /* advance to next frame */ if(l_cur_frame_nr == l_end) break; l_cur_frame_nr += l_step; } /* end while loop over all frames*/ return l_rc; } /* end p_anim_sizechange */ /* ============================================================================ * gap_range_flatten * * return image_id (of the new loaded current frame) on success * or -1 on errors * ============================================================================ */ gint32 gap_range_flatten(GimpRunMode run_mode, gint32 image_id, long range_from, long range_to) { int l_rc; long l_from, l_to; GapAnimInfo *ainfo_ptr; l_rc = -1; ainfo_ptr = gap_lib_alloc_ainfo(image_id, run_mode); if(ainfo_ptr != NULL) { if (0 == gap_lib_dir_ainfo(ainfo_ptr)) { if(run_mode == GIMP_RUN_INTERACTIVE) { l_rc = p_range_dialog (ainfo_ptr, &l_from, &l_to, _("Flatten Frames"), _("Select Frame Range"), 2, GAP_HELP_ID_FLATTEN); } else { l_rc = 0; l_from = range_from; l_to = range_to; } if(l_rc >= 0) { if(gap_lib_gap_check_save_needed(ainfo_ptr->image_id)) { l_rc = gap_lib_save_named_frame(ainfo_ptr->image_id, ainfo_ptr->old_filename); } if(l_rc >= 0) { l_rc = p_frames_convert(ainfo_ptr, l_from, l_to, NULL, NULL, NULL, 1, 0,0,0, 0,0,0, ""); if(l_rc >= 0) { l_rc = gap_lib_load_named_frame(ainfo_ptr->image_id, ainfo_ptr->old_filename); } } } } gap_lib_free_ainfo(&ainfo_ptr); } if(l_rc < 0) { return -1; } return(l_rc); } /* end gap_range_flatten */ /* ============================================================================ * p_frames_layer_del * returns image_id of the new created multilayer image * (or -1 on error) * ============================================================================ */ static int p_frames_layer_del(GapAnimInfo *ainfo_ptr, long range_from, long range_to, long position) { gint32 l_tmp_image_id; long l_cur_frame_nr; long l_step, l_begin, l_end; gint32 l_tmp_layer_id; gint l_nlayers; gint32 *l_layers_list; gdouble l_percentage, l_percentage_step; gchar *l_buff; int l_rc; l_rc = 0; l_percentage = 0.0; if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE) { l_buff = g_strdup_printf (_("Removing layer (pos:%ld) from frames..."), position); gimp_progress_init(l_buff); g_free (l_buff); } /* get info about the image (size and type is common to all frames) */ l_begin = range_from; l_end = range_to; if(range_from > range_to) { l_step = -1; /* operate in descending (reverse) order */ l_percentage_step = 1.0 / ((1.0 + range_from) - range_to); if(range_to < ainfo_ptr->first_frame_nr) { l_begin = ainfo_ptr->first_frame_nr; } if(range_from > ainfo_ptr->last_frame_nr) { l_end = ainfo_ptr->last_frame_nr; } } else { l_step = 1; /* operate in ascending order */ l_percentage_step = 1.0 / ((1.0 + range_to) - range_from); if(range_from < ainfo_ptr->first_frame_nr) { l_begin = ainfo_ptr->first_frame_nr; } if(range_to > ainfo_ptr->last_frame_nr) { l_end = ainfo_ptr->last_frame_nr; } } l_cur_frame_nr = l_begin; while(1) { /* build the frame name */ if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename); ainfo_ptr->new_filename = gap_lib_alloc_fname(ainfo_ptr->basename, l_cur_frame_nr, ainfo_ptr->extension); if(ainfo_ptr->new_filename == NULL) return -1; /* load current frame */ l_tmp_image_id = gap_lib_load_image(ainfo_ptr->new_filename); if(l_tmp_image_id < 0) return -1; /* remove layer[position] */ l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers); if(l_layers_list != NULL) { /* findout layer id of the requestetd position within layerstack */ if(position < l_nlayers) l_tmp_layer_id = l_layers_list[position]; else l_tmp_layer_id = l_layers_list[l_nlayers -1]; g_free (l_layers_list); /* check for last layer (MUST NOT be deleted !) */ if(l_nlayers > 1) { /* remove and delete requested layer */ gimp_image_remove_layer(l_tmp_image_id, l_tmp_layer_id); /* save current frame */ l_rc = gap_lib_save_named_frame(l_tmp_image_id, ainfo_ptr->new_filename); } } /* destroy the tmp image */ gimp_image_delete(l_tmp_image_id); if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE) { l_percentage += l_percentage_step; gimp_progress_update (l_percentage); } /* advance to next frame */ if((l_cur_frame_nr == l_end) || (l_rc < 0)) break; l_cur_frame_nr += l_step; } return l_rc; } /* end p_frames_layer_del */ /* ============================================================================ * gap_range_layer_del * * return image_id (of the new loaded current frame) on success * or -1 on errors * ============================================================================ */ gint32 gap_range_layer_del(GimpRunMode run_mode, gint32 image_id, long range_from, long range_to, long position) { int l_rc; long l_position; long l_from, l_to; GapAnimInfo *ainfo_ptr; l_rc = -1; l_position = 0; ainfo_ptr = gap_lib_alloc_ainfo(image_id, run_mode); if(ainfo_ptr != NULL) { if (0 == gap_lib_dir_ainfo(ainfo_ptr)) { if(run_mode == GIMP_RUN_INTERACTIVE) { l_rc = p_range_dialog (ainfo_ptr, &l_from, &l_to, _("Delete Layers in Frames"), _("Select Frame Range & Stack Position"), 3, GAP_HELP_ID_LAYER_DEL); l_position = l_rc; } else { l_rc = 0; l_from = range_from; l_to = range_to; l_position = position; } if(l_rc >= 0) { if(gap_lib_gap_check_save_needed(ainfo_ptr->image_id)) { l_rc = gap_lib_save_named_frame(ainfo_ptr->image_id, ainfo_ptr->old_filename); } if(l_rc >= 0) { l_rc = p_frames_layer_del(ainfo_ptr, l_from, l_to, l_position); if(l_rc >= 0) { l_rc = gap_lib_load_named_frame(ainfo_ptr->image_id, ainfo_ptr->old_filename); } } } } gap_lib_free_ainfo(&ainfo_ptr); } if(l_rc < 0) { return -1; } return(l_rc); } /* end gap_range_layer_del */ /* ============================================================================ * gap_range_conv * convert frame range to any gimp supported fileformat * * return image_id of the first (or last) of the converted frame images * or -1 on errors * ============================================================================ */ gint32 gap_range_conv(GimpRunMode run_mode, gint32 image_id, long range_from, long range_to, long flatten, GimpImageBaseType dest_type, gint32 dest_colors, gint32 dest_dither, char *basename, char *extension, gint32 palette_type, gint32 alpha_dither, gint32 remove_unused, char *palette) { gint32 l_rc; long l_from, l_to; long l_flatten; gint32 l_dest_colors; gint32 l_dest_dither; gint32 l_palette_type; gint32 l_alpha_dither; gint32 l_remove_unused; GimpImageBaseType l_dest_type; GapAnimInfo *ainfo_ptr; char l_save_proc_name[128]; char l_basename[256]; char *l_basename_ptr; long l_number; char l_extension[32]; char l_palette[256]; strcpy(l_save_proc_name, "gimp_file_save"); strcpy(l_extension, ".jpg"); l_rc = -1; ainfo_ptr = gap_lib_alloc_ainfo(image_id, run_mode); if(ainfo_ptr != NULL) { if (0 == gap_lib_dir_ainfo(ainfo_ptr)) { strncpy(l_basename, ainfo_ptr->basename, sizeof(l_basename) -1); l_basename[sizeof(l_basename) -1] = '\0'; if(run_mode == GIMP_RUN_INTERACTIVE) { l_flatten = 1; /* p_convert_dialog : select destination type * to find out extension */ strcpy(l_palette, "Default"); l_rc = p_convert_dialog (ainfo_ptr, &l_from, &l_to, &l_flatten, &l_dest_type, &l_dest_colors, &l_dest_dither, &l_basename[0], sizeof(l_basename), &l_extension[0], sizeof(l_extension), &l_palette_type, &l_alpha_dither, &l_remove_unused, &l_palette[0], sizeof(l_palette)); } else { l_rc = 0; l_from = range_from; l_to = range_to; l_flatten = flatten; l_dest_type = dest_type; l_dest_colors = dest_colors; l_dest_dither = dest_dither; l_palette_type = palette_type; l_alpha_dither = alpha_dither; l_remove_unused = remove_unused; if(basename != NULL) { strncpy(l_basename, basename, sizeof(l_basename) -1); l_basename[sizeof(l_basename) -1] = '\0'; } if(palette != NULL) { strncpy(l_palette, palette, sizeof(l_palette) -1); l_palette[sizeof(l_palette) -1] = '\0'; } strncpy(l_extension, extension, sizeof(l_extension) -1); l_extension[sizeof(l_extension) -1] = '\0'; } if(l_rc >= 0) { /* cut off extension and trailing frame number */ l_basename_ptr = gap_lib_alloc_basename(&l_basename[0], &l_number); if(l_basename_ptr == NULL) { l_rc = -1; } else { l_rc = p_frames_convert(ainfo_ptr, l_from, l_to, l_save_proc_name, l_basename_ptr, l_extension, l_flatten, l_dest_type, l_dest_colors, l_dest_dither, l_palette_type, l_alpha_dither, l_remove_unused, l_palette); g_free(l_basename_ptr); if((l_rc >= 0) && (run_mode == GIMP_RUN_INTERACTIVE)) { gimp_display_new(l_rc); } } } } gap_lib_free_ainfo(&ainfo_ptr); } return(l_rc); } /* end gap_range_conv */ /* ============================================================================ * gap_range_anim_sizechange * scale, resize or crop all video frame images of the animation * (depending on asiz_mode) * ============================================================================ */ int gap_range_anim_sizechange(GimpRunMode run_mode, GapRangeOpsAsiz asiz_mode, gint32 image_id, long size_x, long size_y, long offs_x, long offs_y) { int l_rc; long l_size_x, l_size_y; long l_offs_x, l_offs_y; GapAnimInfo *ainfo_ptr; l_rc = 0; ainfo_ptr = gap_lib_alloc_ainfo(image_id, run_mode); if(ainfo_ptr != NULL) { if (0 == gap_lib_dir_ainfo(ainfo_ptr)) { if(run_mode == GIMP_RUN_INTERACTIVE) { l_rc = p_anim_sizechange_dialog (ainfo_ptr, asiz_mode, &l_size_x, &l_size_y, &l_offs_x, &l_offs_y); } else { l_size_x = size_x; l_size_y = size_y; l_offs_x = offs_x; l_offs_y = offs_y; } if(l_rc >= 0) { if(gap_lib_gap_check_save_needed(ainfo_ptr->image_id)) { l_rc = gap_lib_save_named_frame(ainfo_ptr->image_id, ainfo_ptr->old_filename); } if(l_rc >= 0) { /* we have to resize the current video frame image in gimp's ram *(from where we were invoked) * Note: All video frames on disc and the current one in ram * must fit in size and type, to allow further animation operations. * (Restriction of duplicate_into) */ gimp_image_undo_disable(ainfo_ptr->image_id); l_rc = p_image_sizechange(ainfo_ptr->image_id, asiz_mode, l_size_x, l_size_y, l_offs_x, l_offs_y); if(l_rc == 0) { /* sizechange for all video frames on disk */ l_rc = p_anim_sizechange(ainfo_ptr, asiz_mode, l_size_x, l_size_y, l_offs_x, l_offs_y ); } /* gap_lib_load_named_frame(ainfo_ptr->image_id, ainfo_ptr->old_filename); */ /* dont need to reload, because the same sizechange operation was * applied both to ram-image and discfile * * But we must clear all undo steps. * (If the user could undo the sizechange on the current image, * it would not fit to the other frames on disk.) */ gimp_image_undo_enable(ainfo_ptr->image_id); /* clear undo stack */ } } } gap_lib_free_ainfo(&ainfo_ptr); } return(l_rc); } /* end gap_range_anim_sizechange */ gimp-gap-2.6.0+dfsg.orig/gap/gimplastvaldesc.c0000644000175000017500000005537611212030253021062 0ustar thibautthibaut/* gimplastvaldesc.c * * GAP ... Gimp Animation Plugins * * This Module contains: * Procedures to register a plugin's LAST_VALUES buffer description * (needed for animated filtercalls using a common iterator procedure) * * should be a part of future libgimp for easy use in many plugin's. * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 2003/09/20 hof: added datatype support for guint guint32. * 2003/01/19 hof: use gimp_directory (replace gimprc query for "gimp_dir") * 2002/04/07 hof: created. */ /* SYSTEM (UNIX) includes */ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include "libgimp/gimp.h" /* gimplastvaldesc should become part of libgimp in the future. * if this will come true, HAVE_LASTVALDESC_H will also become DEFINED. */ #ifdef HAVE_LASTVALDESC_H #include "libgimp/gimplastvaldesc.h" #else /* for now GAP Sources include a private version of gimplastvaldesc.h gimplastvaldesc.c Modules * and must include them explicite because HAVE_LASTVALDESC_H is not defined * (i dont know, if gimplastvaldesc will be a part of libgimp someday -- hof) */ #include "gimplastvaldesc.h" #endif #include "gap_libgapbase.h" typedef struct GimpLastvalTokenTabType { char *token; GimpLastvalType lastval_type; } GimpLastvalTokenTabType; static void p_init_token_table(void); static gchar * p_load_lastval_desc_file(const gchar *fname); static void p_fwrite_lastvals_desc(FILE *fp, const gchar *keyname, GimpLastvalDescType *lastval_desc_arr, gint32 argc); static gint32 p_fwrite_lines_until_keyname(FILE *fp, const char *keyname, gchar *ptr); static void p_fwrite_lines_remaining_without_keyname(FILE *fp, const char *keyname, gchar *ptr); static void p_lastvals_register_persistent(const gchar *keyname, GimpLastvalDescType *lastval_desc_arr, gint32 argc); static GimpLastvalTokenTabType token_tab[GIMP_LASTVAL_END]; gboolean gimp_lastval_desc_register(const gchar *keyname, void *baseadress, gint32 total_size, gint32 nlastvals, GimpLastvalDef *lastvals) { void *adress; gint32 elem_size; gint32 array_size; gchar *elem_name; gint32 offset; GimpLastvalType lastval_type; GimpLastvalDescType *lastval_desc_arr; gint arg_cnt; gint idx; gint struct_cnt; gboolean retcode; retcode = TRUE; p_init_token_table(); arg_cnt = 0; struct_cnt = 0; offset = 0; array_size = 1; elem_size = 1; for(arg_cnt=0; arg_cnt < nlastvals; arg_cnt++) { lastval_type = lastvals[arg_cnt].type; switch(lastval_type) { case GIMP_LASTVAL_ARRAY: array_size = lastvals[arg_cnt].elem_size; if (array_size <= 0 || (offset + array_size) > total_size) { printf("ERROR gimp_lastval_desc_register: %s arg[%d] array_size: %d larger than total_size: %d\n" ,keyname, (int)arg_cnt, (int)array_size, (int)total_size); retcode = FALSE; } break; case GIMP_LASTVAL_STRUCT_BEGIN: struct_cnt++; elem_size = lastvals[arg_cnt].elem_size; if (elem_size <= 0 || (offset + (array_size * elem_size)) > total_size) { printf("ERROR gimp_lastval_desc_register: %s arg[%d] offset %d + elem_size: %d * array_size: %d is larger than total_size: %d\n" ,keyname, (int)arg_cnt, (int)offset, (int)elem_size, (int)array_size, (int)total_size); retcode = FALSE; } array_size = 1; break; case GIMP_LASTVAL_STRUCT_END: struct_cnt--; if (struct_cnt < 0) { printf("ERROR gimp_lastval_desc_register: %s arg[%d] STRUCT_BEGIN STRUCT_END out of balance\n \n" ,keyname, (int)arg_cnt); break; /* error: out of balance */ } elem_size = lastvals[arg_cnt].elem_size; break; default: adress = lastvals[arg_cnt].elem_adress; offset = adress - baseadress; if (offset < 0 || offset >= total_size) { printf("ERROR gimp_lastval_desc_register: %s arg[%d] offset %d outside of structure adressrange\n" ,keyname, (int)arg_cnt, (int)offset); retcode = FALSE; } elem_size = lastvals[arg_cnt].elem_size; if ((offset + (array_size * elem_size)) > total_size) { printf("ERROR gimp_lastval_desc_register: %s arg[%d] offset %d + elem_size: %d * array_size: %d is larger than total_size: %d\n" ,keyname, (int)arg_cnt, (int)offset, (int)elem_size, (int)array_size, (int)total_size); retcode = FALSE; } array_size = 1; break; } } if(struct_cnt != 0) { printf("ERROR gimp_lastval_desc_register: %s arg[%d] STRUCT_BEGIN STRUCT_END out of balance\n" ,keyname, (int)arg_cnt); retcode = FALSE; } if(retcode != TRUE) { return (retcode); } /* description + 2 automatic STRUCT BEGIN/END elemnts describing the total_size */ lastval_desc_arr = g_new(GimpLastvalDescType, arg_cnt+2); /* 1.st entry always describes total_size of the LAST_VALUES Buffer structure */ lastval_desc_arr[0].lastval_type = GIMP_LASTVAL_STRUCT_BEGIN; lastval_desc_arr[0].offset = 0; lastval_desc_arr[0].elem_size = total_size; lastval_desc_arr[0].iter_flag = GIMP_ITER_TRUE; lastval_desc_arr[0].elem_name[0] = '\0'; for(arg_cnt=0, idx = 1; arg_cnt < nlastvals; arg_cnt++, idx++) { switch(lastvals[arg_cnt].type) { case GIMP_LASTVAL_ARRAY: case GIMP_LASTVAL_STRUCT_BEGIN: case GIMP_LASTVAL_STRUCT_END: lastval_desc_arr[idx].offset = 0; break; default: adress = lastvals[arg_cnt].elem_adress; lastval_desc_arr[idx].offset = adress - baseadress; break; } lastval_desc_arr[idx].elem_size = lastvals[arg_cnt].elem_size; lastval_desc_arr[idx].iter_flag = lastvals[arg_cnt].iter_flag; lastval_desc_arr[idx].lastval_type = lastvals[arg_cnt].type; elem_name = lastvals[arg_cnt].elem_name; if(elem_name) { g_snprintf(lastval_desc_arr[idx].elem_name, sizeof(lastval_desc_arr[idx].elem_name), "%s", elem_name); } else { lastval_desc_arr[idx].elem_name[0] = '\0'; } } lastval_desc_arr[idx].lastval_type = GIMP_LASTVAL_STRUCT_END; lastval_desc_arr[idx].offset = 0; lastval_desc_arr[idx].elem_size = total_size; lastval_desc_arr[idx].iter_flag = GIMP_ITER_TRUE; lastval_desc_arr[idx].elem_name[0] = '\0'; idx++; /* register for current session */ /* *{ * gchar *key_description; * * key_description = gimp_lastval_desc_keyname(keyname); * gimp_set_data(key_description, lastval_desc_arr, sizeof(GimpLastvalDescType) * idx); * g_free(key_description); *} */ /* register permanent in a file */ p_lastvals_register_persistent(keyname, lastval_desc_arr, idx); g_free(lastval_desc_arr); return (retcode); } /* gimp_lastval_desc_register */ #define TIMESTAMP_DESCFILE_CHECKED "GAP_KEYNAME_TIMESTAMP_DESCRIPTIONFILE_CHECKED" void gimp_lastval_desc_update(void) { gchar *fname; gchar *file_buff; gchar *l_keyname; gchar *key_description; gint arg_cnt; gint max_expected_argc; GimpLastvalDescType *lastval_desc_arr; gchar *ptr; gchar *next_line_ptr; gint32 l_idx; gint32 l_filesize; long l_timestamp; struct stat stat_buf; arg_cnt = 0; fname = gimp_lastval_desc_filename(); /* check timestamps */ if(gimp_get_data_size(TIMESTAMP_DESCFILE_CHECKED) > 1) { gimp_get_data(TIMESTAMP_DESCFILE_CHECKED, &l_timestamp); if(g_stat(fname, &stat_buf) == 0) { if(l_timestamp > stat_buf.st_mtime) { /* file last modification is older than timestamp of last check * (we dont need to read the file again) */ g_free(fname); return; } } else { /* file not found, no need to continue */ g_free(fname); return; } } l_timestamp = gap_base_get_current_time(); gimp_set_data(TIMESTAMP_DESCFILE_CHECKED, &l_timestamp, sizeof(l_timestamp)); p_init_token_table(); /* read all descriptions from file */ file_buff = p_load_lastval_desc_file(fname); if(file_buff == NULL) { return; } l_filesize = strlen(file_buff); /* set/replace all descriptions in memory for the current gimp session */ max_expected_argc = 10 + (l_filesize / 7); lastval_desc_arr = g_new(GimpLastvalDescType, max_expected_argc); l_keyname = NULL; key_description = g_strdup(" "); for(ptr = file_buff; *ptr != '\0'; ptr = next_line_ptr) { /* skip blanks */ while (*ptr == ' ' || *ptr == '\t') { ptr++;} /* findout start on next line (and terminate the current line with '\0') */ next_line_ptr = ptr; while (*next_line_ptr != '\0') { if(*next_line_ptr == '\n') { *next_line_ptr = '\0'; next_line_ptr++; break; } next_line_ptr++; } /* printf("LINE:%s\n", ptr); */ /* ignore empty lines and comment lines */ if ((*ptr != '\n') && (*ptr != '\0') && (*ptr != '#')) { if (*ptr == '"') { l_idx = 1; l_keyname = &ptr[1]; while (1) { if (ptr[l_idx] == '"' || ptr[l_idx] == '\n' || ptr[l_idx] == '\0') { ptr[l_idx] = '\0'; g_free(key_description); /* printf("KEY:%s\n", l_keyname); */ key_description = gimp_lastval_desc_keyname(l_keyname); break; } l_idx++; } } else { for(l_idx=0; l_idx <= GIMP_LASTVAL_END; l_idx++) { char *l_token; l_token = g_strdup_printf("%s;", token_tab[l_idx].token); if(0 == strncmp(ptr, l_token, strlen(l_token))) { /* found a matching datatype token */ if(strcmp("END;",l_token) == 0) { lastval_desc_arr[arg_cnt].lastval_type = GIMP_LASTVAL_END; lastval_desc_arr[arg_cnt].offset = 0; lastval_desc_arr[arg_cnt].elem_size = 0; lastval_desc_arr[arg_cnt].iter_flag = 0; lastval_desc_arr[arg_cnt].elem_name[0] = '\0'; arg_cnt++; /* if it is the END of description block store array in memory */ /* printf("SET_DATA:%s\n", key_description); */ gimp_set_data(key_description, lastval_desc_arr, sizeof(GimpLastvalDescType) * arg_cnt); arg_cnt = 0; g_free(key_description); key_description = g_strdup(" "); } else { int l_nscan; lastval_desc_arr[arg_cnt].elem_name[0] = '\0'; lastval_desc_arr[arg_cnt].lastval_type = token_tab[l_idx].lastval_type; l_nscan = sscanf(&ptr[strlen(l_token)], "%d;%d;%d;%50s" , &lastval_desc_arr[arg_cnt].offset , &lastval_desc_arr[arg_cnt].elem_size , &lastval_desc_arr[arg_cnt].iter_flag , lastval_desc_arr[arg_cnt].elem_name ); if(l_nscan != 3 && l_nscan != 4) { printf("ERROR while scanning datatype %s in file %s\n", ptr, fname); } else { arg_cnt++; } } break; } g_free(l_token); } if (l_idx > GIMP_LASTVAL_END) { printf("ERROR unknown datatype %s in file %s %d %d\n", ptr, fname, l_idx, GIMP_LASTVAL_END); } } } } g_free(key_description); g_free(lastval_desc_arr); g_free(fname); } /* end gimp_lastval_desc_update */ gchar * gimp_lastval_desc_filename(void) { gchar *l_fname; l_fname = g_build_filename(gimp_directory (), "lastval_descriptions.txt", NULL); return(l_fname); } /* end gimp_lastval_desc_filename */ gchar * gimp_lastval_desc_keyname(const gchar *keyname) { return(g_strdup_printf("%s_ITER_DATA_DESCRIPTION", keyname)); } /* ----------------------- * local helper procedures * ----------------------- */ static void p_init_token_table(void) { static gboolean token_table_initialized = FALSE; if(token_table_initialized != TRUE) { /* typename strings */ token_tab[GIMP_LASTVAL_NONE].token = GIMP_DDESC_NONE; token_tab[GIMP_LASTVAL_ARRAY].token = GIMP_DDESC_ARRAY; token_tab[GIMP_LASTVAL_STRUCT_BEGIN].token = GIMP_DDESC_STRUCT_BEGIN; token_tab[GIMP_LASTVAL_STRUCT_END].token = GIMP_DDESC_STRUCT_END; token_tab[GIMP_LASTVAL_LONG].token = GIMP_DDESC_LONG; token_tab[GIMP_LASTVAL_SHORT].token = GIMP_DDESC_SHORT; token_tab[GIMP_LASTVAL_INT].token = GIMP_DDESC_INT; token_tab[GIMP_LASTVAL_GINT].token = GIMP_DDESC_GINT; token_tab[GIMP_LASTVAL_GINT32].token = GIMP_DDESC_GINT32; token_tab[GIMP_LASTVAL_CHAR].token = GIMP_DDESC_CHAR; token_tab[GIMP_LASTVAL_GCHAR].token = GIMP_DDESC_GCHAR; token_tab[GIMP_LASTVAL_GUCHAR].token = GIMP_DDESC_GUCHAR; token_tab[GIMP_LASTVAL_GDOUBLE].token = GIMP_DDESC_GDOUBLE; token_tab[GIMP_LASTVAL_GFLOAT].token = GIMP_DDESC_GFLOAT; token_tab[GIMP_LASTVAL_FLOAT].token = GIMP_DDESC_FLOAT; token_tab[GIMP_LASTVAL_DOUBLE].token = GIMP_DDESC_DOUBLE; token_tab[GIMP_LASTVAL_DRAWABLE].token = GIMP_DDESC_DRAWABLE; token_tab[GIMP_LASTVAL_GINTDRAWABLE].token = GIMP_DDESC_GINTDRAWABLE; token_tab[GIMP_LASTVAL_GBOOLEAN].token = GIMP_DDESC_GBOOLEAN; token_tab[GIMP_LASTVAL_ENUM].token = GIMP_DDESC_ENUM; token_tab[GIMP_LASTVAL_GUINT].token = GIMP_DDESC_GUINT; token_tab[GIMP_LASTVAL_GUINT32].token = GIMP_DDESC_GUINT32; token_tab[GIMP_LASTVAL_END].token = GIMP_DDESC_END; /* type lastval_type informations */ token_tab[GIMP_LASTVAL_NONE].lastval_type = GIMP_LASTVAL_NONE; token_tab[GIMP_LASTVAL_ARRAY].lastval_type = GIMP_LASTVAL_ARRAY; token_tab[GIMP_LASTVAL_STRUCT_BEGIN].lastval_type = GIMP_LASTVAL_STRUCT_BEGIN; token_tab[GIMP_LASTVAL_STRUCT_END].lastval_type = GIMP_LASTVAL_STRUCT_END; token_tab[GIMP_LASTVAL_LONG].lastval_type = GIMP_LASTVAL_LONG; token_tab[GIMP_LASTVAL_SHORT].lastval_type = GIMP_LASTVAL_SHORT; token_tab[GIMP_LASTVAL_INT].lastval_type = GIMP_LASTVAL_INT; token_tab[GIMP_LASTVAL_GINT].lastval_type = GIMP_LASTVAL_GINT; token_tab[GIMP_LASTVAL_GINT32].lastval_type = GIMP_LASTVAL_GINT32; token_tab[GIMP_LASTVAL_CHAR].lastval_type = GIMP_LASTVAL_CHAR; token_tab[GIMP_LASTVAL_GCHAR].lastval_type = GIMP_LASTVAL_GCHAR; token_tab[GIMP_LASTVAL_GUCHAR].lastval_type = GIMP_LASTVAL_GUCHAR; token_tab[GIMP_LASTVAL_GDOUBLE].lastval_type = GIMP_LASTVAL_GDOUBLE; token_tab[GIMP_LASTVAL_GFLOAT].lastval_type = GIMP_LASTVAL_GFLOAT; token_tab[GIMP_LASTVAL_FLOAT].lastval_type = GIMP_LASTVAL_FLOAT; token_tab[GIMP_LASTVAL_DOUBLE].lastval_type = GIMP_LASTVAL_DOUBLE; token_tab[GIMP_LASTVAL_DRAWABLE].lastval_type = GIMP_LASTVAL_DRAWABLE; token_tab[GIMP_LASTVAL_GINTDRAWABLE].lastval_type = GIMP_LASTVAL_GINTDRAWABLE; token_tab[GIMP_LASTVAL_GBOOLEAN].lastval_type = GIMP_LASTVAL_GBOOLEAN; token_tab[GIMP_LASTVAL_ENUM].lastval_type = GIMP_LASTVAL_ENUM; token_tab[GIMP_LASTVAL_GUINT].lastval_type = GIMP_LASTVAL_GUINT; token_tab[GIMP_LASTVAL_GUINT32].lastval_type = GIMP_LASTVAL_GUINT32; token_tab[GIMP_LASTVAL_END].lastval_type = 0; token_table_initialized = TRUE; } } /* end p_init_token_table */ static gchar * p_load_lastval_desc_file(const gchar *fname) { FILE *fp; gint32 file_size; struct stat stat_buf; gchar *file_buff; file_size = 0; file_buff = NULL; /* get filelength */ if (0 == g_stat(fname, &stat_buf)) { file_size = stat_buf.st_size; /* load File into Buffer */ file_buff = g_malloc0(file_size+1); fp = g_fopen(fname, "rb"); /* open read */ if(fp == NULL) { printf ("open(read) error on '%s'\n", fname); g_free(file_buff); } fread(file_buff, 1, file_size, fp); fclose(fp); } return (file_buff); } /* end p_load_lsatval_desc_file */ static void p_fwrite_lastvals_desc(FILE *fp, const gchar *keyname, GimpLastvalDescType *lastval_desc_arr, gint32 argc) { p_init_token_table(); if(fp) { gint32 l_idx; gint l_indent; gint l_col; struct tm *l_t; long l_ti; l_indent = 0; l_ti = time(0L); /* Get UNIX time */ l_t = localtime(&l_ti); /* konvert time to tm struct */ fprintf(fp, "\"%s\" ", keyname); fprintf(fp, "#- added or changed by GIMP on %04d-%02d-%02d %02d:%02d:%02d\n" , l_t->tm_year + 1900 , l_t->tm_mon + 1 , l_t->tm_mday , l_t->tm_hour , l_t->tm_min , l_t->tm_sec ); for(l_idx=0; l_idx < argc; l_idx++) { if(lastval_desc_arr[l_idx].lastval_type == GIMP_LASTVAL_STRUCT_END) { l_indent--; } for(l_col=0; l_col < l_indent; l_col++) { fprintf(fp, " "); } fprintf(fp, "%s;%d;%d;%d;%s\n" , token_tab[lastval_desc_arr[l_idx].lastval_type].token , (int)lastval_desc_arr[l_idx].offset , (int)lastval_desc_arr[l_idx].elem_size , (int)lastval_desc_arr[l_idx].iter_flag , lastval_desc_arr[l_idx].elem_name ); if(lastval_desc_arr[l_idx].lastval_type == GIMP_LASTVAL_STRUCT_BEGIN) { l_indent++; } } fprintf(fp, "END;\n"); } } /* end p_fwrite_lastvals_desc */ static gint32 p_fwrite_lines_until_keyname(FILE *fp, const char *keyname, gchar *ptr) { gint32 l_idx; gint32 l_lin; l_idx = 0; l_lin = 0; if((ptr) && (fp)) { while(ptr[l_idx] != '\0') { l_lin = l_idx; /* skip white space */ while((ptr[l_idx] == ' ') || (ptr[l_idx] == '\t')) { l_idx++; } if(ptr[l_idx] == '"') { if(strncmp(&ptr[l_idx+1], keyname, strlen(keyname)) == 0) { l_idx = l_lin; break; } } /* skip rest of the line */ while(ptr[l_idx] != '\0') { if (ptr[l_idx] == '\n') { l_idx++; break; } l_idx++; } } fwrite(ptr, l_idx, 1, fp); } return l_idx; } /* end p_fwrite_lines_until_keyname */ static void p_fwrite_lines_remaining_without_keyname(FILE *fp, const char *keyname, gchar *ptr) { gint32 l_idx; gint32 l_lin; gboolean l_write_flag; l_idx = 0; l_lin = 0; l_write_flag = TRUE; if((ptr) && (fp)) { while(ptr[l_idx] != '\0') { l_lin = l_idx; /* skip white space */ while((ptr[l_idx] == ' ') || (ptr[l_idx] == '\t')) { l_idx++; } if(ptr[l_idx] == '"') { if(strncmp(&ptr[l_idx+1], keyname, strlen(keyname)) == 0) { l_write_flag = FALSE; /* dont write matching description block(s) */ } else { l_write_flag = TRUE; /* write all non-matching description blocks */ } } /* skip rest of the line */ while(ptr[l_idx] != '\0') { if (ptr[l_idx] == '\n') { l_idx++; break; } l_idx++; } if((l_write_flag) && (l_idx > l_lin)) { /* write one line to file */ fwrite(&ptr[l_lin], l_idx - l_lin, 1, fp); } if(strncmp(&ptr[l_lin], "END;", 4) == 0) { l_write_flag = TRUE; /* enable write when block has ended */ } } } } /* end p_fwrite_lines_remaining_without_keyname */ static void p_lastvals_register_persistent(const gchar *keyname, GimpLastvalDescType *lastval_desc_arr, gint32 argc) { FILE *fp; gchar *fname; gchar *file_buff; gchar *ptr; gint32 bytes_written; fname = gimp_lastval_desc_filename(); file_buff = p_load_lastval_desc_file(fname); ptr = file_buff; /* rewrite file (replacing or adding the structure description block for keyname) */ fp = g_fopen(fname, "w"); if(fp) { /* write all lines until 1.st description line matching keyname */ bytes_written = p_fwrite_lines_until_keyname(fp, keyname, ptr); if(bytes_written > 0) { ptr += bytes_written; } else { /* start with comment header if file was empty */ fprintf(fp, "# Descriptionfile LAST_VALUES buffer structure (type;offset;size;iterflag,name)\n"); fprintf(fp, "#\n"); fprintf(fp, "# this file is rewritten each time when a procedure registers\n"); fprintf(fp, "# the LAST_VALUES structure. (typical at 1.st gimp startup\n"); fprintf(fp, "# or after installation of new plug-ins)\n"); fprintf(fp, "#\n"); } /* append description lines for keyname (or replace 1.st occurance) */ p_fwrite_lastvals_desc(fp, keyname, lastval_desc_arr, argc); /* copy the rest without description block(s) for keyname */ p_fwrite_lines_remaining_without_keyname(fp, keyname, ptr); fclose(fp); } else { printf("p_lastvals_register_persistent: error at open write file: %s\n", fname); } g_free(fname); } /* end p_lastvals_register_persistent */ gimp-gap-2.6.0+dfsg.orig/gap/gap_morph_exec.h0000644000175000017500000000512111212030253020644 0ustar thibautthibaut/* gap_morph_exec.h * 2004.02.12 hof (Wolfgang Hofer) * layer morphing worker procedures * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 1.3.26a; 2004/02/12 hof: created */ #ifndef _GAP_MORPH_EXEC_H #define _GAP_MORPH_EXEC_H #include "libgimp/gimp.h" #include "gap_morph_main.h" #include "gap_morph_dialog.h" #include "gap_libgimpgap.h" void gap_morph_exec_free_workpoint_list(GapMorphWorkPoint **wp_list); gboolean gap_moprh_exec_save_workpointfile(const char *filename , GapMorphGUIParams *mgup ); GapMorphWorkPoint * gap_moprh_exec_load_workpointfile(const char *filename , GapMorphGUIParams *mgup ); gint32 gap_morph_exec_find_dst_drawable(gint32 image_id, gint32 layer_id); void gap_morph_exec_get_warp_pick_koords(GapMorphWorkPoint *wp_list , gint32 in_x , gint32 in_y , gdouble scale_x , gdouble scale_y , gboolean use_quality_wp_selection , gboolean use_gravity , gdouble gravity_intensity , gdouble affect_radius , gdouble *pick_x , gdouble *pick_y ); gint32 gap_morph_execute(GapMorphGlobalParams *mgpp); gint32 gap_morph_render_one_tween(GapMorphGlobalParams *mgpp); gint32 gap_morph_render_frame_tweens(GapAnimInfo *ainfo_ptr, GapMorphGlobalParams *mgpp); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_fmac_name.h0000644000175000017500000000314211212030253020422 0ustar thibautthibaut/* gap_fmac_name.h * 2006.12.19 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * - filtermacro name definitions and filename convention procedures. * * WARNING: * filtermacros are a temporary solution, useful for animations * but do not expect support for filtermacros in future releases of GIMP-GAP * because GIMP may have real makro features in the future ... * * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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_NAME_H #define GAP_FMAC_NAME_H #include "libgimp/gimp.h" #define GAP_FMACNAME_PLUG_IN_NAME_FMAC_VARYING "plug_in_filter_macro_varying" #define GAP_FMACNAME_PLUG_IN_NAME_FMAC "plug_in_filter_macro" gboolean gap_fmac_chk_filtermacro_file(const char *filtermacro_file); char * gap_fmac_get_alternate_name(const char *filtermacro_file); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_libgimpgap.h0000644000175000017500000000273011212030253020631 0ustar thibautthibaut/* gap_libgimpgap.h * 1997.11.01 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * Master includefile for the library libgimpgap * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 1.3.20d 2003/10/09 hof: created */ #ifndef _LIBGIMPGAP_H #define _LIBGIMPGAP_H #include "libgimp/gimp.h" #include "gap-intl.h" #include "gap_arr_dialog.h" #include "gap_image.h" #include "gap_layer_copy.h" #include "gap_lib.h" #include "gap_lock.h" #include "gap_navi_activtable.h" #include "gap_match.h" #include "gap_onion_base.h" #include "gap_pdb_calls.h" #include "gap_pview_da.h" #include "gap_thumbnail.h" #include "gap_timeconv.h" #include "gap_stock.h" #include "gap_vin.h" #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_player_dialog.c0000644000175000017500000102013211212030253021321 0ustar thibautthibaut/* gap_player_dialog.c * * video (preview) playback of video frames by Wolfgang Hofer (hof) * supports both (fast) thumbnail based playback * and full image playback (slow) * the current implementation has audio support for RIFF WAV audiofiles * but requires the wavplay executable as external audioserver program. * 2003/09/07 * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Revision history * (2007/11/01) v2.3.0 hof: - gimprc changed to "show-tooltips" with gimp-2.4 * (2004/11/12) v2.1.0 hof: - added help button * (2004/03/17) v1.3.27a hof: - go_timer does check if video api is busy and retries * to display the wanted frame if video fetch (of previous frame) * has finished. * - use go_timer to display final frame when play_timer stops. * - use go_timer to display current frame on_framenr_spinbutton_changed * (2004/03/16) v1.3.27a hof: - merged in changes from stable branch: * declare varibales for audiosupport only if GAP_ENABLE_AUDIO_SUPPORT defined * (2004/03/07) v1.3.26b hof: - click on preview opens/replaces the mtrace image * (2004/03/04) v1.3.26b hof: - bugfixes Videofile playback * (2004/02/29) v1.3.26b hof: - Basic Videoapi support (p_fetch_videoframe) * (2004/02/26) v1.3.26b hof: - From/To convert from Button to Label * (2004/02/14) v1.3.26b hof: - if not standalone: Player can run in docked_mode (without having own shell window) * (2004/02/01) v1.3.26b hof: - Player can run in standalone mode (as it did before) * or act as Playback widget window that does not call gtk_main_quit * as it is required for use in the Storyboard dialog module. * - Support for Storyboard level1 playback * - most callbacks now directly use GapPlayerMainGlobalParams *gpp * rather than gpointer *user_data * (2004/01/22) v1.3.25a hof: performance tuning: use gap_thumb_file_load_pixbuf_thumbnail * (2004/01/19) v1.3.24b hof: bugfix: spinbutton callbacks must connect to "value_changed" signal * (2004/01/16) v1.3.22c hof: use gap_thumb_file_load_thumbnail (for faster thumb loading) * (2003/11/15) v1.3.22c hof: bugfix: SHIFT size button * (2003/11/01) v1.3.21d hof: cleanup messages * (2003/10/14) v1.3.20d hof: sourcecode cleanup * (2003/10/06) v1.3.20d hof: bugfix: changed shell_window resize handling * (2003/09/29) v1.3.20c hof: moved gap_arr_overwrite_file_dialog to module gap_arr_dialog.c * (2003/09/23) v1.3.20b hof: use GAPLIBDIR to locate audioconvert_to_wav.sh * (2003/09/14) v1.3.20a hof: bugfix: added p_create_wav_dialog * now can create and resample WAVFILE from other audiofiles (MP3 and others) * based on external shellscript (using SOX and LAME to do that job) * Replaced direct wavplay Procedure calls * by abstracted AudioPlayerClient (APCL_) Procedures * (2003/09/09) v1.3.19b hof: bugfix: on_framenr_spinbutton_changed must resync audio to the new Position when playing * bugfix: Selection of a new audiofile did continue play the old one * (2003/09/07) v1.3.19a hof: audiosupport (based on wavplay, for UNIX only), * audiosupport is on by default, and can be disabled by defining * GAP_DISABLE_WAV_AUDIOSUPPORT * (2003/08/27) v1.3.18b hof: added ctrl/alt modifiers on_go_button_clicked, * added p_printout_range (for STORYBOARD FILE Processing * in the still unpublished GAP Videoencoder Project) * (2003/07/31) v1.3.17b hof: message text fixes for translators (# 118392) * (2003/06/26) v1.3.16a hof: bugfix: make preview drawing_area fit into frame (use an aspect_frame) * query gimprc for "show-tool-tips" * (2003/06/21) v1.3.15a hof: created */ /* undefining GAP_ENABLE_AUDIO_SUPPORT will disable all audio stuff * at compiletime */ #include "config.h" #include #include #include #include #include #include #include #include #include "gap_libgapbase.h" #include "gap_player_main.h" #include "gap_player_dialog.h" #include "gap_pdb_calls.h" #include "gap_pview_da.h" #include "gap_stock.h" #include "gap_lib.h" #include "gap_image.h" #include "gap_vin.h" #include "gap_timeconv.h" #include "gap_thumbnail.h" #include "gap_arr_dialog.h" #include "gap_story_file.h" #include "gap_story_render_processor.h" #include "gap_layer_copy.h" #include "gap_onion_base.h" #include "gap_audio_extract.h" #include "gap_audio_extract.h" #include "gap_drawable_vref_parasite.h" #include "gap-intl.h" extern int gap_debug; /* 1 == print debug infos , 0 dont print debug infos */ int cmdopt_x = 0; /* Debug option flag for wavplay */ #ifdef GAP_ENABLE_AUDIO_SUPPORT #include "wpc_lib.h" /* headerfile for libwavplayclient (preferred) */ char *env_WAVPLAYPATH = WAVPLAYPATH; /* Default pathname of executable /usr/local/bin/wavplay */ char *env_AUDIODEV = AUDIODEV; /* Default compiled in audio device */ unsigned long env_AUDIOLCK = AUDIOLCK; /* Default compiled in locking semaphore */ #else char *env_WAVPLAYPATH = NULL; /* Default pathname of executable /usr/local/bin/wavplay */ char *env_AUDIODEV = NULL; /* Default compiled in audio device */ unsigned long env_AUDIOLCK = 0; /* Default compiled in locking semaphore */ #endif #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT #include "gap_vid_api.h" #endif #define GAP_PLAYER_MIN_SIZE 64 #define GAP_PLAYER_MAX_SIZE 800 #define GAP_STANDARD_PREVIEW_SIZE 256 #define GAP_SMALL_PREVIEW_SIZE 128 #define GAP_PLAYER_CHECK_SIZE 6 #define GAP_PLAY_MAX_GOBUTTONS 51 #define GAP_PLAY_MAX_GOBUTTONS_DOCKED 41 #define GAP_PLAYER_MIDDLE_GO_NUMBER ((GAP_PLAY_MAX_GOBUTTONS / 2)) #define GAP_PLAY_AUDIO_ENTRY_WIDTH 300 #define GAP_PLAY_AUDIO_ENTRY_WIDTH_DOCKED 130 #define GAP_PLAYER_VID_FRAMES_TO_KEEP_CACHED 50 #define KEY_FRAMENR_BUTTON_TYPE "gap_player_framnr_button_type" #define FRAMENR_BUTTON_BEGIN 0 #define FRAMENR_BUTTON_END 1 typedef struct t_gobutton { GapPlayerMainGlobalParams *gpp; gint go_number; } t_gobutton; static gint32 global_max_vid_frames_to_keep_cached = 0; /* the callbacks */ static void on_shell_window_destroy (GtkObject *object, GapPlayerMainGlobalParams *gpp); static void on_help_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp); static void on_from_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp); static void on_to_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp); static gboolean on_vid_preview_button_press_event (GtkWidget *widget, GdkEventButton *bevent, GapPlayerMainGlobalParams *gpp); static gboolean on_warp_frame_scroll_event (GtkWidget *widget, GdkEventScroll *sevent, GapPlayerMainGlobalParams *gpp); static gboolean on_vid_preview_expose_event (GtkWidget *widget, GdkEventExpose *eevent, GapPlayerMainGlobalParams *gpp); static void on_vid_preview_size_allocate (GtkWidget *widget, GtkAllocation *allocation, GapPlayerMainGlobalParams *gpp); static void on_shell_window_size_allocate (GtkWidget *widget, GtkAllocation *allocation, GapPlayerMainGlobalParams *gpp); static void on_framenr_button_clicked (GtkButton *button, GdkEventButton *bevent, GapPlayerMainGlobalParams *gpp); static void on_from_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp); static void on_to_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp); static gboolean on_framenr_scale_clicked (GtkWidget *widget, GdkEvent *event, GapPlayerMainGlobalParams *gpp); static void on_framenr_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp); static void on_origspeed_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp); static void on_speed_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp); static void p_fit_initial_shell_window (GapPlayerMainGlobalParams *gpp); static void p_fit_shell_window (GapPlayerMainGlobalParams *gpp); static gboolean on_size_button_button_press_event (GtkWidget *widget, GdkEventButton *event, GapPlayerMainGlobalParams *gpp); static void on_size_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp); static gboolean on_size_spinbutton_enter (GtkWidget *widget, GdkEvent *event, GapPlayerMainGlobalParams *gpp); static gboolean on_shell_window_leave (GtkWidget *widget, GdkEvent *event, GapPlayerMainGlobalParams *gpp); static void on_exact_timing_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp); static void on_use_thumb_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp); static void on_pinpong_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp); static void on_selonly_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp); static void on_loop_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp); static void on_show_gobuttons_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp); static void on_show_positionscale_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp); static void on_play_button_clicked (GtkButton *button, GdkEventButton *bevent, GapPlayerMainGlobalParams *gpp); static gboolean on_pause_button_press_event (GtkButton *button, GdkEventButton *bevent, GapPlayerMainGlobalParams *gpp); static void on_back_button_clicked (GtkButton *button, GdkEventButton *bevent, GapPlayerMainGlobalParams *gpp); static void on_close_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp); static void on_timer_playback (GapPlayerMainGlobalParams *gpp); static void on_timer_go_job (GapPlayerMainGlobalParams *gpp); static void on_go_button_clicked (GtkButton *button, GdkEventButton *bevent, t_gobutton *gob); static gboolean on_go_button_enter (GtkButton *button, GdkEvent *event, t_gobutton *gob); static void on_gobutton_hbox_leave (GtkWidget *widget, GdkEvent *event, GapPlayerMainGlobalParams *gpp); static void on_audio_enable_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp); static void on_audio_volume_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp); static void on_audio_frame_offset_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp); static void on_audio_reset_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp); static void on_audio_create_copy_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp); static void on_audio_filesel_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp); static void on_audio_filename_entry_changed (GtkWidget *widget, GapPlayerMainGlobalParams *gpp); static void on_cancel_vindex_button_clicked (GtkObject *object, GapPlayerMainGlobalParams *gpp); static void on_audio_auto_offset_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp); static void on_audio_otone_extract_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp); static void on_audio_otone_atrack_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp); static void p_msg_progress_bar_audio(GapPlayerMainGlobalParams *gpp, const char *msg); static void p_reset_progress_bar_audio(GapPlayerMainGlobalParams *gpp); static void p_step_frame(GapPlayerMainGlobalParams *gpp, gint stepsize); static void p_set_frame_with_name_label(GapPlayerMainGlobalParams *gpp); static void p_update_position_widgets(GapPlayerMainGlobalParams *gpp); static void p_stop_playback(GapPlayerMainGlobalParams *gpp); static void p_connect_resize_handler(GapPlayerMainGlobalParams *gpp); static void p_disconnect_resize_handler(GapPlayerMainGlobalParams *gpp); static gboolean p_vid_progress_callback(gdouble progress ,gpointer user_data ); static void p_close_videofile(GapPlayerMainGlobalParams *gpp); static void p_open_videofile(GapPlayerMainGlobalParams *gpp , char *filename , gint32 seltrack , gdouble delace , const char *preferred_decoder ); static guchar * p_fetch_videoframe(GapPlayerMainGlobalParams *gpp , char *gva_videofile , gint32 framenumber , gint32 rangesize , gint32 seltrack , gdouble delace , const char *preferred_decoder , gint32 *th_bpp , gint32 *th_width , gint32 *th_height ); static void p_init_video_playback_cache(GapPlayerMainGlobalParams *gpp); static void p_init_layout_options(GapPlayerMainGlobalParams *gpp); static guchar * p_fetch_frame_via_cache(GapPlayerMainGlobalParams *gpp , const gchar *ckey , gint32 *th_bpp_ptr , gint32 *th_width_ptr , gint32 *th_height_ptr , gint32 *flip_status_ptr ); static guchar * p_fetch_videoframe_via_cache(GapPlayerMainGlobalParams *gpp , char *gva_videofile , gint32 framenumber , gint32 rangesize , gint32 seltrack , gdouble delace , const char *preferred_decoder , gint32 *th_bpp_ptr , gint32 *th_width_ptr , gint32 *th_height_ptr , gint32 *flip_status_ptr , const gchar *ckey ); static void p_frame_chache_processing(GapPlayerMainGlobalParams *gpp , const gchar *ckey); static void p_update_cache_status (GapPlayerMainGlobalParams *gpp); static void p_audio_startup_server(GapPlayerMainGlobalParams *gpp); static gint32 p_get_audio_relevant_FrameNr(GapPlayerMainGlobalParams *gpp, gint32 framenr); static const char* p_get_default_tmp_otone_audiofilename(); static char * p_build_otone_audiofilename(const char *videofilename, gint32 atrack, const char *suffix); static gboolean p_check_otone_workfile_up_to_date(const char *videofilename, const char *audiofilename, gint32 l_extract_audiotrack); static void p_update_ainfo_for_videofile(GapPlayerMainGlobalParams *gpp); /* ----------------------------- * p_check_tooltips * ----------------------------- */ static void p_check_tooltips(void) { gap_base_check_tooltips(NULL); } /* end p_check_tooltips */ /* ----------------------------- * p_audio_errfunc * ----------------------------- */ static void p_audio_errfunc(const char *format,va_list ap) { char buf[1024]; vsnprintf(buf,sizeof(buf),format,ap); /* Format the message */ g_message(_("Problem with audioplayback. The audiolib reported:\n%s"),buf); } /* end p_audio_errfunc */ /* ----------------------------- * p_create_wav_dialog * ----------------------------- * return TRUE : OK, caller can create the wavefile * FALSE: user has cancelled, dont create wavefile */ static gboolean p_create_wav_dialog(GapPlayerMainGlobalParams *gpp) { static GapArrArg argv[4]; gint l_ii; gint l_ii_resample; gint l_ii_samplerate; l_ii = 0; gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_LABEL_LEFT); argv[l_ii].label_txt = _("Audiosource:"); argv[l_ii].text_buf_ret = gpp->audio_filename; g_snprintf(gpp->audio_wavfile_tmp ,sizeof(gpp->audio_wavfile_tmp) ,"%s.tmp.wav" ,gpp->audio_filename ); l_ii++; gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_FILESEL); argv[l_ii].label_txt = _("Wavefile:"); argv[l_ii].entry_width = 400; argv[l_ii].help_txt = _("Name of wavefile to create as copy in RIFF WAVE format"); argv[l_ii].text_buf_len = sizeof(gpp->audio_wavfile_tmp); argv[l_ii].text_buf_ret = gpp->audio_wavfile_tmp; l_ii++; l_ii_resample = l_ii; gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_TOGGLE); argv[l_ii].label_txt = _("Resample:"); argv[l_ii].help_txt = _("ON: Resample the copy at specified samplerate.\n" "OFF: Use original samplerate"); argv[l_ii].int_ret = 1; l_ii++; l_ii_samplerate = l_ii; gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_INT_PAIR); argv[l_ii].constraint = TRUE; argv[l_ii].label_txt = _("Samplerate:"); argv[l_ii].help_txt = _("Target audio samplerate in samples/sec. Ignored if resample is off"); argv[l_ii].int_min = (gint)GAP_PLAYER_MAIN_MIN_SAMPLERATE; argv[l_ii].int_max = (gint)GAP_PLAYER_MAIN_MAX_SAMPLERATE; argv[l_ii].int_ret = (gint)22050; if(gpp->audio_samples > 0) { /* the original is a valid wavefile * in that case we know the samplerate of the original audiofile * and can limit the samplerate of the copy to this size * (resample with higher rates does not improve quality and is a waste of memory. * Making a copy of the input wavfile should use a lower samplerate * that makes it possible for the audioserver to follow fast videoplayback * by switching from the original to the copy) */ argv[l_ii].int_min = (gint)GAP_PLAYER_MAIN_MIN_SAMPLERATE; argv[l_ii].int_max = (gint)MIN(gpp->audio_samplerate, GAP_PLAYER_MAIN_MAX_SAMPLERATE); argv[l_ii].int_ret = (gint)MIN((gpp->audio_samplerate / 2), GAP_PLAYER_MAIN_MAX_SAMPLERATE); } if(TRUE == gap_arr_ok_cancel_dialog( _("Copy Audiofile as Wavefile"), _("Settings"), G_N_ELEMENTS(argv), argv)) { gpp->audio_tmp_resample = (gboolean)(argv[l_ii_resample].int_ret); gpp->audio_tmp_samplerate = (gint32)(argv[l_ii_samplerate].int_ret); return (gap_arr_overwrite_file_dialog(gpp->audio_wavfile_tmp)); } return (FALSE); } /* end p_create_wav_dialog */ /* ----------------------------- * p_audio_shut_server * ----------------------------- */ static void p_audio_shut_server(GapPlayerMainGlobalParams *gpp) { #ifdef GAP_ENABLE_AUDIO_SUPPORT /* if (gap_debug) printf("p_audio_shut_server\n"); */ if(gpp->audio_status > GAP_PLAYER_MAIN_AUSTAT_NONE) { apcl_bye(0, p_audio_errfunc); } gpp->audio_status = GAP_PLAYER_MAIN_AUSTAT_NONE; #endif return; } /* end p_audio_shut_server */ /* ----------------------------- * p_audio_resync * ----------------------------- */ static void p_audio_resync(GapPlayerMainGlobalParams *gpp) { #ifdef GAP_ENABLE_AUDIO_SUPPORT if(gpp->audio_resync < 1) { gpp->audio_resync = 1 + (gpp->speed / 5); } /* if (gap_debug) printf("p_audio_resync :%d\n", (int)gpp->audio_resync); */ #endif return; } /* end p_audio_resync */ /* ----------------------------- * p_audio_stop * ----------------------------- */ static void p_audio_stop(GapPlayerMainGlobalParams *gpp) { #ifdef GAP_ENABLE_AUDIO_SUPPORT /* if (gap_debug) printf("p_audio_stop\n"); */ if(gpp->audio_status > GAP_PLAYER_MAIN_AUSTAT_NONE) { apcl_stop(0,p_audio_errfunc); /* Tell the server to stop */ gpp->audio_status = MIN(gpp->audio_status, GAP_PLAYER_MAIN_AUSTAT_FILENAME_SET); } #endif return; } /* end p_audio_stop */ /* ----------------------------- * p_audio_init * ----------------------------- */ static void p_audio_init(GapPlayerMainGlobalParams *gpp) { #ifdef GAP_ENABLE_AUDIO_SUPPORT /* if (gap_debug) printf("p_audio_init\n"); */ if(gpp->audio_samples > 0) /* audiofile has samples (seems to be a valid audiofile) */ { if(gpp->audio_status == GAP_PLAYER_MAIN_AUSTAT_UNCHECKED) { p_audio_startup_server(gpp); if(gpp->audio_enable != TRUE) { return; } gpp->audio_status = GAP_PLAYER_MAIN_AUSTAT_NONE; } if(gpp->audio_status <= GAP_PLAYER_MAIN_AUSTAT_NONE) { if ( apcl_start(p_audio_errfunc) < 0 ) { g_message(_("Failure to start the wavplay server is fatal.\n" "Please check the executability of the 'wavplay' command.\n" "If you have installed the wavplay executeable somewhere\n" "you can set the Environmentvariable WAVPLAYPATH before gimp startup\n")); } else { gpp->audio_status = GAP_PLAYER_MAIN_AUSTAT_SERVER_STARTED; } /* apcl_semreset(0,p_audio_errfunc); */ /* Tell server to reset semaphores */ } else { p_audio_stop(gpp); } if(gpp->audio_status < GAP_PLAYER_MAIN_AUSTAT_FILENAME_SET) { apcl_path(gpp->audio_filename,0,p_audio_errfunc); /* Tell server the new path */ gpp->audio_status = GAP_PLAYER_MAIN_AUSTAT_FILENAME_SET; } } #endif return; } /* end p_audio_init */ /* ----------------------------- * p_audio_print_labels * ----------------------------- */ static void p_audio_print_labels(GapPlayerMainGlobalParams *gpp) { char txt_buf[100]; gint len; gint32 l_samplerate; gint32 l_samples; gint32 l_videoframes; l_samples = gpp->audio_samples; l_samplerate = gpp->audio_samplerate; if (gap_debug) { printf("p_audio_print_labels\n"); printf("audio_filename: %s\n", gpp->audio_filename); printf("audio_enable: %d\n", (int)gpp->audio_enable); printf("audio_frame_offset: %d\n", (int)gpp->audio_frame_offset); printf("audio_bits: %d\n", (int)gpp->audio_bits); printf("audio_channels: %d\n", (int)gpp->audio_channels); printf("audio_samplerate: %d\n", (int)gpp->audio_samplerate); printf("audio_samples: %d\n", (int)gpp->audio_samples); printf("audio_status: %d\n", (int)gpp->audio_status); } if(gpp->audio_frame_offset < 0) { gap_timeconv_framenr_to_timestr( (gint32)(0 - gpp->audio_frame_offset) , (gdouble)gpp->original_speed , txt_buf , sizeof(txt_buf) ); len = strlen(txt_buf); g_snprintf(&txt_buf[len], sizeof(txt_buf)-len, " %s", _("Audio Delay")); } else { gap_timeconv_framenr_to_timestr( (gint32)(gpp->audio_frame_offset) , (gdouble)gpp->original_speed , txt_buf , sizeof(txt_buf) ); len = strlen(txt_buf); if(gpp->audio_frame_offset == 0) { g_snprintf(&txt_buf[len], sizeof(txt_buf)-len, " %s", _("Syncron")); } else { g_snprintf(&txt_buf[len], sizeof(txt_buf)-len, " %s", _("Audio Skipped")); } } gtk_label_set_text ( GTK_LABEL(gpp->audio_offset_time_label), txt_buf); gap_timeconv_samples_to_timestr( l_samples , (gdouble)l_samplerate , txt_buf , sizeof(txt_buf) ); gtk_label_set_text ( GTK_LABEL(gpp->audio_total_time_label), txt_buf); g_snprintf(txt_buf, sizeof(txt_buf), _("%d (at %.4f frames/sec)") , (int)gap_timeconv_samples_to_frames(l_samples ,(gdouble)l_samplerate ,(gdouble)gpp->original_speed /* framerate */ ) , (float)gpp->original_speed ); gtk_label_set_text ( GTK_LABEL(gpp->audio_total_frames_label), txt_buf); g_snprintf(txt_buf, sizeof(txt_buf), "%d", (int)l_samples ); gtk_label_set_text ( GTK_LABEL(gpp->audio_samples_label), txt_buf); g_snprintf(txt_buf, sizeof(txt_buf), "%d", (int)l_samplerate ); gtk_label_set_text ( GTK_LABEL(gpp->audio_samplerate_label), txt_buf); g_snprintf(txt_buf, sizeof(txt_buf), "%d", (int)gpp->audio_bits ); gtk_label_set_text ( GTK_LABEL(gpp->audio_bits_label), txt_buf); g_snprintf(txt_buf, sizeof(txt_buf), "%d", (int)gpp->audio_channels ); gtk_label_set_text ( GTK_LABEL(gpp->audio_channels_label), txt_buf); l_videoframes = 0; if(gpp->ainfo_ptr) { l_videoframes = 1+ (gpp->ainfo_ptr->last_frame_nr - gpp->ainfo_ptr->first_frame_nr); } gap_timeconv_framenr_to_timestr( l_videoframes , gpp->original_speed , txt_buf , sizeof(txt_buf) ); gtk_label_set_text ( GTK_LABEL(gpp->video_total_time_label), txt_buf); g_snprintf(txt_buf, sizeof(txt_buf), "%d", (int)l_videoframes); gtk_label_set_text ( GTK_LABEL(gpp->video_total_frames_label), txt_buf); } /* end p_audio_print_labels */ /* ----------------------------- * p_print_and_clear_audiolabels * ----------------------------- */ static void p_print_and_clear_audiolabels(GapPlayerMainGlobalParams *gpp) { gpp->audio_samplerate = 0; gpp->audio_bits = 0; gpp->audio_channels = 0; gpp->audio_samples = 0; p_audio_print_labels(gpp); } /* end p_print_and_clear_audiolabels */ /* ----------------------------- * p_audio_filename_changed * ----------------------------- * check if audiofile is a valid wavefile, * and tell audioserver to prepare if its OK * (but dont start to play, just keep audioserver stand by) */ static void p_audio_filename_changed(GapPlayerMainGlobalParams *gpp) { #ifdef GAP_ENABLE_AUDIO_SUPPORT int fd; int rc; int channels; /* Channels recorded in this wav file */ u_long samplerate; /* Sampling rate */ int sample_bits; /* data bit size (8/12/16) */ u_long samples; /* The number of samples in this file */ u_long datastart; /* The offset to the wav data */ if (gap_debug) { printf("p_audio_filename_changed to:%s:\n", gpp->audio_filename); } p_audio_stop(gpp); gpp->audio_status = MIN(gpp->audio_status, GAP_PLAYER_MAIN_AUSTAT_SERVER_STARTED); /* Open the file for reading: */ if ( (fd = g_open(gpp->audio_filename,O_RDONLY)) < 0 ) { p_print_and_clear_audiolabels(gpp); return; } rc = WaveReadHeader(fd ,&channels ,&samplerate ,&sample_bits ,&samples ,&datastart ,p_audio_errfunc); close(fd); if(rc != 0) { g_message (_("Error at reading WAV header from file '%s'") , gpp->audio_filename); p_print_and_clear_audiolabels(gpp); return; } gpp->audio_samplerate = samplerate; gpp->audio_bits = sample_bits; gpp->audio_channels = channels; gpp->audio_samples = samples; if (gap_debug) { printf("p_audio_filename_changed :%s:\n", gpp->audio_filename); printf(" audio_samplerate:%d:\n", gpp->audio_samplerate); printf(" audio_bits:%d:\n", gpp->audio_bits); printf(" audio_channels:%d:\n", gpp->audio_channels); printf(" audio_samples:%d:\n", gpp->audio_samples); } p_audio_print_labels(gpp); /* p_audio_init(gpp) must not be called here. * becuase it calls p_audio_startup_server and this will recursive call * p_audio_filename_changed in an endless loop.... * For now the audio_init is done later on 1st attempt to start playback. */ #endif return; } /* end p_audio_filename_changed */ /* --------------------------------- * p_get_audio_relevant_FrameNr * --------------------------------- * get relevant framenumber respecting offsets * local to the referenced video clip. * (if playback currently does not refer to a vide * return framenr unchanged) */ static gint32 p_get_audio_relevant_FrameNr(GapPlayerMainGlobalParams *gpp, gint32 framenr) { GapStoryLocateRet *stb_ret; gint32 localFrameNr; /* prepare standard behaviour * */ localFrameNr = framenr - gpp->ainfo_ptr->first_frame_nr; if(gpp->stb_ptr) { stb_ret = gap_story_locate_framenr(gpp->stb_ptr , framenr , gpp->stb_in_track ); if(stb_ret) { if((stb_ret->locate_ok) && (stb_ret->stb_elem)) { /* playback of a videoclip via storyboard clip */ if(stb_ret->stb_elem->record_type == GAP_STBREC_VID_MOVIE) { localFrameNr = stb_ret->ret_framenr; } } } } else { if(gpp->ainfo_ptr->ainfo_type == GAP_AINFO_MOVIE) { /* playback of a single videoclip */ localFrameNr = framenr; } } if(gap_debug) { printf("p_get_audio_relevant_FrameNr: framenr:%d localFrameNr:%d\n" ,framenr ,localFrameNr ); } return (localFrameNr); } /* end p_get_audio_relevant_FrameNr */ /* ----------------------------------------- * p_get_default_tmp_otone_audiofilename * ----------------------------------------- * returns a default name for the temporary otone audiofile. * (The caller must NOT g_free the returned string after usage). */ const char* p_get_default_tmp_otone_audiofilename() { static const char *name = "tmp_gap_extracted_original_audiotrack.wav"; return (name); } /* end p_get_default_tmp_otone_audiofilename */ /* ----------------------------------------- * p_build_otone_audiofilename * ----------------------------------------- * on writeable directory use videofilename + audiotrack + ".wav" extension * otherwise use a fixed name for the audiofile. * (The caller shall g_free the returned string after usage). */ char * p_build_otone_audiofilename(const char *videofilename, gint32 atrack, const char *suffix) { char *l_audiofilename; FILE *l_fp; if (suffix == NULL) { l_audiofilename = g_strdup_printf("%s.%d.wav", videofilename, atrack); } else { l_audiofilename = g_strdup_printf("%s%s.%d.wav", videofilename, suffix, atrack); } if(g_file_test(l_audiofilename, G_FILE_TEST_EXISTS)) { return(l_audiofilename); } /* test creation of l_audiofilename is possible */ l_fp = fopen(l_audiofilename, "w"); if (l_fp) { fclose(l_fp); /* file creation OK (we have write permission) * but immediate remove the file. */ g_remove(l_audiofilename); return(l_audiofilename); } l_audiofilename = g_strdup(p_get_default_tmp_otone_audiofilename()); return(l_audiofilename); } /* end p_build_otone_audiofilename */ /* ----------------------------------------- * p_check_otone_workfile_up_to_date * ----------------------------------------- * TODO: additional check if audiofile is complete * (in case extract was cancelled before the full length of the audiotrack could be written) */ gboolean p_check_otone_workfile_up_to_date(const char *videofilename, const char *audiofilename, gint32 l_extract_audiotrack) { char *l_audiofilename; if(!g_file_test(audiofilename, G_FILE_TEST_EXISTS)) { return(FALSE); } if(!g_file_test(videofilename, G_FILE_TEST_EXISTS)) { return(FALSE); } l_audiofilename = p_build_otone_audiofilename(videofilename , l_extract_audiotrack , NULL /* no suffix used */ ); if (strcmp(l_audiofilename, audiofilename) != 0) { return(FALSE); } if (strcmp(l_audiofilename, p_get_default_tmp_otone_audiofilename()) == 0) { return(FALSE); } if (gap_file_get_mtime(l_audiofilename) < gap_file_get_mtime(videofilename)) { return(FALSE); } return (TRUE); } /* end p_check_otone_workfile_up_to_date */ /* ----------------------------- * p_audio_start_play * ----------------------------- * conditional start audioplayback * note: if already playing this procedure does noting. * (first call p_audio_stop to stop the old playing audiofile * before you start another one) */ static void p_audio_start_play(GapPlayerMainGlobalParams *gpp) { #ifdef GAP_ENABLE_AUDIO_SUPPORT gdouble offset_start_sec; gint32 offset_start_samples; gdouble flt_samplerate; gint32 l_samplerate; gint32 l_samples; gdouble l_referedClipSpeed; /* if (gap_debug) printf("p_audio_start_play\n"); */ /* Never play audio when disabled, or video play backwards, * (reverse audio is not supported by the wavplay server) */ if(!gpp->audio_enable) { return; } if(gpp->audio_status >= GAP_PLAYER_MAIN_AUSTAT_PLAYING) { return; } if(gpp->play_backward) { return; } if(gpp->ainfo_ptr == NULL) { return; } l_samples = gpp->audio_samples; l_samplerate = gpp->audio_samplerate; l_referedClipSpeed = gpp->original_speed; if (gpp->audio_auto_offset_by_framenr == TRUE) { gint32 localFramenr; #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if (gpp->gvahand) { l_referedClipSpeed = gpp->gvahand->framerate; l_samplerate = gpp->gvahand->samplerate; } #endif localFramenr = p_get_audio_relevant_FrameNr(gpp, gpp->play_current_framenr); offset_start_sec = ( localFramenr + gpp->audio_frame_offset ) / MAX(1, l_referedClipSpeed); } else { offset_start_sec = ( gpp->play_current_framenr - gpp->ainfo_ptr->first_frame_nr + gpp->audio_frame_offset ) / MAX(1, gpp->original_speed); } offset_start_samples = offset_start_sec * l_samplerate; #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if(gap_debug) { printf("p_audio_start_play original_speed:%.3f refSpeed:%.3f audio_frame_offset:%d l_samples:%d l_samplerate:%d (gvahand:%d) offset_start_samples:%d\n\n" ,gpp->original_speed ,l_referedClipSpeed ,gpp->audio_frame_offset ,l_samples ,l_samplerate ,gpp->gvahand->samplerate ,offset_start_samples ); } #endif if(l_referedClipSpeed > 0) { /* use moidfied samplerate if video is not played at original speed */ flt_samplerate = l_samplerate * gpp->speed / l_referedClipSpeed; } else { flt_samplerate = l_samplerate; } /* check if offset and rate is within playable limits */ if((offset_start_samples >= 0) && ((gdouble)offset_start_samples < ((gdouble)l_samples - 1024.0)) && (flt_samplerate >= GAP_PLAYER_MAIN_MIN_SAMPLERATE) ) { UInt32 lu_samplerate; p_audio_init(gpp); /* tell ausioserver to go standby for this audiofile */ gpp->audio_required_samplerate = (guint32)flt_samplerate; if(flt_samplerate > GAP_PLAYER_MAIN_MAX_SAMPLERATE) { lu_samplerate = (UInt32)GAP_PLAYER_MAIN_MAX_SAMPLERATE; /* required samplerate is faster than highest possible audioplayback speed * (the audioplayback will be played but runs out of sync and cant follow) */ } else { lu_samplerate = (UInt32)flt_samplerate; } apcl_sampling_rate(lu_samplerate,0,p_audio_errfunc); apcl_start_sample((UInt32)offset_start_samples,0,p_audio_errfunc); apcl_play(0,p_audio_errfunc); /* Tell server to play */ apcl_volume(gpp->audio_volume, 0, p_audio_errfunc); gpp->audio_status = GAP_PLAYER_MAIN_AUSTAT_PLAYING; gpp->audio_resync = 0; } #endif return; } /* end p_audio_start_play */ /* ----------------------------- * p_audio_startup_server * ----------------------------- */ static void p_audio_startup_server(GapPlayerMainGlobalParams *gpp) { #ifdef GAP_ENABLE_AUDIO_SUPPORT const char *cp; gboolean wavplay_server_found; if (gap_debug) { printf("p_audio_startup_server\n"); } wavplay_server_found = FALSE; /* * Set environmental values for the wavplay audio server: */ /* check gimprc for the wavplay audio server: */ if ( (cp = gimp_gimprc_query("wavplay_prog")) != NULL ) { env_WAVPLAYPATH = g_strdup(cp); /* Environment overrides compiled in default for WAVPLAYPATH */ if(g_file_test (env_WAVPLAYPATH, G_FILE_TEST_IS_EXECUTABLE) ) { wavplay_server_found = TRUE; } else { g_message(_("WARNING: your gimprc file configuration for the wavplay audio server\n" "does not point to an executable program\n" "the configured value for %s is: %s\n") , "wavplay_prog" , env_WAVPLAYPATH ); } } /* check environment variable for the wavplay audio server: */ if(!wavplay_server_found) { if ( (cp = g_getenv("WAVPLAYPATH")) != NULL ) { env_WAVPLAYPATH = g_strdup(cp); /* Environment overrides compiled in default for WAVPLAYPATH */ if(g_file_test (env_WAVPLAYPATH, G_FILE_TEST_IS_EXECUTABLE) ) { wavplay_server_found = TRUE; } else { g_message(_("WARNING: the environment variable %s\n" "does not point to an executable program\n" "the current value is: %s\n") , "WAVPLAYPATH" , env_WAVPLAYPATH ); } } } if(!wavplay_server_found) { if ( (cp = g_getenv("PATH")) != NULL ) { env_WAVPLAYPATH = gap_lib_searchpath_for_exefile("wavplay", cp); if(env_WAVPLAYPATH) { wavplay_server_found = TRUE; } } } if ( (cp = g_getenv("AUDIODEV")) != NULL ) env_AUDIODEV = g_strdup(cp); /* Environment overrides compiled in default for AUDIODEV */ if ( (cp = g_getenv("AUDIOLCK")) == NULL || sscanf(cp,"%lX",&env_AUDIOLCK) != 1 ) env_AUDIOLCK = AUDIOLCK; /* Use compiled in default, if no environment, or its bad */ if(wavplay_server_found) { p_audio_filename_changed(gpp); gpp->audio_enable = TRUE; } else { gpp->audio_enable = FALSE; g_message(_("No audiosupport available\n" "the audioserver executable file '%s' was not found.\n" "If you have installed '%s'\n" "you should add the installation dir to your PATH\n" "or set environment variable %s to the name of the executable\n" "before you start GIMP") , "wavplay" , "wavplay 1.4" , "WAVPLAYPATH" ); } #endif return; } /* end p_audio_startup_server */ /* ------------------------------ * p_mtrace_image_alive * ------------------------------ * Check if the mtrace_image_id is valid (== belongs to an existing image) * if INVALID (there was no mlayer image or it was closed by the user) then * create a new mtrace_image * if valid then deliver width and height * * OUT: *mtrace_width *mtrace_height .. the size of the mtrace image */ static void p_mtrace_image_alive(GapPlayerMainGlobalParams *gpp , gint32 width , gint32 height , gint32 *mtrace_width , gint32 *mtrace_height ) { GimpImageBaseType image_type; image_type = GIMP_RGB; if(gpp->image_id >= 0) { image_type = gimp_image_base_type(gpp->image_id); } if(gap_image_is_alive(gpp->mtrace_image_id)) { *mtrace_width = gimp_image_width(gpp->mtrace_image_id); *mtrace_height = gimp_image_height(gpp->mtrace_image_id); } else { if(gpp->mtrace_mode == GAP_PLAYER_MTRACE_IMG_SIZE) { *mtrace_width = width; *mtrace_height = height; } else { *mtrace_width = gpp->pv_width; *mtrace_height = gpp->pv_height; } gpp->mtrace_image_id = gimp_image_new( *mtrace_width , *mtrace_height , image_type ); #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* if there is an active videohandle * set image resolution according to * aspect_ratio of the videofile */ if(gpp->gvahand) { GVA_image_set_aspect(gpp->gvahand, gpp->mtrace_image_id); } #endif gimp_display_new(gpp->mtrace_image_id); } } /* end p_mtrace_image_alive */ /* ------------------------------ * 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 * to the mtrace image. * IMPORTANT: all visible layers of the input image are merged */ static void p_mtrace_image( GapPlayerMainGlobalParams *gpp ,gint32 image_id ) { gint32 width; gint32 height; gint32 mtrace_width; gint32 mtrace_height; gint32 src_layer_id; 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); height = MAX(gimp_image_height(image_id), 1); p_mtrace_image_alive(gpp ,width ,height , &mtrace_width , &mtrace_height ); src_layer_id = gap_image_merge_visible_layers(image_id, GIMP_CLIP_TO_IMAGE); dst_layer_id = gap_layer_copy_to_dest_image(gpp->mtrace_image_id /* the dest image */ , src_layer_id /* the layer to copy */ , 100.0 /* opacity */ , 0 /* NORMAL paintmode */ ,&l_src_offset_x ,&l_src_offset_y); gimp_image_add_layer(gpp->mtrace_image_id , dst_layer_id , 0 /* top of layerstack */ ); if((width != mtrace_width) || (height != mtrace_height)) { gimp_layer_scale(dst_layer_id, mtrace_width, mtrace_height, 0); l_src_offset_x = (gint32)(((gdouble)mtrace_width / (gdouble)width) * (gdouble)l_src_offset_x); 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; l_name = g_strdup_printf("frame_%06d (%dms)" ,(int)gpp->play_current_framenr ,(int)(1000 / gpp->speed) ); gimp_drawable_set_name(dst_layer_id, l_name); g_free(l_name); } gimp_displays_flush(); } } /* end p_mtrace_image */ /* ------------------------------ * p_mtrace_tmpbuf * ------------------------------ * add buffer as one composite layer * to the mtrace image. */ static void p_mtrace_tmpbuf( GapPlayerMainGlobalParams *gpp , guchar *th_data , gint32 th_width , gint32 th_height , gint32 th_bpp ) { gint32 mtrace_width; gint32 mtrace_height; gint32 dst_layer_id; if(gpp->mtrace_mode != GAP_PLAYER_MTRACE_OFF) { p_mtrace_image_alive(gpp ,th_width ,th_height , &mtrace_width , &mtrace_height ); dst_layer_id = gap_layer_new_from_buffer(gpp->mtrace_image_id , th_width , th_height , th_bpp , th_data ); gimp_image_add_layer(gpp->mtrace_image_id , dst_layer_id , 0 /* top of layerstack */ ); if(th_bpp == 3) { gimp_layer_add_alpha(dst_layer_id); } if((th_width != mtrace_width) || (th_height != mtrace_height)) { gimp_layer_scale(dst_layer_id, mtrace_width, mtrace_height, 0); } gimp_layer_set_offsets(dst_layer_id , 0 /* offset_x */ , 0 /* offset_y */ ); p_conditional_attach_dvref(gpp, dst_layer_id); { gchar *l_name; l_name = g_strdup_printf("thumb_%06d (%dms)" ,(int)gpp->play_current_framenr ,(int)(1000 / gpp->speed) ); gimp_drawable_set_name(dst_layer_id, l_name); g_free(l_name); } gimp_displays_flush(); } } /* end p_mtrace_tmpbuf */ /* ------------------------------ * p_mtrace_pixbuf * ------------------------------ * add buffer as one composite layer * to the mtrace image. */ static void p_mtrace_pixbuf( GapPlayerMainGlobalParams *gpp , GdkPixbuf *pixbuf ) { if(gpp->mtrace_mode != GAP_PLAYER_MTRACE_OFF) { if(pixbuf) { gint32 nchannels; gint32 rowstride; gint32 width; gint32 height; guchar *pix_data; width = gdk_pixbuf_get_width(pixbuf); height = gdk_pixbuf_get_height(pixbuf); nchannels = gdk_pixbuf_get_n_channels(pixbuf); pix_data = gdk_pixbuf_get_pixels(pixbuf); rowstride = gdk_pixbuf_get_rowstride(pixbuf); p_mtrace_tmpbuf(gpp , pix_data , width , height , nchannels ); } } } /* end p_mtrace_pixbuf */ /* ----------------------------- * p_printout_range * ----------------------------- * call fptr_set_range * if such a callback function for setting the framerange is available (!= NULL) * typically for the case where the player is called from storyboard dialog. * * Another optional functionality * prints the selected RANGE to stdout * (Line Formated for STORYBOARD_FILE processing) * * if the Player is in Storyboard mode * the printout is just a comment with range numbers */ static void p_printout_range(GapPlayerMainGlobalParams *gpp, gboolean inverse, gboolean printflag) { gint32 l_begin; gint32 l_end; l_begin = gpp->begin_frame; l_end = gpp->end_frame; if(inverse) { l_end = gpp->begin_frame; l_begin = gpp->end_frame; } if(gpp->ainfo_ptr == NULL) { return; } if(gpp->ainfo_ptr->basename == NULL) { return; } if(gpp->stb_ptr) { if(printflag) { printf("# storyboard %06d=frame_from %06d=frame_to normal 1=nloops\n" , (int)l_begin , (int)l_end ); } return; } if(printflag) { if(gpp->ainfo_ptr->ainfo_type == GAP_AINFO_MOVIE) { /* Storyboard command line for playback of GAP singleframe range */ printf("VID_PLAY_MOVIE 1=track \"%s\" %06d=frame_from %06d=frame_to normal 1=nloops %d=seltrack\n" , gpp->ainfo_ptr->old_filename , (int)l_begin , (int)l_end , (int)gpp->ainfo_ptr->seltrack ); } else { /* Storyboard command line for playback of GAP singleframe range */ printf("VID_PLAY_FRAMES 1=track \"%s\" %s %06d=frame_from %06d=frame_to normal 1=nloops\n" , gpp->ainfo_ptr->basename , &gpp->ainfo_ptr->extension[1] , (int)l_begin , (int)l_end ); } } /* callback function for adding range as cliplist */ if(gpp->fptr_set_range) { GapPlayerAddClip *plac_ptr; plac_ptr = g_new(GapPlayerAddClip, 1); if(plac_ptr) { plac_ptr->user_data_ptr = gpp->user_data_ptr; plac_ptr->ainfo_ptr = gpp->ainfo_ptr; plac_ptr->range_from = l_begin; plac_ptr->range_to = l_end; (*gpp->fptr_set_range)(plac_ptr); g_free(plac_ptr); } } } /* end p_printout_range */ /* -------------------------------- * p_update_ainfo_for_videofile * -------------------------------- * typical called after creation of a videoindex * to update the total_frames information * (that may have changed from the guess value to * an exact value when all frames were counted) */ static void p_update_ainfo_for_videofile(GapPlayerMainGlobalParams *gpp) { GapAnimInfo *ainfo_ptr; if(gpp == NULL) { return; } #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if(gap_debug) { printf("p_update_ainfo_for_videofile gpp->ainfo_ptr:%d gpp->gvahand:%d\n" , (int)gpp->ainfo_ptr , (int)gpp->gvahand ); } ainfo_ptr = gpp->ainfo_ptr; if ((ainfo_ptr == NULL) || (gpp->gvahand == NULL)) { return; } if(ainfo_ptr->ainfo_type == GAP_AINFO_MOVIE) { if(gpp->gvahand->all_frames_counted) { if(gap_debug) { printf("p_update_ainfo_for_videofile ainfo_ptr->frame_cnt:%d gpp->gvahand->total_frames:%d\n" , (int)ainfo_ptr->frame_cnt , (int)gpp->gvahand->total_frames ); } ainfo_ptr->frame_cnt = gpp->gvahand->total_frames; ainfo_ptr->last_frame_nr = gpp->gvahand->total_frames; } } #endif } /* end p_update_ainfo_for_videofile*/ /* -------------------------------- * p_alloc_ainfo_for_videofile * -------------------------------- * get anim information from filename for videofiles * return NULL if filename is not a supported videofile * if filename is a supported video * return anim information * and keep the used videohandle gpp->gvahand open * for the expected read access. */ static GapAnimInfo * p_alloc_ainfo_for_videofile(GapPlayerMainGlobalParams *gpp , char *filename , gint32 seltrack , gdouble delace , const char *preferred_decoder ) { GapAnimInfo *l_ainfo_ptr; l_ainfo_ptr = NULL; #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if(filename == NULL) { return (NULL); } if(!g_file_test(filename, G_FILE_TEST_EXISTS)) { if(gap_debug) { printf ("p_alloc_ainfo_for_videofile: file %s does not exist\n" , filename ); } return (NULL); } if(!gap_story_filename_is_videofile_by_ext(filename)) { if(gap_debug) { printf ("p_alloc_ainfo_for_videofile: file %s has no typical video extension\n" , filename ); } if(!gpp->force_open_as_video) { return (NULL); } } gpp->gva_lock = TRUE; p_close_videofile(gpp); p_open_videofile(gpp, filename, seltrack, delace, preferred_decoder); gpp->gva_lock = FALSE; if(gpp->gvahand == NULL) { if(gap_debug) { printf ("p_alloc_ainfo_for_videofile: file %s NO compatible Decoder available\n" , filename ); } return (NULL); } l_ainfo_ptr = (GapAnimInfo*)g_malloc(sizeof(GapAnimInfo)); if(l_ainfo_ptr == NULL) return(NULL); l_ainfo_ptr->basename = g_strdup(filename); l_ainfo_ptr->extension = gap_lib_alloc_extension(filename); l_ainfo_ptr->new_filename = NULL; l_ainfo_ptr->image_id = -1; l_ainfo_ptr->old_filename = g_strdup(filename); l_ainfo_ptr->ainfo_type = GAP_AINFO_MOVIE; l_ainfo_ptr->seltrack = seltrack; l_ainfo_ptr->delace = delace; l_ainfo_ptr->curr_frame_nr = 1; l_ainfo_ptr->first_frame_nr = 1; l_ainfo_ptr->frame_cnt = gpp->gvahand->total_frames; if(!gpp->gvahand->all_frames_counted) { /* frames are not counted yet, * and the total_frames information is just a guess * in this case we assume 2 times more frames */ l_ainfo_ptr->frame_cnt *= 2; } l_ainfo_ptr->last_frame_nr = l_ainfo_ptr->frame_cnt; l_ainfo_ptr->width = gpp->gvahand->width; l_ainfo_ptr->height = gpp->gvahand->height; gpp->original_speed = gpp->gvahand->framerate; #endif return(l_ainfo_ptr); } /* end p_alloc_ainfo_for_videofile */ /* ----------------------------- * p_reload_ainfo_ptr * ----------------------------- * get anim information from imagename or image_id * NO operation when Player is in storyboard mode * when called with a negative image_id * then assume that gpp->imagename refers to a videofile * and try to allocate anim info from videofile. */ static void p_reload_ainfo_ptr(GapPlayerMainGlobalParams *gpp, gint32 image_id) { gboolean l_hasImagename; gpp->image_id = image_id; l_hasImagename = FALSE; if(gpp->stb_ptr) { return; } if(gpp->ainfo_ptr) { gap_lib_free_ainfo(&gpp->ainfo_ptr); } if((image_id < 0) && (gpp->imagename)) { gpp->ainfo_ptr = p_alloc_ainfo_for_videofile(gpp ,gpp->imagename ,gpp->seltrack ,gpp->delace ,gpp->preferred_decoder ); if(gpp->ainfo_ptr) { return; } gpp->ainfo_ptr = gap_lib_alloc_ainfo_from_name(gpp->imagename, gpp->run_mode); l_hasImagename = TRUE; } else { char *imagename; imagename = gimp_image_get_filename(image_id); if (imagename) { l_hasImagename = TRUE; g_free(imagename); } /* normal mode using anim frames or single image */ gpp->ainfo_ptr = gap_lib_alloc_ainfo(gpp->image_id, gpp->run_mode); } if(gpp->ainfo_ptr == NULL) { return; } if (0 == gap_lib_dir_ainfo(gpp->ainfo_ptr)) { if(gpp->image_id >= 0) { gpp->ainfo_ptr->width = gimp_image_width(gpp->image_id); gpp->ainfo_ptr->height = gimp_image_height(gpp->image_id); } else { gpp->ainfo_ptr->width = gpp->imagewidth; gpp->ainfo_ptr->height = gpp->imageheight; } if((gpp->ainfo_ptr->frame_cnt != 0) && (l_hasImagename == TRUE)) { GapVinVideoInfo *vin_ptr; vin_ptr = gap_vin_get_all(gpp->ainfo_ptr->basename); gpp->onion_delete = FALSE; gpp->original_speed = 24.0; if(vin_ptr) { if(vin_ptr->framerate > 0.0) { gpp->original_speed = vin_ptr->framerate; } /* check if automatic onionskin layer removal is turned on */ if((vin_ptr->auto_delete_before_save) && (vin_ptr->onionskin_auto_enable)) { /* yes, in this case the player must show the active image * without onionskin layers */ gpp->onion_delete = TRUE; } } if(vin_ptr) { g_free(vin_ptr); } } else { /* player operates on a single image that is not a numbered frame * patch the ainfo structure */ if(gap_debug) { printf("p_reload_ainfo_ptr: player operates on a single image that is not a numbered frame\n"); printf("basename: %s\n", gpp->ainfo_ptr->basename ); printf("extension: %s\n", gpp->ainfo_ptr->extension ); } gpp->ainfo_ptr->curr_frame_nr = 1; gpp->ainfo_ptr->first_frame_nr = 1; gpp->ainfo_ptr->last_frame_nr = 1; gpp->original_speed = 24.0; } } } /* end p_reload_ainfo_ptr */ /* -------------------------------- * p_update_ainfo_dependent_widgets * -------------------------------- */ static void p_update_ainfo_dependent_widgets(GapPlayerMainGlobalParams *gpp) { gdouble l_lower; gdouble l_upper; gdouble l_value; if(gpp == NULL) { return; } if(gpp->ainfo_ptr == NULL) { return; } l_lower = (gdouble)gpp->ainfo_ptr->first_frame_nr; l_upper = (gdouble)gpp->ainfo_ptr->last_frame_nr; GTK_ADJUSTMENT(gpp->from_spinbutton_adj)->lower = l_lower; GTK_ADJUSTMENT(gpp->from_spinbutton_adj)->upper = l_upper; GTK_ADJUSTMENT(gpp->from_spinbutton_adj)->value = CLAMP(GTK_ADJUSTMENT(gpp->from_spinbutton_adj)->value ,l_lower, l_upper); gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->from_spinbutton_adj) , (gfloat)CLAMP(GTK_ADJUSTMENT(gpp->from_spinbutton_adj)->value, l_lower, l_upper) ); GTK_ADJUSTMENT(gpp->to_spinbutton_adj)->lower = l_lower; GTK_ADJUSTMENT(gpp->to_spinbutton_adj)->upper = l_upper; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->to_spinbutton_adj) , (gfloat) CLAMP(GTK_ADJUSTMENT(gpp->to_spinbutton_adj)->value, l_lower, l_upper) ); l_value = CLAMP(GTK_ADJUSTMENT(gpp->framenr_spinbutton_adj)->value, l_lower, l_upper); if(gap_debug) { printf("## tmp p_update_ainfo_dependent_widgets adj l_value:%.2f l_lower:%.2f l_upper:%.2f\n" ,(float)l_value ,(float)l_lower ,(float)l_upper ); } GTK_ADJUSTMENT(gpp->framenr_spinbutton_adj)->lower = l_lower; GTK_ADJUSTMENT(gpp->framenr_spinbutton_adj)->upper = l_upper; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->framenr_spinbutton_adj), l_value); } /* end p_update_ainfo_dependent_widgets */ /* ------------------------------------ * p_find_master_image_id * ------------------------------------ * try to find the master image by filename * matching at basename and extension part * * return positive image_id on success * return -1 if nothing found */ static gint32 p_find_master_image_id(GapPlayerMainGlobalParams *gpp) { gint32 *images; gint nimages; gint l_idi; gint l_baselen; gint l_extlen; gint32 l_found_image_id; if(gpp->ainfo_ptr == NULL) { return -1; } if(gpp->ainfo_ptr->basename == NULL) { return -1; } if(gap_debug) { printf("p_find_master_image_id: image_id %s %s START\n" , gpp->ainfo_ptr->basename , gpp->ainfo_ptr->extension ); } l_baselen = strlen(gpp->ainfo_ptr->basename); l_extlen = strlen(gpp->ainfo_ptr->extension); images = gimp_image_list(&nimages); l_idi = nimages -1; l_found_image_id = -1; while((l_idi >= 0) && images) { gchar *l_filename; l_filename = gimp_image_get_filename(images[l_idi]); if(l_filename) { if(gap_debug) printf("p_find_master_image_id: comare with %s\n", l_filename); if(strncmp(l_filename, gpp->ainfo_ptr->basename, l_baselen) == 0) { gint l_len; l_len = strlen(l_filename); if(l_len > l_extlen) { if(strncmp(&l_filename[l_len - l_extlen], gpp->ainfo_ptr->extension, l_extlen) == 0) { l_found_image_id = images[l_idi]; break; } } } g_free(l_filename); } l_idi--; } if(images) g_free(images); return l_found_image_id; } /* end p_find_master_image_id */ /* ------------------------------------ * p_keep_track_of_active_master_image * ------------------------------------ * Note: in storyboard mode there is no active master image * just return without any action in that case. */ static void p_keep_track_of_active_master_image(GapPlayerMainGlobalParams *gpp) { p_stop_playback(gpp); if(gpp->stb_ptr) { return; } if(gpp->imagename) { return; } gpp->image_id = p_find_master_image_id(gpp); if(gpp->image_id >= 0) { p_reload_ainfo_ptr(gpp, gpp->image_id); p_update_ainfo_dependent_widgets(gpp); } else { /* cannot find the master image, so quit immediate */ printf("p_keep_track_of_active_master_image: Master Image not found (may have been closed)\n"); printf("Exiting Playback\n"); on_shell_window_destroy(NULL, gpp); } } /* end p_keep_track_of_active_master_image */ /* ----------------------------- * on_help_button_clicked * ----------------------------- */ static void on_help_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp) { if(gpp) { if(gpp->help_id) { gimp_standard_help_func(gpp->help_id, gpp->shell_window); } } } /* end on_help_button_clicked */ /* ----------------------------- * p_check_for_active_image * ----------------------------- * check if framenr is the the active image * (from where we were called at plug-in invocation time) * * this procedure also tries to keep track of changes * of the active master image_id outside this plug-in. * * (stepping to another frame, using other GAP plug-ins * changes the master image_id outside ...) */ gboolean p_check_for_active_image(GapPlayerMainGlobalParams *gpp, gint32 framenr) { if (gap_image_is_alive(gpp->image_id)) { if(framenr == gpp->ainfo_ptr->curr_frame_nr) { return(TRUE); } } else { p_keep_track_of_active_master_image(gpp); if(framenr == gpp->ainfo_ptr->curr_frame_nr) { return(TRUE); } return (FALSE); } return (FALSE); } /* end p_check_for_active_image */ /* ----------------------------- * p_update_pviewsize * ----------------------------- * set preview size nd size spinbutton */ static void p_update_pviewsize(GapPlayerMainGlobalParams *gpp) { gint32 l_width; gint32 l_height; l_width = gpp->ainfo_ptr->width; l_height = gpp->ainfo_ptr->height; if(gpp->aspect_ratio > 0.0) { gdouble asp_height; /* force playback at specified aspect ratio */ asp_height = (gdouble)(l_width) / gpp->aspect_ratio; l_height = (gint32)asp_height; } /* * Resize the greater one of dwidth and dheight to PREVIEW_SIZE */ if ( l_width > l_height ) { /* landscape */ gpp->pv_height = l_height * gpp->pv_pixelsize / l_width; gpp->pv_height = MAX (1, gpp->pv_height); gpp->pv_width = gpp->pv_pixelsize; } else { /* portrait */ gpp->pv_width = l_width * gpp->pv_pixelsize / l_height; gpp->pv_width = MAX(1, gpp->pv_width); gpp->pv_height = gpp->pv_pixelsize; } if(gpp->pv_pixelsize != (gint32)GTK_ADJUSTMENT(gpp->size_spinbutton_adj)->value) { gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->size_spinbutton_adj) , (gfloat)gpp->pv_pixelsize ); } gpp->pv_pixelsize = (gint32)GTK_ADJUSTMENT(gpp->size_spinbutton_adj)->value; gap_pview_set_size(gpp->pv_ptr , gpp->pv_width , gpp->pv_height , MAX(GAP_PLAYER_CHECK_SIZE, (gpp->pv_pixelsize / 16)) ); } /* end p_update_pviewsize */ /* ----------------------------- * p_set_frame_with_name_label * ----------------------------- * set labeltext as filename (or basename) with type indicator prefix */ static void p_set_frame_with_name_label(GapPlayerMainGlobalParams *gpp) { #define MAX_CHARS 60 char *frame_title; frame_title = NULL; if(gpp->stb_ptr) { gchar *l_prefix; l_prefix = NULL; if(gpp->stb_in_track > 0) { /* filename prefix shortcut for storyboard single track playback for specified track number */ l_prefix = g_strdup_printf(_("STB:[%d]"), (int)gpp->stb_in_track); } else { /* filename prefix shortcut for storyboard in composite video playback mode */ l_prefix = g_strdup(_("STB:")); } /* shortname prefix to indicate that displayed filename is from type storyboard file */ frame_title = gap_base_shorten_filename(l_prefix /* prefix short for storyboard */ ,gpp->stb_ptr->storyboardfile /* filenamepart */ ,NULL /* suffix */ ,MAX_CHARS ); g_free(l_prefix); } else { if((gpp->imagename) && (gpp->ainfo_ptr)) { if(gpp->ainfo_ptr->ainfo_type == GAP_AINFO_MOVIE) { /* shortname prefix to indicate that displayed filename is a single videofile */ frame_title = gap_base_shorten_filename(_("VIDEO:") /* prefix short for storyboard */ ,gpp->ainfo_ptr->basename /* filenamepart */ ,NULL /* suffix */ ,MAX_CHARS ); } } } if(frame_title == NULL) { /* shortname prefix to indicate that displayed filename is basename of the frames */ frame_title = gap_base_shorten_filename(_("FRAMES:") /* prefix short for storyboard */ ,gpp->ainfo_ptr->basename /* filenamepart */ ,NULL /* suffix */ ,MAX_CHARS ); } gtk_frame_set_label (GTK_FRAME (gpp->frame_with_name) , frame_title); g_free(frame_title); } /* end p_set_frame_with_name_label */ /* ----------------------------- * p_update_position_widgets * ----------------------------- * set position spinbutton and time entry */ static void p_update_position_widgets(GapPlayerMainGlobalParams *gpp) { static gchar time_txt[12]; if((gint32)GTK_ADJUSTMENT(gpp->framenr_spinbutton_adj)->value != gpp->play_current_framenr) { gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->framenr_spinbutton_adj) , (gfloat)gpp->play_current_framenr ); } gap_timeconv_framenr_to_timestr( (gpp->play_current_framenr - gpp->ainfo_ptr->first_frame_nr) , gpp->original_speed , time_txt , sizeof(time_txt) ); gtk_label_set_text ( GTK_LABEL(gpp->timepos_label), time_txt); } /* end p_update_position_widgets */ /* ----------------------------- * p_start_playback_timer * ----------------------------- * this procedure sets up the delay * until next timercall. */ static void p_start_playback_timer(GapPlayerMainGlobalParams *gpp) { gint32 delay_until_next_timercall_millisec; gdouble cycle_time_secs; cycle_time_secs = 1.0 / MAX(gpp->speed, 1.0); if(cycle_time_secs != gpp->cycle_time_secs) { /* playback speed has changed while playing * reset timing (restart playing with new speed on the fly) * use a half delay, as guess after speed has changed */ gpp->rest_secs = cycle_time_secs / 2.0; gpp->delay_secs = 0.0; /* reset the absolute delay (since start or speedchange) */ gpp->framecnt = 0.0; g_timer_start(gpp->gtimer); /* (re)start timer at start of playback (== reset to 0) */ } else { if(gpp->rest_secs < 0) { /* use a minimal delay, bacause we are LATE */; gpp->rest_secs = 10.0 / 1000.0; gpp->framecnt = 0.0; g_timer_start(gpp->gtimer); /* (re)start timer at start of playback (== reset to 0) */ } } gpp->cycle_time_secs = cycle_time_secs; delay_until_next_timercall_millisec = (gpp->rest_secs) * 1000.0; /*if(gap_debug) printf("p_start_playback_timer: START delay_until_next_timercall_millisec:%d\n", (int)delay_until_next_timercall_millisec);*/ gpp->play_is_active = TRUE; gpp->play_timertag = (gint32) g_timeout_add(delay_until_next_timercall_millisec, (GtkFunction)on_timer_playback, gpp); } /* end p_start_playback_timer */ /* ----------------------------- * p_initial_start_playback_timer * ----------------------------- */ static void p_initial_start_playback_timer(GapPlayerMainGlobalParams *gpp) { p_audio_stop(gpp); /* stop old playback if there is any */ gpp->audio_resync = 0; gpp->cycle_time_secs = 1.0 / MAX(gpp->speed, 1.0); gpp->rest_secs = 10.0 / 1000.0; /* use minimal delay for the 1st call */ gpp->delay_secs = 0.0; /* absolute delay (for display) */ gpp->framecnt = 0.0; gpp->go_job_framenr = -1; /* pending timer_go_job gets useless, since we start playback now */ gtk_label_set_text ( GTK_LABEL(gpp->status_label), _("Playing")); g_timer_start(gpp->gtimer); /* (re)start timer at start of playback (== reset to 0) */ p_start_playback_timer(gpp); p_audio_start_play(gpp); } /* end p_initial_start_playback_timer */ /* ----------------------------- * p_remove_play_timer * ----------------------------- */ static void p_remove_play_timer(GapPlayerMainGlobalParams *gpp) { /*if(gap_debug) printf("p_remove_play_timer\n");*/ if(gpp->play_timertag >= 0) { g_source_remove(gpp->play_timertag); } gpp->play_timertag = -1; } /* end p_remove_play_timer */ /* ----------------------------- * p_stop_playback * ----------------------------- */ static void p_stop_playback(GapPlayerMainGlobalParams *gpp) { /* if(gap_debug) printf("p_stop_playback\n"); */ p_remove_play_timer(gpp); gpp->mtrace_mode = GAP_PLAYER_MTRACE_OFF; gpp->request_cancel_video_api = TRUE; gpp->play_is_active = FALSE; gpp->pingpong_count = 0; gtk_label_set_text ( GTK_LABEL(gpp->status_label), _("Ready")); p_check_tooltips(); p_audio_stop(gpp); gpp->audio_resync = 0; } /* end p_stop_playback */ /* --------------------------------- * on_cancel_vindex_button_clicked * --------------------------------- */ static void on_cancel_vindex_button_clicked (GtkObject *object, GapPlayerMainGlobalParams *gpp) { if(gpp) { gpp->cancel_video_api = TRUE; gpp->request_cancel_video_api = FALSE; } } /* end on_cancel_vindex_button_clicked */ /* ----------------------------------------- * on_audio_auto_offset_checkbutton_toggled * ----------------------------------------- */ static void on_audio_auto_offset_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if (togglebutton->active) { gpp->audio_auto_offset_by_framenr = TRUE; } else { gpp->audio_auto_offset_by_framenr = FALSE; gpp->audio_resync = 0; } p_audio_resync(gpp); } /* end on_audio_auto_offset_checkbutton_toggled */ /* ----------------------------------------- * p_msg_progress_bar_audio * ----------------------------------------- */ static void p_msg_progress_bar_audio(GapPlayerMainGlobalParams *gpp, const char *msg) { if (gpp->progress_bar_audio) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(gpp->progress_bar_audio), msg); } } /* end p_msg_progress_bar_audio */ /* ----------------------------------------- * p_reset_progress_bar_audio * ----------------------------------------- */ static void p_reset_progress_bar_audio(GapPlayerMainGlobalParams *gpp) { if (gpp->progress_bar_audio) { /* reset audio extract progress when done */ gtk_progress_bar_set_text(GTK_PROGRESS_BAR(gpp->progress_bar_audio)," "); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gpp->progress_bar_audio), 0.0); } } /* end p_reset_progress_bar_audio */ /* ----------------------------------------- * on_audio_otone_extract_button_clicked * ----------------------------------------- */ static void on_audio_otone_extract_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp) { #ifdef GAP_ENABLE_AUDIO_SUPPORT #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT gboolean l_otone_is_up_to_date; gint32 l_extract_audiotrack; gint32 l_begin_frame_nr; gint32 l_end_frame_nr; char *l_audiofilename; char *l_audiofilename_cancel; if(gpp == NULL) { return; } if(gpp->gva_lock) { /* do not attempt displaying frames while we are inside * of p_alloc_ainfo_for_videofile procedure */ return; } if(gpp->gvahand == NULL) { if(gpp->ainfo_ptr->ainfo_type == GAP_AINFO_MOVIE) { p_open_videofile(gpp , gpp->ainfo_ptr->old_filename , gpp->ainfo_ptr->seltrack , gpp->ainfo_ptr->delace , gpp->preferred_decoder ); } } if((gpp->gvahand == NULL) || (gpp->gva_videofile == NULL)) { /* no videofile or no videohandle available */ return; } if(gpp->gvahand->audio_cannels <= 0) { /* video has no audiotracks */ return; } p_reset_progress_bar_audio(gpp); p_msg_progress_bar_audio(gpp, _("cheking audiotrack")); l_extract_audiotrack = CLAMP(GTK_ADJUSTMENT(gpp->audio_otone_atrack_spinbutton_adj)->value , 1 , gpp->gvahand->audio_cannels ); /* build otone workfile name (set gpp->audio_otone_wavfile ) */ l_audiofilename = p_build_otone_audiofilename(gpp->gva_videofile , l_extract_audiotrack , NULL /* no special suffix used here */ ); l_audiofilename_cancel = p_build_otone_audiofilename(gpp->gva_videofile , l_extract_audiotrack , ".incomplete" ); l_otone_is_up_to_date = p_check_otone_workfile_up_to_date(gpp->gva_videofile, l_audiofilename, l_extract_audiotrack); if (l_otone_is_up_to_date == TRUE) { p_msg_progress_bar_audio(gpp, _("extracted audio is up to date")); } else { gdouble l_dbl_total_frames; l_begin_frame_nr = 1; l_end_frame_nr = gpp->gvahand->total_frames; l_dbl_total_frames = (gdouble)gpp->gvahand->total_frames; p_msg_progress_bar_audio(gpp, _("extracting audio")); if(g_file_test(l_audiofilename, G_FILE_TEST_EXISTS)) { g_remove(l_audiofilename); } if(g_file_test(l_audiofilename_cancel, G_FILE_TEST_EXISTS)) { g_remove(l_audiofilename_cancel); } gpp->cancel_video_api = FALSE; gpp->request_cancel_video_api = FALSE; /* extract audio segment (in full length) to otone workfile */ gap_audio_extract_from_videofile(gpp->gva_videofile , l_audiofilename , l_extract_audiotrack , gpp->preferred_decoder /* preferred_decoder */ , TRUE /* exact_seek */ , GVA_UPOS_FRAMES /* pos_unit */ , l_begin_frame_nr , l_dbl_total_frames /* extracted_frames */ , l_dbl_total_frames /* expected_frames */ , TRUE /* do_progress */ , gpp->progress_bar_audio /* GtkWidget *progressBar using NULL for gimp_progress */ , p_vid_progress_callback /* fptr_progress_callback */ , gpp /* user_data */ ); if (gpp->cancel_video_api == TRUE) { p_msg_progress_bar_audio(gpp, _("Audio Extract CANCELLED")); } else { /* reset audio extract progress when successfully done */ p_reset_progress_bar_audio(gpp); } if(!g_file_test(l_audiofilename, G_FILE_TEST_EXISTS)) { p_msg_progress_bar_audio(gpp, _("Audio Extract FAILED")); g_message(_("Extract of audiotrack failed on videofile: %s"), gpp->gva_videofile); goto cleanup; } else { gint32 l_audiofile_size; l_audiofile_size = gap_file_get_filesize(l_audiofilename); if (l_audiofile_size < 1) { p_msg_progress_bar_audio(gpp, _("Audio Extract FAILED")); g_message(_("Extract of audiotrack failed on videofile: %s"), gpp->gva_videofile); goto cleanup; } if (gpp->cancel_video_api == TRUE) { /* due to cancel the extracted audiofile is not complete * Therefore rename with suffix "incomplete" */ if (strcmp(l_audiofilename_cancel, l_audiofilename) != 0) { g_rename(l_audiofilename, l_audiofilename_cancel); g_free(l_audiofilename); l_audiofilename = l_audiofilename_cancel; l_audiofilename_cancel = NULL; } } } } gpp->audio_auto_offset_by_framenr = TRUE; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gpp->audio_auto_offset_by_framenr_checkbutton), gpp->audio_auto_offset_by_framenr); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gpp->audio_enable_checkbutton), TRUE); /* before the gtk_entry_set_text call, already set the gpp->audio_filename * explicite to the new name l_audiofilename * (this fakes "name has not changed" and prevents the callback * on_audio_filename_entry_changed from resetting the progress_bar_audio message * that shall be kept until the user enters the audiofilename manually) * */ g_snprintf(gpp->audio_filename, sizeof(gpp->audio_filename), "%s" , l_audiofilename ); gtk_entry_set_text(GTK_ENTRY(gpp->audio_filename_entry), l_audiofilename); p_audio_filename_changed (gpp); cleanup: gpp->cancel_video_api = FALSE; if(l_audiofilename) { g_free(l_audiofilename); } if(l_audiofilename_cancel) { g_free(l_audiofilename_cancel);} #endif /* GAP_ENABLE_VIDEOAPI_SUPPORT */ #endif /* GAP_ENABLE_VIDEOAPI_SUPPORT */ } /* end on_audio_otone_extract_button_clicked */ /* ---------------------------------------- * on_audio_otone_atrack_spinbutton_changed * ---------------------------------------- */ static void on_audio_otone_atrack_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if(gpp->audio_otone_atrack != (gdouble)GTK_ADJUSTMENT(gpp->audio_otone_atrack_spinbutton_adj)->value) { gpp->audio_otone_atrack = (gdouble)GTK_ADJUSTMENT(gpp->audio_otone_atrack_spinbutton_adj)->value; #ifdef GAP_ENABLE_AUDIO_SUPPORT p_audio_stop(gpp); #endif } } /* end on_audio_otone_atrack_spinbutton_changed */ /* -------------------------------- * p_vid_progress_callback * -------------------------------- * this callback is used while searching videoframes * return: TRUE: cancel videoapi immediate * FALSE: continue */ static gboolean p_vid_progress_callback(gdouble progress ,gpointer user_data ) { GapPlayerMainGlobalParams *gpp; gpp = (GapPlayerMainGlobalParams *)user_data; if(gpp == NULL) { if(gap_debug) { printf("PLAYER: gpp == NULL p_vid_progress_callback CANCEL == true\n"); } return (TRUE); } if(gpp->progress_bar == NULL) { if(gap_debug) { printf("PLAYER: gpp->progress_bar == NULL p_vid_progress_callback CANCEL == trUE\n"); } return (TRUE); } gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gpp->progress_bar), progress); /* g_main_context_iteration makes sure that * gtk does refresh widgets, and react on events while the videoapi * is busy with searching for the next frame. */ while(g_main_context_iteration(NULL, FALSE)); /* if vthe long running videoindex creation is running * cancel is done only explicite when the cancel_vindex_button is clicked. */ if(!gpp->vindex_creation_is_running) { /* no videoindex creation is running * (in most cases we are in a seek to frame operation at this point) * in this case we do cancel immedate on request. * request_cancel_video_api is set on most user actions * on the player widgets when he wants positioning or start/stop playing */ gpp->cancel_video_api = gpp->request_cancel_video_api; } if(gpp->cancel_video_api) { if(gap_debug) { printf("PLAYER: cancel_video_api is TRUE p_vid_progress_callback CANCEL == TRUE\n"); } return (TRUE); /* cancel video api if playback was stopped */ } return(FALSE); /* continue with video API */ } /* end p_vid_progress_callback */ /* -------------------------------- * p_close_videofile * -------------------------------- */ static void p_close_videofile(GapPlayerMainGlobalParams *gpp) { #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if(gpp->gvahand) { if(gpp->gva_videofile) g_free(gpp->gva_videofile); GVA_close(gpp->gvahand); gpp->gvahand = NULL; gpp->gva_videofile = NULL; } #endif } /* end p_close_videofile */ /* -------------------------------- * p_reopen_videofile * -------------------------------- */ static void p_reopen_videofile(GapPlayerMainGlobalParams *gpp , char *filename , gint32 seltrack , gdouble delace , const char *preferred_decoder ) { const char *l_preferred_decoder; #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT p_close_videofile(gpp); /* use global preferred_decoder setting per default */ l_preferred_decoder = gpp->preferred_decoder; if(preferred_decoder) { if(*preferred_decoder != '\0') { /* use element specific preferred_decoder if available */ l_preferred_decoder = preferred_decoder; } } /* * printf("PLAYER: open START\n"); * if(l_preferred_decoder) * { * printf("PLAYER: (decoder:%s)\n", l_preferred_decoder); * } */ gpp->gvahand = GVA_open_read_pref(filename , seltrack , 1 /* aud_track */ , l_preferred_decoder , FALSE /* use MMX if available (disable_mmx == FALSE) */ ); /*printf("PLAYER: open gpp->gvahand:%d\n", (int)gpp->gvahand);*/ if(gpp->gvahand) { gpp->gva_videofile = g_strdup(filename); /* gpp->gvahand->emulate_seek = TRUE; */ gpp->gvahand->do_gimp_progress = FALSE; gpp->gvahand->progress_cb_user_data = gpp; gpp->gvahand->fptr_progress_callback = p_vid_progress_callback; if(gap_debug) { printf("## p_reopen_videofile gpp->gvahand->total_frames:%d\n" ,(int)gpp->gvahand->total_frames ); } /* printf("PLAYER: open fptr_progress_callback FPTR:%d\n" * , (int)gpp->gvahand->fptr_progress_callback); */ /* set decoder name as progress idle text */ { t_GVA_DecoderElem *dec_elem; if(gpp->progress_bar_idle_txt) { g_free(gpp->progress_bar_idle_txt); } dec_elem = (t_GVA_DecoderElem *)gpp->gvahand->dec_elem; if(dec_elem->decoder_name) { gpp->progress_bar_idle_txt = g_strdup(dec_elem->decoder_name); } else { gpp->progress_bar_idle_txt = g_strdup(" "); } } } #endif } /* end p_reopen_videofile */ /* -------------------------------- * p_open_videofile * -------------------------------- * open videofile handle * with checks for video index creation. * in case where video index creation is recommanded * this is done after asking the user for permission. */ static void p_open_videofile(GapPlayerMainGlobalParams *gpp , char *filename , gint32 seltrack , gdouble delace , const char *preferred_decoder ) { char *vindex_file; gboolean l_have_valid_vindex; l_have_valid_vindex = FALSE; #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT p_reopen_videofile(gpp, filename, seltrack, delace, preferred_decoder); vindex_file = NULL; if(gpp->gvahand) { /* set decoder name as progress idle text */ { t_GVA_DecoderElem *dec_elem; dec_elem = (t_GVA_DecoderElem *)gpp->gvahand->dec_elem; if(dec_elem->decoder_name) { vindex_file = GVA_build_videoindex_filename(gpp->gva_videofile ,1 /* track */ ,dec_elem->decoder_name ); } } if(gpp->gvahand->vindex) { if(gpp->gvahand->vindex->total_frames > 0) { l_have_valid_vindex = TRUE; } } if((l_have_valid_vindex == FALSE) &&(gpp->startup == FALSE)) { gboolean vindex_permission; t_GVA_SeekSupport seekSupp; gpp->cancel_video_api = FALSE; gpp->request_cancel_video_api = FALSE; if(gpp->progress_bar) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(gpp->progress_bar), _("seek-selftest")); } seekSupp = GVA_check_seek_support(gpp->gvahand); /* check for permission to create a videoindex file */ vindex_permission = gap_arr_create_vindex_permission(gpp->gva_videofile , vindex_file , (gint32)seekSupp ); if(vindex_permission) { /* create video index * (dont do that while we are in startup * because the shell window and progress_bar widget and many other things * are not set up yet and this long running operation * would be done without any visible sign) */ gpp->cancel_video_api = FALSE; gpp->request_cancel_video_api = FALSE; if(gpp->progress_bar) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(gpp->progress_bar), _("Creating Index")); } gpp->gvahand->create_vindex = TRUE; /* while videoindex creation show cancel button and hide play/stop buttons */ gtk_widget_hide (gpp->play_n_stop_hbox); gtk_widget_show (gpp->cancel_vindex_button); /* printf("PLAYER: open before GVA_count_frames\n"); */ gpp->vindex_creation_is_running = TRUE; GVA_count_frames(gpp->gvahand); gpp->vindex_creation_is_running = FALSE; /* printf("PLAYER: open after GVA_count_frames\n"); */ gtk_widget_hide (gpp->cancel_vindex_button); gtk_widget_show (gpp->play_n_stop_hbox); if(!gpp->cancel_video_api) { if(gpp->gvahand->vindex != NULL) { p_update_ainfo_for_videofile(gpp); p_update_ainfo_dependent_widgets(gpp); p_reopen_videofile(gpp, filename, seltrack, delace, preferred_decoder); } else { g_message(_("No videoindex available. " "Access is limited to (slow) sequential read " "on file: %s") , gpp->gvahand->filename ); } } } } /* GVA_debug_print_videoindex(gpp->gvahand); */ if(vindex_file) { g_free(vindex_file); } } /* printf("PLAYER: open END\n"); */ #endif } /* end p_open_videofile */ /* ----------------------------- * p_fetch_videoframe * ----------------------------- */ static guchar * p_fetch_videoframe(GapPlayerMainGlobalParams *gpp , char *gva_videofile , gint32 framenumber , gint32 rangesize , gint32 seltrack , gdouble delace , const char *preferred_decoder , gint32 *th_bpp , gint32 *th_width , gint32 *th_height ) { guchar *th_data; th_data = NULL; #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if(gpp->gva_lock) { return(NULL); } gpp->gva_lock = TRUE; if((gpp->gva_videofile) && (gpp->gvahand)) { if((strcmp(gpp->gva_videofile, gva_videofile) != 0) ||(seltrack != (gpp->gvahand->vid_track+1))) { //printf(" VIDFETCH (..) CALL p_close_videofile\n"); //printf(" VIDFETCH (..) gpp->gva_videofile: %s\n", gpp->gva_videofile); //printf(" VIDFETCH (..) gpp->gvahand->vid_track: %d\n", (int)gpp->gvahand->vid_track); //printf(" VIDFETCH (..) gva_videofile: %s\n", gva_videofile); //printf(" VIDFETCH (..) seltrack: %d\n", (int)seltrack); p_close_videofile(gpp); } } //printf(" VIDFETCH (0) gpp->gvahand: %d framenumber:%06d\n", (int)gpp->gvahand, (int)framenumber); if(gpp->gvahand == NULL) { p_open_videofile(gpp, gva_videofile, seltrack, delace, preferred_decoder); } if(gpp->gvahand) { gint32 l_deinterlace; gdouble l_threshold; gboolean do_scale; gint32 fcache_size; if(gpp->progress_bar) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(gpp->progress_bar), _("Videoseek")); } //printf(" VIDFETCH (3) gimprc: FCACHE SIZE: %d\n", (int)gpp->gvahand->fcache.frame_cache_size); if(global_max_vid_frames_to_keep_cached < 1) { char *value_string; value_string = gimp_gimprc_query("video-max-frames-keep-cached"); if(value_string) { //printf(" VIDFETCH (4) gimprc: value_string: %s\n", value_string); global_max_vid_frames_to_keep_cached = atol(value_string); } if(global_max_vid_frames_to_keep_cached < 1) { global_max_vid_frames_to_keep_cached = GAP_PLAYER_VID_FRAMES_TO_KEEP_CACHED; } } fcache_size = CLAMP(rangesize, 1, global_max_vid_frames_to_keep_cached); if(fcache_size > gpp->gvahand->fcache.frame_cache_size) { //printf(" VIDFETCH (5) gimprc: FCACHE_MAX:%d fcache_size:%d rangesize:%d\n" // , (int)global_max_vid_frames_to_keep_cached // , (int)fcache_size // , (int)rangesize // ); GVA_set_fcache_size(gpp->gvahand, fcache_size); } do_scale = TRUE; if(*th_width < 1) { *th_bpp = gpp->gvahand->frame_bpp; *th_width = gpp->gvahand->width; *th_height = gpp->gvahand->height; do_scale = FALSE; } /* split delace value: integer part is deinterlace mode, rest is threshold */ l_deinterlace = delace; l_threshold = delace - (gdouble)l_deinterlace; gpp->cancel_video_api = FALSE; gpp->request_cancel_video_api = FALSE; //printf(" VIDFETCH (6) current_seek_nr:%d current_frame_nr:%d\n", (int)gpp->gvahand->current_seek_nr ,(int)gpp->gvahand->current_frame_nr ); /* fetch the wanted framenr */ th_data = GVA_fetch_frame_to_buffer(gpp->gvahand , do_scale , framenumber , l_deinterlace , l_threshold , th_bpp , th_width , th_height ); //printf(" VIDFETCH (7) current_seek_nr:%d current_frame_nr:%d\n", (int)gpp->gvahand->current_seek_nr ,(int)gpp->gvahand->current_frame_nr ); if(gpp->progress_bar) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(gpp->progress_bar) ,gpp->progress_bar_idle_txt ); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gpp->progress_bar), 0.0); } } if(th_data) { /* throw away frame data because the fetch was cancelled * (an empty display is better than trash or the wrong frame) */ if(gpp->cancel_video_api) { 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 { /* one possible reason for a videframe fetch failure * could be an EOF in the video * (in this moment the GVA API might know the exactly * number of total_frames and we can set the limits in the player widget * if we are running on a single videofile -- but NOT in storyboard mode) */ if(!gpp->stb_ptr) { if((gpp->imagename) && (gpp->gvahand->all_frames_counted)) { if(gap_debug) { printf("p_fetch_videoframe CALL p_update_ainfo_dependent_widgets ainfo_ptr->frame_cnt:%d gpp->gvahand->total_frames:%d\n" , (int)gpp->ainfo_ptr->frame_cnt , (int)gpp->gvahand->total_frames ); } gpp->ainfo_ptr->frame_cnt = gpp->gvahand->total_frames; gpp->ainfo_ptr->last_frame_nr = gpp->gvahand->total_frames; p_update_ainfo_dependent_widgets(gpp); } } } gpp->gva_lock = FALSE; #endif return (th_data); } /* end p_fetch_videoframe */ /* ----------------------------- * p_init_video_playback_cache * ----------------------------- */ static void p_init_video_playback_cache(GapPlayerMainGlobalParams *gpp) { gpp->max_player_cache = gap_player_cache_get_gimprc_bytesize(); gap_player_cache_set_max_bytesize(gpp->max_player_cache); } /* end p_init_video_playback_cache */ /* ----------------------------- * p_init_layout_options * ----------------------------- */ static void p_init_layout_options(GapPlayerMainGlobalParams *gpp) { gchar *value_string; gpp->show_go_buttons = TRUE; gpp->show_position_scale = TRUE; value_string = gimp_gimprc_query("video_player_show_go_buttons"); if(value_string) { if ((*value_string == 'Y') || (*value_string == 'y')) { gpp->show_go_buttons = TRUE; } else { gpp->show_go_buttons = FALSE; } g_free(value_string); } value_string = gimp_gimprc_query("video_player_show_position_scale"); if(value_string) { if ((*value_string == 'Y') || (*value_string == 'y')) { gpp->show_position_scale = TRUE; } else { gpp->show_position_scale = FALSE; } g_free(value_string); } } /* end p_init_layout_options */ /* ------------------------------ * p_fetch_frame_via_cache * ------------------------------ * fetch any type of frame from the players cache. * returns NULL * - if no frame for the specified ckey was found in the cache, * - or if the player runs in MTRACE mode, * the parameters th_bpp, th_width, th_height are not changed * in case when NULL is the return value * If cached frame is returned, * the parameters th_bpp, th_width, th_height are set * according to the size of the cached frame */ static guchar * p_fetch_frame_via_cache(GapPlayerMainGlobalParams *gpp , const gchar *ckey , gint32 *th_bpp_ptr /* IN/OUT */ , gint32 *th_width_ptr /* IN/OUT */ , gint32 *th_height_ptr /* IN/OUT */ , gint32 *flip_status_ptr /* IN/OUT */ ) { GapPlayerCacheData* cdata; guchar *th_data; cdata = NULL; th_data = NULL; if (gpp->mtrace_mode == GAP_PLAYER_MTRACE_OFF) { cdata = gap_player_cache_lookup(ckey); } if(cdata != NULL) { th_data = gap_player_cache_decompress(cdata); *th_bpp_ptr = cdata->th_bpp; *th_width_ptr = cdata->th_width; *th_height_ptr = cdata->th_height; *flip_status_ptr = cdata->flip_status; } return (th_data); } /* end p_fetch_frame_via_cache */ /* ------------------------------ * p_fetch_videoframe_via_cache * ------------------------------ * fetch frame from the players cache * or alternatively from the videofile. * * No cache lookup is done if the player * runs in MTRACE mode, because the cache * holds a scaled copy, but MTRACE shall * deliver the original image quality and size. */ static guchar * p_fetch_videoframe_via_cache(GapPlayerMainGlobalParams *gpp , char *gva_videofile , gint32 framenumber , gint32 rangesize , gint32 seltrack , gdouble delace , const char *preferred_decoder , gint32 *th_bpp_ptr , gint32 *th_width_ptr , gint32 *th_height_ptr , gint32 *flip_status_ptr , const gchar *ckey ) { guchar *th_data; th_data = p_fetch_frame_via_cache(gpp , ckey , th_bpp_ptr , th_width_ptr , th_height_ptr , flip_status_ptr ); if(th_data == NULL) { th_data = p_fetch_videoframe(gpp , gva_videofile , framenumber , rangesize , seltrack , delace , preferred_decoder , th_bpp_ptr , th_width_ptr , th_height_ptr ); } return (th_data); } /* end p_fetch_videoframe_via_cache */ /* ------------------------------ * p_frame_chache_processing * ------------------------------ */ static void p_frame_chache_processing(GapPlayerMainGlobalParams *gpp , const gchar *ckey) { GapPlayerCacheData *cdata; guchar *th_data; gint32 th_size; gint32 th_width; gint32 th_height; gint32 th_bpp; gboolean th_has_alpha; if (gpp->max_player_cache <= 0) { /* chaching is turned OFF */ return; } if(gap_player_cache_lookup(ckey) != NULL) { /* frame with ckey is already cached */ return; } th_data = gap_pview_get_repaint_thdata(gpp->pv_ptr , &th_size , &th_width , &th_height , &th_bpp , &th_has_alpha ); if (th_data != NULL) { cdata = gap_player_cache_new_data(th_data , th_size , th_width , th_height , th_bpp , gpp->cache_compression , gpp->pv_ptr->flip_status ); if(cdata != NULL) { /* insert frame into cache */ gap_player_cache_insert(ckey, cdata); p_update_cache_status(gpp); } } } /* end p_frame_chache_processing */ /* -------------------------------- * p_close_composite_storyboard * -------------------------------- */ static void p_close_composite_storyboard(GapPlayerMainGlobalParams *gpp) { if(gpp->stb_ptr == NULL) { return; } gpp->stb_parttype = -1; gpp->stb_unique_id = -1; #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT if(gpp->stb_comp_vidhand) { gap_story_render_close_vid_handle(gpp->stb_comp_vidhand);; gpp->stb_comp_vidhand = NULL; } #endif } /* end p_close_composite_storyboard */ /* -------------------------------- * p_open_composite_storyboard * -------------------------------- */ static void p_open_composite_storyboard(GapPlayerMainGlobalParams *gpp) { gint32 l_total_framecount; if(gpp->stb_ptr == NULL) { return; } #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT p_close_composite_storyboard(gpp); gpp->stb_comp_vidhand = gap_story_render_open_vid_handle_from_stb (gpp->stb_ptr ,&l_total_framecount ); if(gap_debug) { printf("p_open_composite_storyboard: %s comp_vidhand:%d type:%d(%d) id:%d(%d)\n" ,gpp->stb_ptr->storyboardfile ,(int)gpp->stb_comp_vidhand ,(int)gpp->stb_ptr->stb_parttype ,(int)gpp->stb_parttype ,(int)gpp->stb_ptr->stb_unique_id ,(int)gpp->stb_unique_id ); gap_story_render_debug_print_framerange_list(gpp->stb_comp_vidhand->frn_list, -1); } if(gpp->stb_comp_vidhand) { /* store identifiers of the opened storyboard */ gpp->stb_parttype = gpp->stb_ptr->stb_parttype; gpp->stb_unique_id = gpp->stb_ptr->stb_unique_id; } #endif } /* end p_open_composite_storyboard */ /* ----------------------------- * p_fetch_composite_image * ----------------------------- */ static gint32 p_fetch_composite_image(GapPlayerMainGlobalParams *gpp , gint32 framenumber , gint32 width , gint32 height ) { gint32 composite_image_id; composite_image_id = -1; if(gpp->stb_ptr == NULL) { return (composite_image_id); } #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* (re)open if nothing already open or ident data has changed */ if ((gpp->stb_comp_vidhand == NULL) || (gpp->stb_parttype != gpp->stb_ptr->stb_parttype) || (gpp->stb_unique_id != gpp->stb_ptr->stb_unique_id)) { p_open_composite_storyboard(gpp); } if(gpp->stb_comp_vidhand) { gint32 l_layer_id; l_layer_id = -1; /* The storyboard render processor is used to fetch * the frame as rendered gimp image of desired size. * * NOTE:flip_request transformations are already rendered by * the storyboard render processor * therefore no changes to propagate to the players * pview widget */ composite_image_id = gap_story_render_fetch_composite_image( gpp->stb_comp_vidhand , framenumber , width , height , NULL /* filtermacro_file */ , &l_layer_id ); if(gap_debug) { printf("p_fetch_composite_image: comp_vidhand:%d composite_image_id:%d\n" ,(int)gpp->stb_comp_vidhand ,(int)composite_image_id ); } } #endif return (composite_image_id); } /* end p_fetch_composite_image */ /* --------------------------------------- * p_fetch_display_th_data_from_storyboard * --------------------------------------- * fetch the requested framnr as th_data * by interpreting the relevant storyboard clip element. * * return th_data if the clip is from type MOVIE * return NULL in case of other clip types (of error) * for other clip types (IMAGE or FRAME range) * the filename of the relevant image is set into the * output parameter filename_pptr. * OUT: ckey_pptr the string for caching the frame fetched from clip type MOVIE * (no changes for other clip types) * OUT: filename_pptr filename for fetching frame in case clip type is no MOVIE * is reset to NULL for clip type MOVIE */ guchar * p_fetch_display_th_data_from_storyboard(GapPlayerMainGlobalParams *gpp , gint32 framenr , gchar **ckey_pptr , gchar **filename_pptr , gint32 *th_width_ptr , gint32 *th_height_ptr , gint32 *th_bpp_ptr , gint32 *flip_request_ptr , gint32 *flip_status_ptr ) { GapStoryLocateRet *stb_ret; guchar *l_th_data; l_th_data = NULL; stb_ret = gap_story_locate_framenr(gpp->stb_ptr , framenr , gpp->stb_in_track ); if(stb_ret) { if((stb_ret->locate_ok) && (stb_ret->stb_elem)) { *filename_pptr = gap_story_get_filename_from_elem_nr(stb_ret->stb_elem , stb_ret->ret_framenr ); *flip_request_ptr = stb_ret->stb_elem->flip_request; if(stb_ret->stb_elem->record_type == GAP_STBREC_VID_MOVIE) { if(*filename_pptr) { if(gpp->use_thumbnails) { /* fetch does already scale down to current preview size */ *th_width_ptr = gpp->pv_ptr->pv_width; *th_height_ptr = gpp->pv_ptr->pv_height; } else { /* negative width/height does force fetch at original video size */ *th_width_ptr = -1; *th_height_ptr = -1; } if (gpp->max_player_cache > 0) { *ckey_pptr = gap_player_cache_new_movie_key(*filename_pptr , stb_ret->ret_framenr , stb_ret->stb_elem->seltrack , stb_ret->stb_elem->delace ); } l_th_data = p_fetch_videoframe_via_cache(gpp , *filename_pptr , stb_ret->ret_framenr , 1 + (abs(stb_ret->stb_elem->to_frame) - abs(stb_ret->stb_elem->from_frame)) , stb_ret->stb_elem->seltrack , stb_ret->stb_elem->delace , stb_ret->stb_elem->preferred_decoder , th_bpp_ptr /* IN/OUT */ , th_width_ptr /* IN/OUT */ , th_height_ptr /* IN/OUT */ , flip_status_ptr /* IN/OUT */ , *ckey_pptr /* IN */ ); if(gpp->cancel_video_api) { if(l_th_data) { g_free(l_th_data); /* throw away undefined data in case of cancel */ l_th_data = NULL; } if(gpp->progress_bar) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(gpp->progress_bar) , _("Canceled")); } } g_free(*filename_pptr); *filename_pptr = NULL; } } } g_free(stb_ret); } return (l_th_data); } /* end p_fetch_display_th_data_from_storyboard */ /* ----------------------------------------------- * p_fetch_display_composite_image_from_storyboard * ----------------------------------------------- * fetch the requested framnr as th_data (if already cached) * or as gimp image id (if fetched as composite video frame * via storyboard render processor) * * return th_data if the frame was in the cache. (NULL if not) * OUT: ckey_pptr the string for caching the frame * OUT: composite_image_id_ptr image id if fetched via processing. * (-1 is output if no image was fetched) */ guchar * p_fetch_display_composite_image_from_storyboard(GapPlayerMainGlobalParams *gpp , gint32 framenr , gchar **ckey_pptr , gint32 *composite_image_id_ptr , gint32 *th_width_ptr , gint32 *th_height_ptr , gint32 *th_bpp_ptr , gint32 *flip_request_ptr , gint32 *flip_status_ptr ) { gint32 l_width; gint32 l_height; guchar *l_th_data; l_th_data = NULL; *composite_image_id_ptr = -1; if(gpp->stb_ptr == NULL) { return (NULL); } l_width = gpp->stb_ptr->master_width; l_height = gpp->stb_ptr->master_height; if(gpp->use_thumbnails) { /* fetch does already scale down to current preview size */ l_width = gpp->pv_ptr->pv_width; l_height = gpp->pv_ptr->pv_height; } if(gpp->stb_comp_vidhand == NULL) { p_open_composite_storyboard(gpp); } if(gpp->stb_comp_vidhand) { *ckey_pptr = gap_player_cache_new_composite_video_key( gpp->stb_ptr->storyboardfile , framenr , gpp->stb_ptr->stb_parttype , gpp->stb_ptr->stb_unique_id ); l_th_data = p_fetch_frame_via_cache(gpp , *ckey_pptr , th_bpp_ptr , th_width_ptr , th_height_ptr , flip_status_ptr ); if(gap_debug) { printf("COMPOSITE thdata:%d ckey: %s\n" ,(int)l_th_data ,*ckey_pptr ); } if(l_th_data == NULL) { /* The storyboard render processor is used to fetch * the frame as rendered gimp image of desired size. * in this case th_data is returned as NULL. * * NOTE:flip_request transformations are already rendered by * the storyboard render processor * therefore no changes to propagate to the players * pview widget */ *composite_image_id_ptr = p_fetch_composite_image(gpp , framenr , l_width , l_height ); *flip_status_ptr = *flip_request_ptr; } } return (l_th_data); } /* end p_fetch_display_composite_image_from_storyboard */ /* ------------------------------ * p_render_display_free_pixbuf * ------------------------------ * render form pixbuf * free the pixbuf after rendering (unref) */ static void p_render_display_free_pixbuf(GapPlayerMainGlobalParams *gpp , GdkPixbuf *pixbuf , gint32 flip_request , gint32 flip_status ) { /* copy pixbuf as layer into the mtrace_image (only of mtrace_mode not OFF) */ p_mtrace_pixbuf(gpp, pixbuf); gap_pview_render_f_from_pixbuf (gpp->pv_ptr , pixbuf , flip_request , flip_status ); g_object_unref(pixbuf); } /* end p_render_display_free_pixbuf */ /* ------------------------------ * p_render_display_free_thdata * ------------------------------ * render form th_data buffer * free the th_data buffer after rendering * (but only if data was not grabbed for refresh) */ static void p_render_display_free_thdata(GapPlayerMainGlobalParams *gpp , guchar *th_data , gint32 th_width , gint32 th_height , gint32 th_bpp , gint32 flip_request , gint32 flip_status ) { gboolean th_data_was_grabbed; p_mtrace_tmpbuf(gpp , th_data , th_width , th_height , th_bpp ); th_data_was_grabbed = gap_pview_render_f_from_buf (gpp->pv_ptr , th_data , th_width , th_height , th_bpp , TRUE /* allow_grab_src_data */ , flip_request , flip_status ); if(th_data_was_grabbed) { /* the gap_pview_render_f_from_buf procedure can grab the th_data * instead of making a ptivate copy for later use on repaint demands. * if such a grab happened it returns TRUE. * (this is done for optimal performance reasons) * in such a case the caller must NOT free the src_data (th_data) !!! */ th_data = NULL; } if(th_data) g_free(th_data); } /* end p_render_display_free_thdata */ /* ------------------------------ * p_render_display_free_image_id * ------------------------------ * render from the specified image_id * and delete this image after rendering */ static void p_render_display_free_image_id(GapPlayerMainGlobalParams *gpp , gint32 image_id , gint32 flip_request , gint32 flip_status ) { /* there is no need for undo on this scratch image * so we turn undo off for performance reasons */ gimp_image_undo_disable (image_id); /* copy image as layer into the mtrace_image (only if mtrace_mode not OFF) */ p_mtrace_image(gpp, image_id); gap_pview_render_f_from_image (gpp->pv_ptr , image_id , flip_request , flip_status ); gimp_image_delete(image_id); } /* end p_render_display_free_image_id */ /* ------------------------------------------ * p_render_display_from_active_image_or_file * ------------------------------------------ */ static void p_render_display_from_active_image_or_file(GapPlayerMainGlobalParams *gpp , char *img_filename , gboolean framenr_is_the_active_image , gint32 flip_request , gint32 flip_status ) { gint32 l_image_id; /* got no thumbnail data, must use the full image */ if(framenr_is_the_active_image) { /* check if automatic onionskin layer removal is turned on * (in this case the player must display the image without * onionskin layers) */ if(gpp->onion_delete) { l_image_id = gap_onion_base_image_duplicate(gpp->image_id); gap_onion_base_onionskin_delete(l_image_id); } else { l_image_id = gimp_image_duplicate(gpp->image_id); } } else { l_image_id = gap_lib_load_image(img_filename); if (l_image_id < 0) { /* could not read the image * one reason could be, that frames were deleted while this plugin is active * so we stop playback, * and try to reload informations about all frames */ if(gap_debug) printf("LOAD IMAGE_ID: %s failed\n", img_filename); if(gpp->image_id < 0) { /* give up, because we could not get any imagedata * (this case may happen if images are deleted while playback * or if videofiles with unknown extensions were passed * to the player and were tried to load as gimp image * because they are not recognized as video) */ return; } p_keep_track_of_active_master_image(gpp); } } if(gpp->use_thumbnails) { gap_thumb_cond_gimp_file_save_thumbnail(l_image_id, img_filename); } p_render_display_free_image_id(gpp , l_image_id , flip_request , flip_status ); } /* end p_render_display_from_active_image_or_file */ /* ------------------------------ * p_display_frame * ------------------------------ * display framnr from thumbnail or from full image * the active image (the one from where we were invoked) * is not read from discfile to reflect actual changes. * * Alternative sources for fetching the frame are * A) storyboard files (gpp->stb_ptr != NULL) * in this case the fetch for a single track is done by * interpreting the relevant videoclip, * * or via calling the fetcher from the storyboard render processor * to get the composite image (if stb_in_track -1) * * B) fetching from a single movie file * when invoked from the video extract plug-in. * (gpp->ainfo_ptr->ainfo_type == GAP_AINFO_MOVIE) * * Note: * there is no active image if the player was invoked * for storyboard playback (gpp->stb_ptr != NULL) * or for filename based playback (gpp->imagename != NULL) * in those cases we always have to fetch from file (thumb or full image) */ static void p_display_frame(GapPlayerMainGlobalParams *gpp, gint32 framenr) { char *l_filename; gint32 l_th_width; gint32 l_th_height; gint32 l_th_data_count; gint32 l_th_bpp; gint32 l_flip_request; gint32 l_flip_status; gint32 l_composite_image_id; guchar *l_th_data; gboolean framenr_is_the_active_image; GdkPixbuf *pixbuf; gchar *ckey; /*if(gap_debug) printf("p_display_frame START: framenr:%d\n", (int)framenr);*/ if(gpp->gva_lock) { /* do not attempt displaying frames while we are inside * of p_alloc_ainfo_for_videofile procedure */ return; } ckey = NULL; l_th_data = NULL; pixbuf = NULL; l_th_bpp = 3; l_filename = NULL; 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; l_flip_status = GAP_STB_FLIP_NONE; if(gpp->stb_in_track >= 0) { l_th_data = p_fetch_display_th_data_from_storyboard(gpp , framenr , &ckey , &l_filename , &l_th_width , &l_th_height , &l_th_bpp , &l_flip_request , &l_flip_status ); if(gpp->cancel_video_api) { return; } } else { gint32 mapped_framenr = gap_story_get_mapped_master_frame_number(gpp->stb_ptr->mapping, framenr); if(gap_debug) { printf(" >> PLAY composite framenr:%d mapped_framenr:%d\n" ,(int)framenr ,(int)mapped_framenr ); } l_th_data = p_fetch_display_composite_image_from_storyboard(gpp , mapped_framenr , &ckey , &l_composite_image_id , &l_th_width , &l_th_height , &l_th_bpp , &l_flip_request , &l_flip_status ); } } else { l_flip_request = gpp->flip_request; l_flip_status = gpp->flip_status; if(gpp->ainfo_ptr->ainfo_type == GAP_AINFO_MOVIE) { /* playback of a single videoclip */ if(gpp->use_thumbnails) { /* fetch does alread scale down to current preview size */ l_th_width = gpp->pv_ptr->pv_width; l_th_height = gpp->pv_ptr->pv_height; } else { /* negative width/height does force fetch at original video size */ l_th_width = -1; l_th_height = -1; } if (gpp->max_player_cache > 0) { ckey = gap_player_cache_new_movie_key(gpp->ainfo_ptr->old_filename , framenr , gpp->ainfo_ptr->seltrack , gpp->ainfo_ptr->delace ); } l_th_data = p_fetch_videoframe_via_cache(gpp , gpp->ainfo_ptr->old_filename , framenr , 1 + (abs(gpp->ainfo_ptr->last_frame_nr) - abs(gpp->ainfo_ptr->first_frame_nr)) , gpp->ainfo_ptr->seltrack , gpp->ainfo_ptr->delace , gpp->preferred_decoder , &l_th_bpp /* IN/OUT */ , &l_th_width /* IN/OUT */ , &l_th_height /* IN/OUT */ , &l_flip_status /* OUT */ , ckey /* IN */ ); if(gpp->cancel_video_api) { if(l_th_data) { g_free(l_th_data); /* throw away undefined data in case of cancel */ l_th_data = NULL; } if(gpp->progress_bar) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(gpp->progress_bar) , _("Canceled")); } return; } } else { if(gpp->ainfo_ptr->frame_cnt > 0) { l_filename = gap_lib_alloc_fname(gpp->ainfo_ptr->basename, framenr, gpp->ainfo_ptr->extension); } else { /* if player operates on a single image we have to build * the filename just of basename or basename+extension part * (this rare case can occure when the player is invoked * from a storyboard to playback a clip that is made up of a single image) */ if(gpp->ainfo_ptr->extension) { l_filename = g_strdup_printf("%s%s" ,gpp->ainfo_ptr->basename ,gpp->ainfo_ptr->extension ); } else { l_filename = g_strdup(gpp->ainfo_ptr->basename); } } if(gpp->imagename == NULL) { framenr_is_the_active_image = p_check_for_active_image(gpp, framenr); } } } /* --------------------- */ if((l_filename == NULL) && (l_th_data == NULL) && (l_composite_image_id < 0)) { /* frame not available, create black fully transparent buffer * ( renders as empty checkerboard) */ l_th_bpp = 4; l_th_width = gpp->pv_width; l_th_height = gpp->pv_height; l_th_data_count = l_th_width * l_th_height * l_th_bpp; l_th_data = g_malloc0(l_th_data_count); } else { if(gpp->use_thumbnails) { if(framenr_is_the_active_image) { gint32 l_tmp_image_id; l_tmp_image_id = -1; /* check if automatic onionskin layer removal is turned on */ if(gpp->onion_delete) { /* check if image has visible onionskin layers */ if(gap_onion_image_has_oinonlayers(gpp->image_id, TRUE /* only visible*/)) { l_tmp_image_id = gap_onion_base_image_duplicate(gpp->image_id); } } if(l_tmp_image_id == -1) { gap_pdb_gimp_image_thumbnail(gpp->image_id , gpp->pv_width , gpp->pv_height , &l_th_width , &l_th_height , &l_th_bpp , &l_th_data_count , &l_th_data ); } else { gap_onion_base_onionskin_delete(l_tmp_image_id); gap_pdb_gimp_image_thumbnail(l_tmp_image_id , gpp->pv_width , gpp->pv_height , &l_th_width , &l_th_height , &l_th_bpp , &l_th_data_count , &l_th_data ); gimp_image_delete(l_tmp_image_id); } } else { /* init preferred width and height * (as hint for the thumbnail loader to decide * if thumbnail is to fetch from normal or large thumbnail directory * just for the case when both sizes are available) */ l_th_width = gpp->pv_width; l_th_height = gpp->pv_height; pixbuf = gap_thumb_file_load_pixbuf_thumbnail(l_filename , &l_th_width, &l_th_height , &l_th_bpp ); } } } if(l_composite_image_id >= 0) { p_render_display_free_image_id(gpp , l_composite_image_id , l_flip_request , l_flip_status ); } else { if(pixbuf) { p_render_display_free_pixbuf(gpp, pixbuf, l_flip_request, l_flip_status); } else { if((l_th_data == NULL) && (!framenr_is_the_active_image) && (gpp->max_player_cache > 0)) { ckey = gap_player_cache_new_image_key(l_filename); l_th_data = p_fetch_frame_via_cache(gpp , ckey , &l_th_bpp , &l_th_width , &l_th_height , &l_flip_status ); } if (l_th_data) { p_render_display_free_thdata(gpp , l_th_data , l_th_width , l_th_height , l_th_bpp , l_flip_request , l_flip_status ); l_th_data = NULL; } else { /* got no thumbnail data, must use the full image */ p_render_display_from_active_image_or_file(gpp , l_filename , framenr_is_the_active_image , l_flip_request , l_flip_status ); } } } if (ckey != NULL) { p_frame_chache_processing(gpp, ckey); g_free(ckey); } gpp->play_current_framenr = framenr; p_update_position_widgets(gpp); gdk_flush(); if(l_th_data) g_free(l_th_data); if(l_filename) g_free(l_filename); } /* end p_display_frame */ /* ------------------------------ * p_get_next_framenr_in_sequence /2 * ------------------------------ */ gint32 p_get_next_framenr_in_sequence2(GapPlayerMainGlobalParams *gpp) { gint32 l_first; gint32 l_last; l_first = gpp->ainfo_ptr->first_frame_nr; l_last = gpp->ainfo_ptr->last_frame_nr; if(gpp->play_selection_only) { l_first = gpp->begin_frame; l_last = gpp->end_frame; } if(gpp->play_backward) { if(gpp->play_current_framenr <= l_first) { p_audio_resync(gpp); if(gpp->play_loop) { if(gpp->play_pingpong) { gpp->play_current_framenr = l_first + 1; gpp->play_backward = FALSE; gpp->pingpong_count++; } else { gpp->play_current_framenr = l_last; } } else { if((gpp->play_pingpong) && (gpp->pingpong_count <= 0)) { gpp->play_current_framenr = l_first + 1; gpp->play_backward = FALSE; gpp->pingpong_count++; } else { gpp->pingpong_count = 0; return -1; /* STOP if first frame reached */ } } } else { gpp->play_current_framenr--; } } else { if(gpp->play_current_framenr >= l_last) { p_audio_resync(gpp); if(gpp->play_loop) { if(gpp->play_pingpong) { gpp->play_current_framenr = l_last - 1; gpp->play_backward = TRUE; gpp->pingpong_count++; } else { gpp->play_current_framenr = l_first; } } else { if((gpp->play_pingpong) && (gpp->pingpong_count <= 0)) { gpp->play_current_framenr = l_last - 1; gpp->play_backward = TRUE; gpp->pingpong_count++; } else { gpp->pingpong_count = 0; return -1; /* STOP if last frame reached */ } } } else { gpp->play_current_framenr++; } } gpp->play_current_framenr = CLAMP(gpp->play_current_framenr, l_first, l_last); return (gpp->play_current_framenr); } /* end p_get_next_framenr_in_sequence2 */ gint32 p_get_next_framenr_in_sequence(GapPlayerMainGlobalParams *gpp) { gint32 framenr; framenr = p_get_next_framenr_in_sequence2(gpp); if((framenr < 0) || (gpp->play_backward) || (gpp->audio_resync > 0)) { /* stop audio at end (-1) or when video plays revers or resync needed */ p_audio_stop(gpp); /* RESYNC: break for N frames, then restart audio at sync position * (NOTE: ideally we should restart immediate without any break * but restarting the playback often and very quickly leads to * deadlock (in the audioserver or clent/server communication) */ if(gpp->audio_resync > 0) { gpp->audio_resync--; } } else { /* conditional audio start * (can happen on any frame if audio offsets are used) */ #ifdef TRY_AUTO_SYNC_AT_FAST_PLAYBACKSPEED /* this codespart tries to keep audio playing sync at fast speed * but sounds not good, and does not work reliable * therefore it should not be compiled in public release version. * (asynchron audio that will not be able to follow up the videospeed * will be the result in that case) */ if (gpp->audio_required_samplerate > GAP_PLAYER_MAIN_MAX_SAMPLERATE) { gint32 nframes; /* required samplerate is faster than highest possible audioplayback speed * stop and restart at new offset at every n.th frame to follow the faster video * (this will result in glitches) */ nframes = 8 * (1 + (gpp->speed / 5)); if((framenr % nframes) == 0) { printf("WARNING: Audiospeed cant follow up video speed nframes:%d\n", (int)nframes); p_audio_resync(gpp); /* audioserver does not like tto much stop&go and hangs sometimes */ } } #endif p_audio_start_play(gpp); } return(framenr); } /*end p_get_next_framenr_in_sequence */ /* ----------------------------- * p_step_frame * ----------------------------- */ static void p_step_frame(GapPlayerMainGlobalParams *gpp, gint stepsize) { gint32 framenr; framenr = gpp->play_current_framenr + stepsize; if(gpp->ainfo_ptr) { framenr = CLAMP(framenr , gpp->ainfo_ptr->first_frame_nr , gpp->ainfo_ptr->last_frame_nr ); if(gpp->play_current_framenr != framenr) { /* we want the go_timer to display that framenr */ gpp->go_job_framenr = framenr; if(gpp->go_timertag < 0) { /* if the go_timer is not already prepared to fire * we start p_display_frame(gpp, gpp->go_job_framenr); * after minimal delay of 8 millisecods. */ gpp->go_timertag = (gint32) g_timeout_add(8, (GtkFunction)on_timer_go_job, gpp); } } } } /* end p_step_frame */ /* ------------------------------ * p_framenr_from_go_number * ------------------------------ */ gint32 p_framenr_from_go_number(GapPlayerMainGlobalParams *gpp, gint32 go_number) { /* if(gap_debug) printf("p_framenr_from_go_number go_base_framenr: %d go_base:%d go_number:%d curr_frame:%d\n" , (int)gpp->go_base_framenr , (int)gpp->go_base , (int)go_number , (int)gpp->play_current_framenr ); */ if((gpp->go_base_framenr < 0) || (gpp->go_base < 0)) { gpp->go_base_framenr = gpp->play_current_framenr; gpp->go_base = go_number; } /* printf("p_framenr_from_go_number: result framenr:%d\n", (int)(gpp->go_base_framenr + (go_number - gpp->go_base)) ); */ return CLAMP(gpp->go_base_framenr + (go_number - gpp->go_base) , gpp->ainfo_ptr->first_frame_nr , gpp->ainfo_ptr->last_frame_nr ); } /* end p_framenr_from_go_number */ /* ------------------ * on_timer_playback * ------------------ * This timer callback is called periodical in intervall depending of playback speed. * (the playback timer is completely removed while not playing) */ static void on_timer_playback(GapPlayerMainGlobalParams *gpp) { gulong elapsed_microsecs; gdouble elapsed_secs; static char status_txt[30]; /*if(gap_debug) printf("\non_timer_playback: START\n");*/ if(gpp) { p_remove_play_timer(gpp); if(gpp->in_timer_playback) { /* if speed is too fast the timer may fire again, while still processing * the previous callback. in that case return without any action * NOTE: at test with gtk2.2.1 this line of CODE was never reached, * even if the frame is too late. * the check if in_timer_playback is done just to be at the safe side. * (late frames are detected by checking the elapsed time). */ if(gap_debug) printf("\n\n\n on_timer_playback interrupted by next TIMERCALL \n\n"); return; } gpp->in_timer_playback = TRUE; if(gpp->play_is_active) { gint ii; gint ii_max; gint32 l_prev_framenr; gint32 l_framenr = -1; gboolean l_frame_dropped; gdouble l_delay; l_framenr = -1; l_frame_dropped = FALSE; l_delay = gpp->delay_secs; ii_max = (gpp->exact_timing) ? 20 : 2; /* - if we have exact timing handle (or drop) upto max 20 frames in one timercallback * - if your machine is fast enough to display the frame at gpp->speed * this loop will display only one frame. (the ideal case) * - if NOT fast enough, but the frame is just a little late, * it tries to display upto (3) frames without restarting the timer. * (and without giving control back to the gtk main loop) * - if we are still late at this point * we begin to drop upto (20) frames to get back in exact time. * - if this does not help either, we give up * (results in NON exact timing, regardless to the exact_timing flag). */ for(ii=1; ii < ii_max; ii++) { l_prev_framenr = l_framenr; l_framenr = p_get_next_framenr_in_sequence(gpp); gpp->framecnt += 1.0; /* count each handled frame (for timing purpose) */ /*if(gap_debug) printf("on_timer_playback[%d]: l_framenr:%d\n", (int)ii, (int)l_framenr);*/ if(l_framenr < 0) { if((l_frame_dropped) && (l_prev_framenr > 0)) { /* the last frame in sequence (l_prev_framenr) would be DROPPED * to keep exact timing, but now it is time to STOP * in this case we display that frame, * with minimal delay of 8 millisecs via the one-shot go_timer. */ gpp->go_job_framenr = l_prev_framenr; if(gpp->go_timertag >= 0) { g_source_remove(gpp->go_timertag); } gpp->go_timertag = (gint32) g_timeout_add(8, (GtkFunction)on_timer_go_job, gpp); } p_stop_playback(gpp); /* STOP at end of sequence */ break; } else { if((ii > 3) || ((0 - gpp->rest_secs) > (gpp->cycle_time_secs * 2)) ) { /* if delay is too much * (we are 2 cycletimes back, or already had handled 3 LATE frames in sequence) * start dropping frames now * until we are in time again */ l_frame_dropped = TRUE; /* printf("DROP (SKIP) frame\n"); */ gtk_label_set_text ( GTK_LABEL(gpp->status_label), _("Skip")); } else { p_display_frame(gpp, l_framenr); } /* get secs elapsed since playbackstart (or last speed change) */ elapsed_secs = g_timer_elapsed(gpp->gtimer, &elapsed_microsecs); gpp->rest_secs = (gpp->cycle_time_secs * gpp->framecnt) - elapsed_secs; /*if(gap_debug) printf("on_timer_playback[%d]: rest:%.4f\n", (int)ii, (float)gpp->rest_secs); */ if(gpp->rest_secs > 0) { if((!l_frame_dropped) && (ii == 1)) { gtk_label_set_text ( GTK_LABEL(gpp->status_label), _("Playing")); } /* we are fast enough, there is rest time to wait until next frame */ l_delay = gpp->delay_secs; /* we have no additional delay */ break; } l_delay = gpp->delay_secs - gpp->rest_secs; /* no time left at this point, try to display (or drop) next frame immediate */ if(!l_frame_dropped) { g_snprintf(status_txt, sizeof(status_txt), _("Delay %.2f"), (float)(l_delay)); gtk_label_set_text ( GTK_LABEL(gpp->status_label), status_txt); } } } /* end for */ /* keep track of absolute delay (since start or speed change) just for display purposes */ gpp->delay_secs = l_delay; /* restart timer for next cycle */ if(gpp->play_is_active) { p_start_playback_timer(gpp); } } gpp->in_timer_playback = FALSE; } } /* end on_timer_playback */ /* ------------------ * on_timer_go_job * ------------------ * This timer callback is called once after a go_button enter/clicked * callback with a miniamal delay of 8 millisecs. * * here is an example how it works: * * consider the user moves the mouse from left to right * passing go_buttons 1 upto 7 * * (1) (2) (3) (4) (5) (6) (7) * +-------+-------+-------+------+------+------+-------> time axis * ..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX * < -- RENDER time for (1) ------------> * * - at (1) the on_timer_go_job Timer is initialized * - The timer will fire after 8 millsecs, and starts rendering. * while renderng 2,3,4,5,6 do happen, and get queued as pending events. * - after render has finished * the events are processed in sequence * the first of the queued evnts (2) will init the go_timer again, * and each of the oter events just sets the go_framenr (upto 6). * - after another 8 millisecs delay the timer callback will start again * and now processes the most recent go_framenr (6) * * that way it is possible to skip frames for fast mousemoves on slow machines * (without that trick, the GUI would block until all visited go_bottons * are processed) */ static void on_timer_go_job(GapPlayerMainGlobalParams *gpp) { /*if(gap_debug) printf("\non_timer_go_job: START\n");*/ if(gpp) { if(gpp->go_timertag >= 0) { g_source_remove(gpp->go_timertag); } gpp->go_timertag = -1; if(gpp->go_job_framenr >= 0) { if(gpp->gva_lock) { /* the video api is still busy with fetching the previous frame * (do not disturb, but setup the go_timer for a next try * after 96 milliseconds) */ gpp->go_timertag = (gint32) g_timeout_add(96, (GtkFunction)on_timer_go_job, gpp); /*if(gap_debug) printf("on_timer_go_job: TRY LATER (96msec) %06d\n", (int)gpp->go_job_framenr);*/ } else { /*if(gap_debug) printf("on_timer_go_job: DISPLAY RENDER %06d\n", (int)gpp->go_job_framenr); */ p_display_frame(gpp, gpp->go_job_framenr); } } } } /* end on_timer_go_job */ /* ----------------------------- * on_play_button_clicked * ----------------------------- */ static void on_play_button_clicked(GtkButton *button , GdkEventButton *bevent , GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } gpp->play_backward = FALSE; gpp->request_cancel_video_api = TRUE; if(bevent) { if(bevent->state & GDK_SHIFT_MASK) { gpp->mtrace_mode = GAP_PLAYER_MTRACE_IMG_SIZE; } if (bevent->state & GDK_CONTROL_MASK) { gpp->mtrace_mode = GAP_PLAYER_MTRACE_PV_SIZE; } if(bevent->state & GDK_MOD1_MASK) { gpp->mtrace_image_id = -1; /* force creation of new image */ } } if(gpp->play_is_active) { if (gpp->audio_required_samplerate > GAP_PLAYER_MAIN_MAX_SAMPLERATE) { p_audio_resync(gpp); } return; } if(gpp->play_selection_only) { if (gpp->play_current_framenr >= gpp->end_frame) { /* we are at selection end, start from selection begin */ gpp->play_current_framenr = gpp->begin_frame; } } else { if (gpp->play_current_framenr >= gpp->ainfo_ptr->last_frame_nr) { /* we are at end, start from begin */ gpp->play_current_framenr = gpp->ainfo_ptr->first_frame_nr; } } p_initial_start_playback_timer(gpp); } /* end on_play_button_clicked */ /* ----------------------------- * on_pause_button_press_event * ----------------------------- */ static gboolean on_pause_button_press_event (GtkButton *button, GdkEventButton *bevent, GapPlayerMainGlobalParams *gpp) { gboolean play_was_active; if(gpp == NULL) { return FALSE; } if(gpp->progress_bar) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(gpp->progress_bar) ,gpp->progress_bar_idle_txt ); } play_was_active = gpp->play_is_active; p_stop_playback(gpp); if(!play_was_active) { if ((bevent->button > 1) && (bevent->type == GDK_BUTTON_PRESS) && (gpp->ainfo_ptr)) { if(bevent->button > 2) { p_display_frame(gpp, gpp->end_frame); /* right mousebutton : goto end */ } else { p_display_frame(gpp, gpp->ainfo_ptr->curr_frame_nr); /* middle mousebutton : goto active image (invoker) */ } } else { p_display_frame(gpp, gpp->begin_frame); /* left mousebutton : goto begin */ } } return FALSE; } /* end on_pause_button_press_event */ /* ----------------------------- * on_back_button_clicked * ----------------------------- */ static void on_back_button_clicked(GtkButton *button , GdkEventButton *bevent , GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } gpp->play_backward = TRUE; gpp->request_cancel_video_api = TRUE; if(bevent) { if(bevent->state & GDK_SHIFT_MASK) { gpp->mtrace_mode = GAP_PLAYER_MTRACE_IMG_SIZE; } if (bevent->state & GDK_CONTROL_MASK) { gpp->mtrace_mode = GAP_PLAYER_MTRACE_PV_SIZE; } if(bevent->state & GDK_MOD1_MASK) { gpp->mtrace_image_id = -1; /* force creation of new image */ } } if(gpp->play_is_active) { return; } if(gpp->play_selection_only) { if (gpp->play_current_framenr <= gpp->begin_frame) { /* we are already at selection begin, start from selection end */ gpp->play_current_framenr = gpp->end_frame; } } else { if (gpp->play_current_framenr <= gpp->ainfo_ptr->first_frame_nr) { /* we are already at begin, start from end */ gpp->play_current_framenr = gpp->ainfo_ptr->last_frame_nr; } } p_initial_start_playback_timer(gpp); } /* end on_back_button_clicked */ /* ----------------------------- * on_from_spinbutton_changed * ----------------------------- */ static void on_from_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } gpp->begin_frame = (gint32)GTK_ADJUSTMENT(gpp->from_spinbutton_adj)->value; if(gpp->begin_frame > gpp->end_frame) { gpp->end_frame = gpp->begin_frame; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->to_spinbutton_adj) , (gfloat)gpp->end_frame ); } else { if(gpp->caller_range_linked) { p_printout_range(gpp, FALSE, FALSE); } } } /* end on_from_spinbutton_changed */ /* ----------------------------- * on_to_spinbutton_changed * ----------------------------- */ static void on_to_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } gpp->end_frame = (gint32)GTK_ADJUSTMENT(gpp->to_spinbutton_adj)->value; if(gpp->end_frame < gpp->begin_frame) { gpp->begin_frame = gpp->end_frame; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->from_spinbutton_adj) , (gfloat)gpp->begin_frame ); } else { if(gpp->caller_range_linked) { p_printout_range(gpp, FALSE, FALSE); } } } /* end on_to_spinbutton_changed */ /* ----------------------------- * on_vid_preview_button_press_event * ----------------------------- */ gboolean on_vid_preview_button_press_event (GtkWidget *widget, GdkEventButton *bevent, GapPlayerMainGlobalParams *gpp) { if(gap_debug) { printf("on_vid_preview_button_press_event: START\n"); } if(gpp->mtrace_mode == GAP_PLAYER_MTRACE_OFF) { gpp->mtrace_mode = GAP_PLAYER_MTRACE_IMG_SIZE; if (bevent->state & GDK_CONTROL_MASK) { gpp->mtrace_mode = GAP_PLAYER_MTRACE_PV_SIZE; } if(bevent->state & GDK_MOD1_MASK) { gpp->mtrace_image_id = -1; /* force creation of new image */ } p_display_frame(gpp, gpp->play_current_framenr); gpp->mtrace_mode = GAP_PLAYER_MTRACE_OFF; } return FALSE; } /* end on_vid_preview_button_press_event */ /* ----------------------------- * on_warp_frame_scroll_event * ----------------------------- * handle scroll event (inludes wheel mose) */ static gboolean on_warp_frame_scroll_event (GtkWidget *widget, GdkEventScroll *sevent, GapPlayerMainGlobalParams *gpp) { /*if(gap_debug) printf("on_warp_frame_scroll_event: START\n"); */ p_stop_playback(gpp); if((sevent->direction == GDK_SCROLL_UP) || (sevent->direction == GDK_SCROLL_RIGHT)) { p_step_frame(gpp, -1); } else { p_step_frame(gpp, 1); } return FALSE; } /* end on_warp_frame_scroll_event */ /* ----------------------------- * on_vid_preview_expose_event * ----------------------------- */ gboolean on_vid_preview_expose_event (GtkWidget *widget, GdkEventExpose *eevent, GapPlayerMainGlobalParams *gpp) { /*if(gap_debug) printf(" xxxxxxxx on_vid_preview_expose_event: START\n");*/ if(gpp == NULL) { return FALSE; } if (gpp->play_is_active && (gpp->rest_secs < 0.2)) { /* we are playing and the next frame update is very near (less than 2/10 sec) * in that case it is better choice to skip the repaint * on expose events. * (dont waste time for repaint in that case) */ return FALSE; } gap_pview_repaint(gpp->pv_ptr); return FALSE; } /* end on_vid_preview_expose_event */ /* ----------------------------- * on_shell_window_size_allocate * ----------------------------- */ static void on_shell_window_size_allocate (GtkWidget *widget, GtkAllocation *allocation, GapPlayerMainGlobalParams *gpp) { if((gpp == NULL) || (allocation == NULL)) { return; } if(gap_debug) printf("on_shell_window_size_allocate: START shell_alloc: w:%d h:%d \n" , (int)allocation->width , (int)allocation->height ); if(gpp->shell_initial_width < 0) { gpp->shell_initial_width = allocation->width; gpp->shell_initial_height = allocation->height; p_fit_initial_shell_window(gpp); /* for setting window default size */ } else { if((allocation->width < gpp->shell_initial_width) || (allocation->height < gpp->shell_initial_height)) { /* dont allow shrink below initial size */ p_fit_initial_shell_window(gpp); } } } /* end on_shell_window_size_allocate */ /* ----------------------------- * on_vid_preview_size_allocate * ----------------------------- * this procedure handles automatic * resize of the preview when the user resizes the window. * While sizechanges via the Size spinbutton this handler is usually * disconnected, and will be reconnected when the mouse leaves the shell window. * This handlerprocedure acts on the drawing_area widget of the preview. * Size changes of drawing_area are propagated to * the preview (aspect_frame and drawing_area) by calls to p_update_pviewsize. */ static void on_vid_preview_size_allocate (GtkWidget *widget, GtkAllocation *allocation, GapPlayerMainGlobalParams *gpp) { gint32 allo_width; gint32 allo_height; #define PV_BORDER_X 10 #define PV_BORDER_Y 10 if((gpp == NULL) || (allocation == NULL)) { return; } if(gap_debug) printf("on_vid_preview_size_allocate: START old: ow:%d oh:%d new: w:%d h:%d \n" , (int)gpp->old_resize_width , (int)gpp->old_resize_height , (int)allocation->width , (int)allocation->height ); if(gpp->pv_ptr->da_widget == NULL) { return; } if(gpp->pv_ptr->da_widget->window == NULL) { return; } if(gap_debug) printf(" on_vid_preview_size_allocate: ORIGINAL pv_w:%d pv_h:%d handler_id:%d\n" , (int)gpp->pv_ptr->pv_width , (int)gpp->pv_ptr->pv_height , (int)gpp->resize_handler_id ); allo_width = allocation->width; allo_height = allocation->height; /* react on significant changes (min 6 pixels) only) */ if(((gpp->old_resize_width / 6) != (allo_width / 6)) || ((gpp->old_resize_height / 6) != (allo_height / 6))) { gint32 pv_pixelsize; gboolean blocked; gdouble img_ratio; gdouble alloc_ratio; img_ratio = 1.0; blocked = FALSE; alloc_ratio = (gdouble)allo_width / (gdouble)allo_height; if(gpp->ainfo_ptr == NULL) { blocked = FALSE; pv_pixelsize = gpp->pv_pixelsize; } else { img_ratio = (gdouble)gpp->ainfo_ptr->width / (gdouble)gpp->ainfo_ptr->height; if(img_ratio >= 1.0) { /* imageorientation is landscape */ if(alloc_ratio <= img_ratio) { pv_pixelsize = CLAMP( (allo_width - PV_BORDER_X) , GAP_PLAYER_MIN_SIZE , GAP_PLAYER_MAX_SIZE); } else { pv_pixelsize = CLAMP( (((allo_height - PV_BORDER_Y) * gpp->ainfo_ptr->width) / gpp->ainfo_ptr->height) , GAP_PLAYER_MIN_SIZE , GAP_PLAYER_MAX_SIZE); } } else { /* imageorientation is portrait */ if(alloc_ratio <= img_ratio) { pv_pixelsize = CLAMP( (((allo_width - PV_BORDER_X) * gpp->ainfo_ptr->height) / gpp->ainfo_ptr->width) , GAP_PLAYER_MIN_SIZE , GAP_PLAYER_MAX_SIZE); } else { pv_pixelsize = CLAMP( (allo_height - PV_BORDER_Y) , GAP_PLAYER_MIN_SIZE , GAP_PLAYER_MAX_SIZE); } } } if (gap_debug) printf("pv_pixelsize: %d img_ratio:%.3f alloc_ratio:%.3f\n" , (int)pv_pixelsize , (float)img_ratio , (float)alloc_ratio ); if(pv_pixelsize > gpp->pv_pixelsize) { if ((alloc_ratio > 1.0) /* landscape */ && (allo_width < gpp->old_resize_width)) { if(gap_debug) printf(" BLOCK preview grow on width shrink\n"); blocked = TRUE; } if ((alloc_ratio <= 1.0) /* portrait */ && (allo_height < gpp->old_resize_height)) { if(gap_debug) printf(" BLOCK preview grow on height shrink\n"); blocked = TRUE; } } if(!blocked) { gpp->pv_pixelsize = pv_pixelsize; p_update_pviewsize(gpp); if(!gpp->play_is_active) { /* have to refresh current frame * repaint is not enough because size has changed * (if play_is_active we can skip this, because the next update is on the way) */ p_display_frame(gpp, gpp->play_current_framenr); } } if(gap_debug) printf(" on_vid_preview_size_allocate: AFTER resize pv_w:%d pv_h:%d\n" , (int)gpp->pv_ptr->pv_width , (int)gpp->pv_ptr->pv_height ); } gpp->old_resize_width = allo_width; gpp->old_resize_height = allo_height; if(gap_debug) printf(" on_vid_preview_size_allocate: END\n"); } /* end on_vid_preview_size_allocate */ /* ----------------------------- * on_framenr_button_clicked * ----------------------------- * SHIFT-click: goto frame * else: (normal click or other modifier keys ...) * set END of range if inoked from the framenr_2_button widget * set BEGIN of range if NOT inoked from the framenr_2_button widget */ static void on_framenr_button_clicked (GtkButton *button, GdkEventButton *bevent, GapPlayerMainGlobalParams *gpp) { GimpParam *return_vals; int nreturn_vals; gint button_type; gint32 dummy_layer_id; /*if(gap_debug) printf("on_framenr_button_clicked: START\n"); */ if(gpp == NULL) { return; } p_stop_playback(gpp); if(button) { button_type = (gint) g_object_get_data (G_OBJECT (button), KEY_FRAMENR_BUTTON_TYPE); } else { button_type = FRAMENR_BUTTON_BEGIN; } if(bevent) { if (!(bevent->state & GDK_SHIFT_MASK)) /* normal Click */ { /* for normal click and other modifiers other than SHIFT (GDK_CONTROL_MASK) */ if(button_type == FRAMENR_BUTTON_END) { /* set END of the range */ gpp->end_frame = gpp->play_current_framenr; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->to_spinbutton_adj) , (gfloat)gpp->play_current_framenr ); if(gpp->end_frame < gpp->begin_frame) { gpp->begin_frame = gpp->end_frame; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->from_spinbutton_adj) , (gfloat)gpp->begin_frame ); } return; } /* set BEGIN of the range */ gpp->begin_frame = gpp->play_current_framenr; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->from_spinbutton_adj) , (gfloat)gpp->play_current_framenr ); if(gpp->begin_frame > gpp->end_frame) { gpp->end_frame = gpp->begin_frame; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->to_spinbutton_adj) , (gfloat)gpp->end_frame ); } return; } } if((gpp->stb_ptr) || (gpp->image_id < 0)) { /* NOP in storyboard mode */ return; } dummy_layer_id = gap_image_get_any_layer(gpp->image_id); return_vals = gimp_run_procedure ("plug_in_gap_goto", &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, gpp->image_id, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_INT32, gpp->play_current_framenr, GIMP_PDB_END); if(return_vals) { if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { p_reload_ainfo_ptr(gpp, return_vals[1].data.d_image); p_update_ainfo_dependent_widgets(gpp); gimp_displays_flush(); } gimp_destroy_params(return_vals, nreturn_vals); } } /* end on_framenr_button_clicked */ /* ----------------------------- * on_from_button_clicked * ----------------------------- */ static void on_from_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp) { if(gpp) { gboolean printflag; printflag = TRUE; if(gpp->fptr_set_range) { printflag = FALSE; } p_printout_range(gpp, FALSE, printflag); } } /* end on_from_button_clicked */ /* ----------------------------- * on_to_button_clicked * ----------------------------- */ static void on_to_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp) { if(gpp) { gboolean printflag; printflag = TRUE; if(gpp->fptr_set_range) { printflag = FALSE; } p_printout_range(gpp, TRUE, printflag); } } /* end on_to_button_clicked */ /* ----------------------------- * on_framenr_scale_clicked * ----------------------------- */ static gboolean on_framenr_scale_clicked (GtkWidget *widget, GdkEvent *event, GapPlayerMainGlobalParams *gpp) { if(gpp) { if(gap_debug) printf("SCALE CLICKED\n"); if(gpp->play_is_active) { p_stop_playback(gpp); } } return(FALSE); /* event not completely handled, continue calling other handlers */ } /* end on_framenr_scale_clicked */ /* ----------------------------- * on_framenr_spinbutton_changed * ----------------------------- */ static void on_framenr_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp) { gint32 framenr; if(gpp == NULL) { return; } framenr = (gint32)GTK_ADJUSTMENT(gpp->framenr_spinbutton_adj)->value; /* force redraw of the framenr_scale widget * that refers to the framenr_spinbutton_adj adjustment */ gtk_widget_queue_draw(gpp->framenr_scale); if(gpp->play_current_framenr != framenr) { /* force adjustment to the integer value */ GTK_ADJUSTMENT (gpp->framenr_spinbutton_adj)->value = framenr; gpp->play_current_framenr = framenr; if(gpp->play_is_active) { if(gpp->rest_secs < 0.2) { /* currently playing and next update is near, * just set the framenr and let the play_timer do the display render job */ gpp->play_current_framenr = framenr; } else { /* currently playing, but next update not near * render display immediate */ p_display_frame(gpp, framenr); } } else { /* currently not playing, setup a go_timer job to display framenr */ if(gpp->go_timertag >= 0) { g_source_remove(gpp->go_timertag); } gpp->go_job_framenr = framenr; gpp->go_timertag = (gint32) g_timeout_add(8, (GtkFunction)on_timer_go_job, gpp); } p_audio_resync(gpp); /* force audio resync */ } } /* end on_framenr_spinbutton_changed */ /* ----------------------------- * on_origspeed_button_clicked * ----------------------------- */ static void on_origspeed_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if(gpp->speed != gpp->original_speed) { gpp->prev_speed = gpp->speed; gpp->speed = gpp->original_speed; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->speed_spinbutton_adj) , (gfloat)gpp->speed ); } else { if(gpp->original_speed != gpp->prev_speed) { gpp->speed = gpp->prev_speed; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->speed_spinbutton_adj) , (gfloat)gpp->speed ); } } p_audio_resync(gpp); } /* end on_origspeed_button_clicked */ /* ----------------------------- * on_speed_spinbutton_changed * ----------------------------- */ static void on_speed_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } gpp->speed = GTK_ADJUSTMENT(gpp->speed_spinbutton_adj)->value; /* stop audio at speed changes * (audio will restart automatically at next frame with samplerate matching new speed) */ p_audio_resync(gpp); } /* end on_speed_spinbutton_changed */ /* -------------------------- * p_fit_initial_shell_window * -------------------------- */ static void p_fit_initial_shell_window(GapPlayerMainGlobalParams *gpp) { gint width; gint height; if(gpp == NULL) { return; } if(gpp->shell_initial_width < 0) { return; } if(gpp->shell_window == NULL) { return; } width = gpp->shell_initial_width; height = gpp->shell_initial_height; gtk_widget_set_size_request (gpp->shell_window, width, height); /* shrink shell window */ gtk_window_set_default_size(GTK_WINDOW(gpp->shell_window), width, height); /* shrink shell window */ gtk_window_resize (GTK_WINDOW(gpp->shell_window), width, height); /* shrink shell window */ } /* end p_fit_initial_shell_window */ /* --------------------- * p_fit_shell_window * --------------------- */ static void p_fit_shell_window(GapPlayerMainGlobalParams *gpp) { gint width; gint height; if(gpp->shell_window == NULL) { return; } if((gpp->pv_ptr->pv_width <= GAP_STANDARD_PREVIEW_SIZE) && (gpp->pv_ptr->pv_height <= GAP_STANDARD_PREVIEW_SIZE)) { p_fit_initial_shell_window(gpp); return; } /* FIXME: use preview size plus fix offsets (the offsets are just a guess * and may be too small for other languages and/or fonts */ width = MAX(gpp->pv_ptr->pv_width, GAP_STANDARD_PREVIEW_SIZE) + 272; #ifdef GAP_ENABLE_AUDIO_SUPPORT height = MAX(gpp->pv_ptr->pv_height, GAP_STANDARD_PREVIEW_SIZE) + 178; #else height = MAX(gpp->pv_ptr->pv_height, GAP_STANDARD_PREVIEW_SIZE) + 128; #endif gtk_window_set_default_size(GTK_WINDOW(gpp->shell_window), width, height); /* shrink shell window */ gtk_window_resize (GTK_WINDOW(gpp->shell_window), width, height); /* resize shell window */ } /* end p_fit_shell_window */ /* ----------------------------- * on_size_button_button_press_event * ----------------------------- */ static gboolean on_size_button_button_press_event (GtkWidget *widget, GdkEventButton *bevent, GapPlayerMainGlobalParams *gpp) { gboolean fit_initial_flag; if(gap_debug) printf("\nON_SIZE_BUTTON_BUTTON_PRESS_EVENT START\n"); if(gpp == NULL) { return FALSE; } p_disconnect_resize_handler(gpp); fit_initial_flag = TRUE; if ((bevent->state & GDK_SHIFT_MASK) && (bevent->type == GDK_BUTTON_PRESS) && (gpp->ainfo_ptr)) { if(gap_debug) printf("GDK_SHIFT_MASK !!\n\n"); gpp->pv_pixelsize = CLAMP(MAX(gpp->ainfo_ptr->width, gpp->ainfo_ptr->height) , GAP_PLAYER_MIN_SIZE , GAP_PLAYER_MAX_SIZE); fit_initial_flag = FALSE; } else { /* toggle between normal and large thumbnail size */ if(gpp->pv_pixelsize == GAP_STANDARD_PREVIEW_SIZE) { gpp->pv_pixelsize = GAP_SMALL_PREVIEW_SIZE; } else { gpp->pv_pixelsize = GAP_STANDARD_PREVIEW_SIZE; } } if(gpp->pv_pixelsize != (gint32)GTK_ADJUSTMENT(gpp->size_spinbutton_adj)->value) { p_update_pviewsize(gpp); if(!gpp->play_is_active) { p_display_frame(gpp, gpp->play_current_framenr); } } gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->size_spinbutton_adj) , (gfloat)gpp->pv_pixelsize ); if(fit_initial_flag) { p_fit_initial_shell_window(gpp); } else { p_fit_shell_window(gpp); } p_connect_resize_handler(gpp); return FALSE; } /* end on_size_button_button_press_event */ /* ----------------------------- * on_size_spinbutton_changed * ----------------------------- */ static void on_size_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if(gap_debug) { printf("on_size_spinbutton_changed: value: %d pv_pixelsize: %d\n" , (int)GTK_ADJUSTMENT(gpp->size_spinbutton_adj)->value ,(int)gpp->pv_pixelsize ); } if(gpp->pv_pixelsize != (gint32)GTK_ADJUSTMENT(gpp->size_spinbutton_adj)->value) { gpp->pv_pixelsize = (gint32)GTK_ADJUSTMENT(gpp->size_spinbutton_adj)->value; p_update_pviewsize(gpp); if(!gpp->play_is_active) { p_display_frame(gpp, gpp->play_current_framenr); } p_fit_shell_window(gpp); } } /* end on_size_spinbutton_changed */ /* ----------------------------- * on_size_spinbutton_enter * ----------------------------- */ static gboolean on_size_spinbutton_enter (GtkWidget *widget, GdkEvent *event, GapPlayerMainGlobalParams *gpp) { /*if(gap_debug) printf("\n on_size_spinbutton_enter START\n");*/ if(gpp) { p_disconnect_resize_handler(gpp); } return FALSE; } /* end on_size_spinbutton_enter */ /* ----------------------------- * on_shell_window_leave * ----------------------------- */ static gboolean on_shell_window_leave (GtkWidget *widget, GdkEvent *event, GapPlayerMainGlobalParams *gpp) { /*if(gap_debug) printf("\n on_shell_window_leave START\n");*/ if(gpp) { p_connect_resize_handler(gpp); } return FALSE; } /* end on_shell_window_leave */ /* ----------------------------- * on_exact_timing_checkbutton_toggled * ----------------------------- */ static void on_exact_timing_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if (togglebutton->active) { gpp->exact_timing = TRUE; } else { gpp->exact_timing = FALSE; } } /* end on_exact_timing_checkbutton_toggled */ /* ----------------------------- * on_use_thumb_checkbutton_toggled * ----------------------------- */ static void on_use_thumb_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if (togglebutton->active) { gpp->use_thumbnails = TRUE; } else { gpp->use_thumbnails = FALSE; } } /* end on_use_thumb_checkbutton_toggled */ /* ----------------------------- * on_pinpong_checkbutton_toggled * ----------------------------- */ static void on_pinpong_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if (togglebutton->active) { gpp->play_pingpong = TRUE; } else { gpp->play_pingpong = FALSE; } } /* end on_pinpong_checkbutton_toggled */ /* ----------------------------- * on_selonly_checkbutton_toggled * ----------------------------- */ static void on_selonly_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if (togglebutton->active) { gpp->play_selection_only = TRUE; } else { gpp->play_selection_only = FALSE; } } /* end on_selonly_checkbutton_toggled */ /* ----------------------------- * on_loop_checkbutton_toggled * ----------------------------- */ static void on_loop_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if (togglebutton->active) { gpp->play_loop = TRUE; } else { gpp->play_loop = FALSE; } } /* end on_loop_checkbutton_toggled */ /* ------------------------------------- * on_show_gobuttons_checkbutton_toggled * ------------------------------------- */ static void on_show_gobuttons_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if (togglebutton->active) { gpp->show_go_buttons = TRUE; gtk_widget_show(gpp->gobutton_hbox); } else { gpp->show_go_buttons = FALSE; gtk_widget_hide(gpp->gobutton_hbox); } } /* end on_show_gobuttons_checkbutton_toggled */ /* ----------------------------------------- * on_show_positionscale_checkbutton_toggled * ----------------------------------------- */ static void on_show_positionscale_checkbutton_toggled(GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if (togglebutton->active) { gpp->show_position_scale = TRUE; gtk_widget_show(gpp->frame_scale_hbox); } else { gpp->show_position_scale = FALSE; gtk_widget_hide(gpp->frame_scale_hbox); } } /* end on_show_positionscale_checkbutton_toggled */ /* ----------------------------- * on_close_button_clicked * ----------------------------- */ static void on_close_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } p_stop_playback(gpp); if(gpp->gva_lock) { gpp->request_cancel_video_api = TRUE; return; } if(gpp->audio_tmp_dialog_is_open) { /* ignore close as long as sub dialog is open */ return; } gtk_widget_destroy (GTK_WIDGET (gpp->shell_window)); /* close & destroy dialog window */ if(gpp->standalone_mode) { gtk_main_quit (); } } /* end on_close_button_clicked */ /* ----------------------------- * on_shell_window_destroy * ----------------------------- */ static void on_shell_window_destroy (GtkObject *object, GapPlayerMainGlobalParams *gpp) { if(gpp) { p_stop_playback(gpp); } gpp->shell_window = NULL; p_close_videofile(gpp); p_close_composite_storyboard(gpp); if(gpp->standalone_mode) { gtk_main_quit (); } } /* end on_shell_window_destroy */ /* ----------------------------- * on_go_button_clicked * ----------------------------- */ static void on_go_button_clicked (GtkButton *button, GdkEventButton *bevent, t_gobutton *gob) { GapPlayerMainGlobalParams *gpp; gint32 framenr; if(gob == NULL) { return; } gpp = gob->gpp; if(gpp == NULL) { return; } /*if (gap_debug) printf("on_go_button_clicked: go_number:%d\n", (int)gob->go_number );*/ p_stop_playback(gpp); framenr = p_framenr_from_go_number(gpp, gob->go_number); if(gpp->play_current_framenr != framenr) { p_display_frame(gpp, framenr); } if(bevent->type == GDK_BUTTON_PRESS) { if(bevent->state & GDK_CONTROL_MASK) { gpp->begin_frame = framenr; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->from_spinbutton_adj) , (gfloat)gpp->begin_frame ); if(gpp->begin_frame > gpp->end_frame) { gpp->end_frame = gpp->begin_frame; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->to_spinbutton_adj) , (gfloat)gpp->end_frame ); } return; } if(bevent->state & GDK_MOD1_MASK) /* ALT modifier Key */ { gpp->end_frame = framenr; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->to_spinbutton_adj) , (gfloat)gpp->end_frame ); if(gpp->end_frame < gpp->begin_frame) { gpp->begin_frame = gpp->end_frame; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->from_spinbutton_adj) , (gfloat)gpp->begin_frame ); } return; } } if(framenr != gpp->ainfo_ptr->curr_frame_nr) { on_framenr_button_clicked(NULL, NULL, gpp); } } /* end on_go_button_clicked */ /* ----------------------------- * on_go_button_enter * ----------------------------- */ static gboolean on_go_button_enter (GtkButton *button, GdkEvent *event, t_gobutton *gob) { GapPlayerMainGlobalParams *gpp; gint32 framenr; if(gob == NULL) { return FALSE; } gpp = gob->gpp; if(gpp == NULL) { return FALSE; } /*if (gap_debug) printf("ON_GO_BUTTON_ENTER: go_number:%d\n", (int)gob->go_number ); */ p_stop_playback(gpp); /* skip display on full sized image mode * (gui cant follow that fast on many machines, and would react slow) */ /*if(gpp->use_thumbnails) */ { framenr = p_framenr_from_go_number(gpp, gob->go_number); if(gpp->play_current_framenr != framenr) { if(gap_debug) { if(gpp->go_timertag >= 0) { if(gap_debug) printf("on_go_button_enter: DROP GO_FRAMENR: %d\n", (int)gpp->go_job_framenr); } } /* we want the go_timer to display that framenr */ gpp->go_job_framenr = framenr; if(gpp->go_timertag < 0) { /* if the go_timer is not already prepared to fire * we start p_display_frame(gpp, gpp->go_job_framenr); * after minimal delay of 8 millisecods. */ gpp->go_timertag = (gint32) g_timeout_add(8, (GtkFunction)on_timer_go_job, gpp); } } } return FALSE; } /* end on_go_button_enter */ /* ----------------------------- * on_gobutton_hbox_leave * ----------------------------- */ static void on_gobutton_hbox_leave (GtkWidget *widget, GdkEvent *event, GapPlayerMainGlobalParams *gpp) { /*if (gap_debug) printf("ON_GOBUTTON_HBOX_LEAVE\n");*/ if(gpp == NULL) { return; } /* reset go_base */ gpp->go_base_framenr = -1; gpp->go_base = -1; p_check_tooltips(); } /* end on_gobutton_hbox_leave */ /* ----------------------------------- * on_audio_enable_checkbutton_toggled * ----------------------------------- */ static void on_audio_enable_checkbutton_toggled (GtkToggleButton *togglebutton, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if (togglebutton->active) { gpp->audio_enable = TRUE; /* audio will start automatic at next frame when playback is running */ } else { gpp->audio_enable = FALSE; gpp->audio_resync = 0; p_audio_stop(gpp); } } /* end on_audio_enable_checkbutton_toggled */ /* ----------------------------- * on_audio_volume_spinbutton_changed * ----------------------------- */ static void on_audio_volume_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if(gpp->audio_volume != (gdouble)GTK_ADJUSTMENT(gpp->audio_volume_spinbutton_adj)->value) { gpp->audio_volume = (gdouble)GTK_ADJUSTMENT(gpp->audio_volume_spinbutton_adj)->value; #ifdef GAP_ENABLE_AUDIO_SUPPORT if(gpp->audio_status >= GAP_PLAYER_MAIN_AUSTAT_PLAYING) { apcl_volume(gpp->audio_volume, 0, p_audio_errfunc); } #endif } } /* end on_audio_volume_spinbutton_changed */ /* ----------------------------------------- * on_audio_frame_offset_spinbutton_changed * ----------------------------------------- */ static void on_audio_frame_offset_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if(gpp->audio_frame_offset != (gint32)GTK_ADJUSTMENT(gpp->audio_frame_offset_spinbutton_adj)->value) { gpp->audio_frame_offset = (gint32)GTK_ADJUSTMENT(gpp->audio_frame_offset_spinbutton_adj)->value; /* resync audio will cause an automatic restart respecting te new audio_offset value */ p_audio_resync(gpp); p_audio_print_labels(gpp); } } /* end on_audio_frame_offset_spinbutton_changed */ /* ----------------------------------------- * on_audio_reset_button_clicked * ----------------------------------------- */ static void on_audio_reset_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } gpp->audio_frame_offset = 0; gpp->audio_volume = 1.0; gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->audio_frame_offset_spinbutton_adj) , (gfloat)gpp->audio_frame_offset ); gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->audio_volume_spinbutton_adj) , (gfloat)gpp->audio_volume ); /* resync audio (for the case its already playing this * will cause an automatic restart respecting te new audio_offset value */ p_audio_resync(gpp); p_audio_print_labels(gpp); } /* end on_audio_reset_button_clicked */ /* ----------------------------------------- * on_audio_create_copy_button_clicked * ----------------------------------------- */ static void on_audio_create_copy_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp) { #ifdef GAP_ENABLE_AUDIO_SUPPORT const char *cp; char *envAUDIOCONVERT_TO_WAV; gboolean script_found; gboolean use_newly_created_wavfile; if(gpp == NULL) { return; } if(gpp->audio_tmp_dialog_is_open) { return; } script_found = FALSE; use_newly_created_wavfile = FALSE; envAUDIOCONVERT_TO_WAV = g_strdup(" "); /* check gimprc for the audioconvert_program */ if ( (cp = gimp_gimprc_query("audioconvert_program")) != NULL ) { g_free(envAUDIOCONVERT_TO_WAV); envAUDIOCONVERT_TO_WAV = g_strdup(cp); if(g_file_test (envAUDIOCONVERT_TO_WAV, G_FILE_TEST_IS_EXECUTABLE) ) { script_found = TRUE; } else { g_message(_("WARNING: Your gimprc file configuration for the audioconverter script\n" "does not point to an executable program\n" "the configured value for %s is: %s\n") , "audioconvert_program" , envAUDIOCONVERT_TO_WAV ); } } /* check environment variable for the audioconvert_program */ if(!script_found) { if ( (cp = g_getenv("AUDIOCONVERT_TO_WAV")) != NULL ) { g_free(envAUDIOCONVERT_TO_WAV); envAUDIOCONVERT_TO_WAV = g_strdup(cp); /* Environment overrides compiled in default for WAVPLAYPATH */ if(g_file_test (env_WAVPLAYPATH, G_FILE_TEST_IS_EXECUTABLE) ) { script_found = TRUE; } else { g_message(_("WARNING: The environment variable %s\n" "does not point to an executable program\n" "the current value is: %s\n") , "AUDIOCONVERT_TO_WAV" , envAUDIOCONVERT_TO_WAV ); } } } if(!script_found) { g_free(envAUDIOCONVERT_TO_WAV); envAUDIOCONVERT_TO_WAV = g_build_filename(GAPLIBDIR , "audioconvert_to_wav.sh" , NULL ); if(!g_file_test(envAUDIOCONVERT_TO_WAV, G_FILE_TEST_IS_EXECUTABLE)) { g_message(_("ERROR: The external program for audioconversion is not executable.\n" "Filename: '%s'\n") , envAUDIOCONVERT_TO_WAV ); return; } script_found = TRUE; } gpp->audio_tmp_dialog_is_open = TRUE; if(p_create_wav_dialog(gpp)) { gint l_rc; gchar *l_cmd; gchar *l_resample_params; printf("CREATE WAVFILE as %s\n" " in progress ***\n" ,gpp->audio_wavfile_tmp ); gtk_label_set_text ( GTK_LABEL(gpp->audio_status_label), _("Creating audiofile - please wait")); gtk_widget_hide(gpp->audio_table); gtk_widget_show(gpp->audio_status_label); while (gtk_events_pending ()) { gtk_main_iteration (); } if(gpp->audio_tmp_resample) { l_resample_params = g_strdup_printf("--resample %d" , (int)gpp->audio_tmp_samplerate ); } else { l_resample_params = g_strdup(" "); /* do not resample */ } if(g_file_test(gpp->audio_wavfile_tmp, G_FILE_TEST_EXISTS)) { g_remove(gpp->audio_wavfile_tmp); } l_cmd = g_strdup_printf("%s --in \"%s\" --out \"%s\" %s" , envAUDIOCONVERT_TO_WAV , gpp->audio_filename , gpp->audio_wavfile_tmp , l_resample_params ); /* CALL the external audioconverter Program */ l_rc = system(l_cmd); if (l_rc != 0) { printf("extern audioconverter FAILED. cmd:%s\n", l_cmd); g_message(_("external audioconverter FAILED.")); p_msg_progress_bar_audio(gpp, _("extern audioconverter FAILED")); } g_free(l_cmd); g_free(l_resample_params); /* if the external converter created the wavfile * then use the newly created wavfile */ if(g_file_test(gpp->audio_wavfile_tmp, G_FILE_TEST_EXISTS)) { use_newly_created_wavfile = TRUE; } } g_free(envAUDIOCONVERT_TO_WAV); gpp->audio_tmp_dialog_is_open = FALSE; gtk_label_set_text ( GTK_LABEL(gpp->audio_status_label), " "); gtk_widget_hide(gpp->audio_status_label); gtk_widget_show(gpp->audio_table); if(use_newly_created_wavfile) { gtk_entry_set_text(GTK_ENTRY(gpp->audio_filename_entry), gpp->audio_wavfile_tmp); } #endif return; } /* end on_audio_create_copy_button_clicked */ /* ----------------------------------------- * on_audio_filename_entry_changed * ----------------------------------------- */ static void on_audio_filename_entry_changed (GtkWidget *widget, GapPlayerMainGlobalParams *gpp) { gboolean has_changed; if(gpp == NULL) { return; } has_changed = TRUE; if (gpp->audio_filename) { if(gap_debug) { printf("\non_audio_filename_entry_changed\n"); printf(" ()) gpp->audio_filename:%s\n" , gpp->audio_filename); printf(" ()) gtk_entry_get_text:%s\n" , gtk_entry_get_text(GTK_ENTRY(gpp->audio_filename_entry))); } if (gtk_entry_get_text(GTK_ENTRY(gpp->audio_filename_entry)) != NULL) { if (strcmp(gpp->audio_filename, gtk_entry_get_text(GTK_ENTRY(gpp->audio_filename_entry))) == 0) { has_changed = FALSE; } } } g_snprintf(gpp->audio_filename, sizeof(gpp->audio_filename), "%s" , gtk_entry_get_text(GTK_ENTRY(gpp->audio_filename_entry)) ); p_audio_filename_changed(gpp); if(has_changed == TRUE) { p_reset_progress_bar_audio(gpp); } } /* end on_audio_filename_entry_changed */ /* -------------------------- * AUDIO_FILESEL * -------------------------- */ static void on_audio_filesel_close_cb(GtkWidget *widget, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if(gpp->audio_filesel == NULL) { gtk_window_present(GTK_WINDOW(gpp->audio_filesel)); return; /* filesel is already closed */ } gtk_widget_destroy(GTK_WIDGET(gpp->audio_filesel)); gpp->audio_filesel = NULL; } /* end on_audio_filesel_close_cb */ static void on_audio_filesel_ok_cb(GtkWidget *widget, GapPlayerMainGlobalParams *gpp) { const gchar *filename; if(gpp == NULL) { return; } if(gpp->audio_filesel == NULL) { return; /* filesel is already closed */ } filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (gpp->audio_filesel)); if(filename) { if(*filename != '\0') { gtk_entry_set_text(GTK_ENTRY(gpp->audio_filename_entry), filename); } } on_audio_filesel_close_cb(widget, gpp); } /* end on_audio_filesel_ok_cb */ /* ----------------------------------------- * on_audio_filesel_button_clicked * ----------------------------------------- */ static void on_audio_filesel_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } if(gpp->audio_filesel) { gtk_window_present(GTK_WINDOW(gpp->audio_filesel)); return; /* filesection dialog is already open */ } gpp->audio_filesel = gtk_file_selection_new (_("Select Audiofile")); gtk_window_set_position (GTK_WINDOW (gpp->audio_filesel), GTK_WIN_POS_MOUSE); gtk_file_selection_set_filename (GTK_FILE_SELECTION (gpp->audio_filesel), gpp->audio_filename); gtk_widget_show (gpp->audio_filesel); g_signal_connect (G_OBJECT (gpp->audio_filesel), "destroy", G_CALLBACK (on_audio_filesel_close_cb), gpp); g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (gpp->audio_filesel)->ok_button), "clicked", G_CALLBACK (on_audio_filesel_ok_cb), gpp); g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (gpp->audio_filesel)->cancel_button), "clicked", G_CALLBACK (on_audio_filesel_close_cb), gpp); } /* end on_audio_filesel_button_clicked */ /* ----------------------------- * p_new_audioframe * ----------------------------- * create widgets for the audio options */ static GtkWidget * p_new_audioframe(GapPlayerMainGlobalParams *gpp) { GtkWidget *frame0a; GtkWidget *hseparator; GtkWidget *label; GtkWidget *vbox1; GtkWidget *table1; GtkWidget *entry; GtkWidget *button; GtkWidget *check_button; GtkWidget *spinbutton; GtkWidget *progress_bar; GtkObject *adj; gint row; if (gap_debug) printf("p_new_audioframe\n"); frame0a = gimp_frame_new ("Audio Playback Settings"); /* the vbox */ vbox1 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox1); gtk_container_add (GTK_CONTAINER (frame0a), vbox1); /* table */ table1 = gtk_table_new (14, 3, FALSE); gpp->audio_table = table1; gtk_widget_show (table1); gtk_box_pack_start (GTK_BOX (vbox1), table1, TRUE, TRUE, 0); gtk_table_set_row_spacings (GTK_TABLE (table1), 4); gtk_table_set_col_spacings (GTK_TABLE (table1), 4); /* status label */ label = gtk_label_new(" "); gpp->audio_status_label = label; gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (vbox1), label, TRUE, TRUE, 0); gtk_widget_hide(label); row = 0; /* audiofile label */ label = gtk_label_new (_("Audiofile:")); gtk_widget_show (label); gtk_table_attach (GTK_TABLE (table1), label, 0, 1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /*gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);*/ /* right alligned */ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); /* left alligned */ /* audiofile entry */ entry = gtk_entry_new(); gpp->audio_filename_entry = entry; gtk_widget_show (entry); gimp_help_set_help_data(entry, _("Enter an audiofile. The file must be in RIFF WAVE fileformat."),NULL); if(gpp->docking_container) { gtk_widget_set_size_request(entry, GAP_PLAY_AUDIO_ENTRY_WIDTH_DOCKED, -1); } else { gtk_widget_set_size_request(entry, GAP_PLAY_AUDIO_ENTRY_WIDTH, -1); } gtk_entry_set_text(GTK_ENTRY(entry), gpp->audio_filename); gtk_table_attach(GTK_TABLE(table1), entry, 1, 2, row, row + 1, (GtkAttachOptions) GTK_FILL | GTK_EXPAND | GTK_SHRINK, (GtkAttachOptions) GTK_FILL, 4, 0); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK (on_audio_filename_entry_changed), gpp); /* audiofile button (fileselect invoker) */ button = gtk_button_new_with_label ( "..."); gtk_widget_show (button); gimp_help_set_help_data(button, _("Open audiofile selection browser dialog window"),NULL); gtk_table_attach(GTK_TABLE(table1), button, 2, 3, row, row + 1, (GtkAttachOptions) GTK_FILL, (GtkAttachOptions) GTK_FILL, 4, 0); g_signal_connect (G_OBJECT (button), "pressed", G_CALLBACK (on_audio_filesel_button_clicked), gpp); row++; /* Volume */ label = gtk_label_new(_("Volume:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); /* volume spinutton */ spinbutton = gimp_spin_button_new (&adj, /* return value */ gpp->audio_volume, /* initial_val */ 0.0, /* umin */ 1.0, /* umax */ 0.01, /* sstep */ 0.1, /* pagestep */ 0.0, /* page_size */ 0.1, /* climb_rate */ 2 /* digits */ ); gtk_widget_show (spinbutton); /*gtk_widget_set_sensitive(spinbutton, FALSE);*/ /* VOLUME CONTROL NOT IMPLEMENTED YET !!! */ gpp->audio_volume_spinbutton_adj = adj; gtk_table_attach(GTK_TABLE(table1), spinbutton, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); gimp_help_set_help_data(spinbutton, _("Audio Volume"),NULL); g_signal_connect (G_OBJECT (gpp->audio_volume_spinbutton_adj), "value_changed", G_CALLBACK (on_audio_volume_spinbutton_changed), gpp); /* check button */ check_button = gtk_check_button_new_with_label (_("Enable")); gpp->audio_enable_checkbutton = check_button; gtk_table_attach ( GTK_TABLE (table1), check_button, 2, 3, row, row+1, GTK_FILL, 0, 0, 0); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), gpp->audio_enable); gimp_help_set_help_data(check_button, _("ON: Play button plays video + audio.\n" "OFF: Play video silently"),NULL); gtk_widget_show (check_button); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_audio_enable_checkbutton_toggled), gpp); row++; /* Sample Offset */ label = gtk_label_new(_("Offset:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); /* offset spinutton */ spinbutton = gimp_spin_button_new (&adj, /* return value */ gpp->audio_frame_offset, /* initial_val */ -500000, /* umin */ 500000, /* umax */ 1.0, /* sstep */ 100, /* pagestep */ 0, /* page_size */ 1, /* climb_rate */ 0 /* digits */ ); gtk_widget_show (spinbutton); gpp->audio_frame_offset_spinbutton_adj = adj; gtk_table_attach(GTK_TABLE(table1), spinbutton, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); gimp_help_set_help_data(spinbutton , _("Audio offset in frames at original video playback speed. " "A value of 0 starts audio and video at synchron time. " "A value of -10 will play frame 1 up to frame 9 silently " "and start audio at frame 10. " "A value of 10 starts audio at frame 1, " "but skips the audio begin part in a length that is " "equal to the duration of 10 frames " "at original video playback speed.") ,NULL); g_signal_connect (G_OBJECT (gpp->audio_frame_offset_spinbutton_adj), "value_changed", G_CALLBACK (on_audio_frame_offset_spinbutton_changed), gpp); /* check button */ check_button = gtk_check_button_new_with_label (_("original audio")); gpp->audio_auto_offset_by_framenr_checkbutton = check_button; gtk_table_attach ( GTK_TABLE (table1), check_button, 2, 3, row, row+1, GTK_FILL, 0, 0, 0); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), gpp->audio_auto_offset_by_framenr); gimp_help_set_help_data(check_button, _("ON: for video clip playback sync audio startposition according" " to original position in the referenced video." " Use this option if the audiofile is an extracted audiotrack" " of the full referenced videofile\n" "OFF: do not sync audio with original position in the referenced videos." " Use this for independent audiofile playback.") ,NULL); gtk_widget_show (check_button); g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_audio_auto_offset_checkbutton_toggled), gpp); row++; /* Sample Offset */ label = gtk_label_new(_("Audiotrack:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); /* create the audio_otone_atrack_spinbutton spinutton */ spinbutton = gimp_spin_button_new (&adj, /* return value */ 1, /* initial_val */ 0.0, /* umin */ 10.0, /* umax */ 1.0, /* sstep */ 1.0, /* pagestep */ 0.0, /* page_size */ 1.0, /* climb_rate */ 0 /* digits */ ); gtk_widget_show (spinbutton); gpp->audio_otone_atrack_spinbutton_adj = adj; gpp->audio_otone_atrack_spinbutton = spinbutton; gtk_table_attach(GTK_TABLE(table1), spinbutton, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); gimp_help_set_help_data(spinbutton, _("Audio Track"),NULL); g_signal_connect (G_OBJECT (gpp->audio_volume_spinbutton_adj), "value_changed", G_CALLBACK (on_audio_otone_atrack_spinbutton_changed), gpp); /* create extract audio otone track button */ button = gtk_button_new_with_label(_("Extract Audio")); gpp->audio_otone_extract_button = button; gtk_widget_show (button); gimp_help_set_help_data(button, _("Extract Audio Track from videofile " "for the current videofile and use it for origial audiotrack playback") ,NULL); gtk_table_attach(GTK_TABLE(table1), button, 2, 3, row, row + 1, (GtkAttachOptions) GTK_FILL, (GtkAttachOptions) GTK_FILL, 4, 0); g_signal_connect (G_OBJECT (button), "pressed", G_CALLBACK (on_audio_otone_extract_button_clicked), gpp); row++; /* create wavfile button */ button = gtk_button_new_with_label(_("Copy As Wavfile")); gtk_widget_show (button); gimp_help_set_help_data(button, _("Create a copy from audiofile as RIFF WAVE audiofile " "and use the copy for audio playback"),NULL); gtk_table_attach(GTK_TABLE(table1), button, 1, 2, row, row + 1, (GtkAttachOptions) GTK_FILL, (GtkAttachOptions) GTK_FILL, 4, 0); g_signal_connect (G_OBJECT (button), "pressed", G_CALLBACK (on_audio_create_copy_button_clicked), gpp); /* reset button */ button = gtk_button_new_from_stock (GIMP_STOCK_RESET); gtk_widget_show (button); gimp_help_set_help_data(button, _("Reset offset and volume"),NULL); gtk_table_attach(GTK_TABLE(table1), button, 2, 3, row, row + 1, (GtkAttachOptions) GTK_FILL, (GtkAttachOptions) GTK_FILL, 4, 0); g_signal_connect (G_OBJECT (button), "pressed", G_CALLBACK (on_audio_reset_button_clicked), gpp); row++; /* create the audio extract progressbar */ progress_bar = gtk_progress_bar_new (); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress_bar), " "); gtk_widget_show (progress_bar); gtk_table_attach (GTK_TABLE (table1), progress_bar, 1, 3, row, row+1, (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), (GtkAttachOptions) (GTK_FILL), 4, 0); gpp->progress_bar_audio = progress_bar; row++; hseparator = gtk_hseparator_new (); gtk_widget_show (hseparator); gtk_table_attach(GTK_TABLE(table1), hseparator, 0, 3, row, row + 1, (GtkAttachOptions) GTK_FILL, (GtkAttachOptions) GTK_FILL, 0, 0); row++; /* Audio Offset Length (mm:ss:msec) */ label = gtk_label_new(_("Offsettime:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); label = gtk_label_new("mm:ss:msec"); gpp->audio_offset_time_label = label; gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); row++; /* Total Audio Length (mm:ss:msec) */ label = gtk_label_new(_("Audiotime:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); label = gtk_label_new("mm:ss:msec"); gpp->audio_total_time_label = label; gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); row++; /* Length (frames) */ label = gtk_label_new(_("Audioframes:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); label = gtk_label_new("####"); gpp->audio_total_frames_label = label; gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); row++; /* Audiolength (Samples) */ label = gtk_label_new(_("Samples:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); label = gtk_label_new("######"); gpp->audio_samples_label = label; gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); row++; /* Audio Samplerate */ label = gtk_label_new(_("Samplerate:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); label = gtk_label_new("######"); gpp->audio_samplerate_label = label; gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); row++; /* Audio Channels */ label = gtk_label_new(_("Channels:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); label = gtk_label_new("#"); gpp->audio_channels_label = label; gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); row++; /* Bits per Audio Sample */ label = gtk_label_new(_("Bits/Sample:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); label = gtk_label_new("##"); gpp->audio_bits_label = label; gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); row++; /* Total Video Length (mm:ss:msec) */ label = gtk_label_new(_("Videotime:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); label = gtk_label_new("mm:ss:msec"); gpp->video_total_time_label = label; gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); row++; /* Video Length (frames) */ label = gtk_label_new(_("Videoframes:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); label = gtk_label_new("000000"); gpp->video_total_frames_label = label; gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); return(frame0a); } /* end p_new_audioframe */ /* ----------------------------------------- * p_update_cache_status * ----------------------------------------- */ static void p_update_cache_status (GapPlayerMainGlobalParams *gpp) { static char status_txt[50]; gint32 elem_counter; gint32 bytes_used; gint32 max_bytes; elem_counter = gap_player_cache_get_current_frames_cached(); bytes_used = gap_player_cache_get_current_bytes_used(); max_bytes = gap_player_cache_get_max_bytesize(); g_snprintf(status_txt, sizeof(status_txt), "%d", (int)elem_counter); gtk_label_set_text ( GTK_LABEL(gpp->label_current_cache_values) , status_txt); if(gpp->progress_bar_cache_usage) { float mb_used; gdouble progress; mb_used = (float)bytes_used / (1024.0 * 1024.0); progress = (gdouble)bytes_used / MAX((gdouble)max_bytes, 1.0); g_snprintf(status_txt, sizeof(status_txt), "%.4f MB", mb_used); if(gap_debug) { printf("p_update_cache_status: bytes_used:%d max_bytes:%d, max_player_cache:%d progress:%f\n" , (int)bytes_used , (int)max_bytes , (int)gpp->max_player_cache , (float)progress ); } gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gpp->progress_bar_cache_usage) , CLAMP(progress, 0.0, 1.0)); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(gpp->progress_bar_cache_usage) , status_txt); } } /* end p_update_cache_status */ /* ----------------------------------------- * on_cache_size_spinbutton_changed * ----------------------------------------- */ static void on_cache_size_spinbutton_changed (GtkEditable *editable, GapPlayerMainGlobalParams *gpp) { gdouble mb_chachesize; gdouble bytesize; if(gpp == NULL) { return; } mb_chachesize = GTK_ADJUSTMENT(gpp->cache_size_spinbutton_adj)->value; bytesize = mb_chachesize * (1024.0 * 1024.0); if(gpp->max_player_cache != (gint32)bytesize) { gpp->max_player_cache = (gint32)bytesize; if(gap_debug) { printf("on_cache_size_spinbutton_changed: max_player_cache:%d\n" , (int) gpp->max_player_cache ); } gap_player_cache_set_max_bytesize(gpp->max_player_cache); p_update_cache_status(gpp); } } /* end on_cache_size_spinbutton_changed */ /* ----------------------------------------- * on_cache_clear_button_clicked * ----------------------------------------- */ static void on_cache_clear_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } gap_player_cache_free_all(); p_update_cache_status(gpp); } /* end on_cache_clear_button_clicked */ /* ----------------------------------------- * p_gimprc_save_boolen_option * ----------------------------------------- */ static void p_gimprc_save_boolen_option (const char *option_name, gboolean value) { if(value) { gimp_gimprc_set(option_name, "yes"); } else { gimp_gimprc_set(option_name, "no"); } } /* end p_gimprc_save_boolen_option */ /* ----------------------------------------- * on_prefs_save_gimprc_button_clicked * ----------------------------------------- */ static void on_prefs_save_gimprc_button_clicked (GtkButton *button, GapPlayerMainGlobalParams *gpp) { if(gpp == NULL) { return; } gap_player_cache_set_gimprc_bytesize(gpp->max_player_cache); p_gimprc_save_boolen_option("video_player_show_go_buttons" ,gpp->show_go_buttons); p_gimprc_save_boolen_option("video_player_show_position_scale" ,gpp->show_position_scale); } /* end on_prefs_save_gimprc_button_clicked */ /* ----------------------------- * p_new_configframe * ----------------------------- * create widgets for the audio options */ static GtkWidget * p_new_configframe(GapPlayerMainGlobalParams *gpp) { GtkWidget *frame0c; GtkWidget *label; GtkWidget *vbox1; GtkWidget *table1; GtkWidget *button; GtkWidget *progress_bar; GtkWidget *spinbutton; GtkWidget *checkbutton; GtkObject *adj; gint row; if (gap_debug) printf("p_new_configframe\n"); frame0c = gimp_frame_new ("Playback Preferences"); /* the vbox */ vbox1 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox1); gtk_container_add (GTK_CONTAINER (frame0c), vbox1); /* table */ table1 = gtk_table_new (14, 3, FALSE); gpp->audio_table = table1; gtk_widget_show (table1); gtk_box_pack_start (GTK_BOX (vbox1), table1, TRUE, TRUE, 0); gtk_table_set_row_spacings (GTK_TABLE (table1), 4); gtk_table_set_col_spacings (GTK_TABLE (table1), 4); row = 0; /* Cahe size label */ label = gtk_label_new (_("Cache Size (MB):")); gtk_widget_show (label); gtk_table_attach (GTK_TABLE (table1), label, 0, 1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); /* left alligned */ { gdouble mb_cachesize; mb_cachesize = (gdouble)gpp->max_player_cache / (1024.0 * 1024.0); /* frame cache size spinutton */ spinbutton = gimp_spin_button_new (&adj, /* return value */ mb_cachesize, /* initial_val */ 0.0, /* umin */ 9000.0, /* umax */ 1.0, /* sstep */ 10.0, /* pagestep */ 0.0, /* page_size */ 10.0, /* climb_rate */ 4 /* digits */ ); gtk_widget_show (spinbutton); gpp->cache_size_spinbutton_adj = adj; gtk_table_attach(GTK_TABLE(table1), spinbutton, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); gimp_help_set_help_data(spinbutton, _("Player frame cache maximum size in MB. Value 0 turns the cache off."),NULL); g_signal_connect (G_OBJECT (gpp->cache_size_spinbutton_adj), "value_changed", G_CALLBACK (on_cache_size_spinbutton_changed), gpp); } /* clear player frame cache button */ button = gtk_button_new_from_stock (GIMP_STOCK_RESET); gtk_widget_show (button); gimp_help_set_help_data(button, _("Clear the frame cache"),NULL); gtk_table_attach(GTK_TABLE(table1), button, 2, 3, row, row + 1, (GtkAttachOptions) GTK_FILL, (GtkAttachOptions) GTK_FILL, 4, 0); g_signal_connect (G_OBJECT (button), "pressed", G_CALLBACK (on_cache_clear_button_clicked), gpp); row++; /* Chache Status (number of frames currently in the cache) */ label = gtk_label_new(_("Cached Frames:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); /* current number of frames in the player cache */ label = gtk_label_new("0"); gpp->label_current_cache_values = label; gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table1), label, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); gtk_widget_show(label); /* cache usage percentage progressbar */ progress_bar = gtk_progress_bar_new (); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress_bar), " "); gtk_widget_show (progress_bar); gtk_table_attach (GTK_TABLE (table1), progress_bar, 2, 3, row, row+1, (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), (GtkAttachOptions) (GTK_FILL), 4, 0); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress_bar), "0.0 MB"); gpp->progress_bar_cache_usage = progress_bar; row++; /* Layout Options label */ label = gtk_label_new (_("Layout Options:")); gtk_widget_show (label); gtk_table_attach (GTK_TABLE (table1), label, 0, 1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); /* left alligned */ row++; /* Show Go button array (configure to show/hide this optional positioning tool) */ checkbutton = gtk_check_button_new_with_label (_("Show Button Array")); gpp->show_go_buttons_checkbutton = checkbutton; gtk_widget_show (checkbutton); gtk_table_attach (GTK_TABLE (table1), checkbutton, 1, 3, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (checkbutton, _("ON: Show the go button array positioning tool.\n" "OFF: Hide the go button array."), NULL); if(gpp->show_go_buttons) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), TRUE); } g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (on_show_gobuttons_checkbutton_toggled), gpp); row++; /* Show Position Scale (configure to show/hide this optional positioning tool) */ checkbutton = gtk_check_button_new_with_label (_("Show Position Scale")); gpp->show_position_scale_checkbutton = checkbutton; gtk_widget_show (checkbutton); gtk_table_attach (GTK_TABLE (table1), checkbutton, 1, 3, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (checkbutton, _("ON: Show the position scale.\n" "OFF: Hide the position scale."), NULL); if(gpp->show_position_scale) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), TRUE); } g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (on_show_positionscale_checkbutton_toggled), gpp); row++; /* Save Player Preferences label */ label = gtk_label_new (_("Save Preferences:")); gtk_widget_show (label); gtk_table_attach (GTK_TABLE (table1), label, 0, 1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); /* left alligned */ /* save player frame cache settings to gimprc */ button = gtk_button_new_from_stock (GTK_STOCK_SAVE); gtk_widget_show (button); gimp_help_set_help_data(button, _("Save player cache and layout settings (as gimprc parameters)"),NULL); gtk_table_attach(GTK_TABLE(table1), button, 1, 2, row, row + 1, (GtkAttachOptions) GTK_FILL, (GtkAttachOptions) GTK_FILL, 4, 0); g_signal_connect (G_OBJECT (button), "pressed", G_CALLBACK (on_prefs_save_gimprc_button_clicked), gpp); return(frame0c); } /* end p_new_configframe */ /* ----------------------------- * p_create_player_window * ----------------------------- */ GtkWidget* p_create_player_window (GapPlayerMainGlobalParams *gpp) { GtkWidget *shell_window; GtkWidget *event_box; GtkWidget *frame0; GtkWidget *aspect_frame; GtkWidget *frame2; GtkWidget *vbox0; GtkWidget *vbox1; GtkWidget *hbox1; GtkWidget *play_n_stop_hbox; GtkWidget *gobutton_hbox; GtkWidget *table1; GtkWidget *table11; GtkWidget *table2; GtkWidget *vid_preview; GtkWidget *status_label; GtkWidget *timepos_label; GtkWidget *label; GtkObject *from_spinbutton_adj; GtkWidget *from_spinbutton; GtkObject *to_spinbutton_adj; GtkWidget *to_spinbutton; GtkObject *framenr_spinbutton_adj; GtkWidget *framenr_spinbutton; GtkWidget *framenr_scale; GtkObject *speed_spinbutton_adj; GtkWidget *speed_spinbutton; GtkObject *size_spinbutton_adj; GtkWidget *size_spinbutton; GtkWidget *cancel_vindex_button; GtkWidget *play_button; GtkWidget *pause_button; GtkWidget *back_button; GtkWidget *close_button; GtkWidget *origspeed_button; GtkWidget *size_button; GtkWidget *framenr_1_button; GtkWidget *framenr_2_button; GtkWidget *from_button; GtkWidget *to_button; GtkWidget *progress_bar; GtkWidget *use_thumb_checkbutton; GtkWidget *exact_timing_checkbutton; GtkWidget *pinpong_checkbutton; GtkWidget *selonly_checkbutton; GtkWidget *loop_checkbutton; GtkWidget *spc_hbox0; GtkWidget *spc_label; GtkWidget *notebook; GtkWidget *label_vid; GtkWidget *label_cfg; GtkWidget *frame0c; GtkWidget *spc_hbox0c; #ifdef GAP_ENABLE_AUDIO_SUPPORT GtkWidget *frame0a; GtkWidget *spc_hbox0a; GtkWidget *label_aud; #endif GtkWidget *frame_scale_hbox; #define ROW_EXTRA_SPACING 8 gint row; gint notebook_idx; /* columns for the spinbutton and buttons */ gint colspin; gint colbutton; colspin = 0; colbutton = 1; shell_window = NULL; if(gpp->docking_container) { shell_window = gpp->docking_container; } else { shell_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gpp->shell_window = shell_window; gtk_window_set_title (GTK_WINDOW (shell_window), _("Videoframe Playback")); gtk_window_set_resizable(GTK_WINDOW (shell_window), TRUE); } g_signal_connect (G_OBJECT (shell_window), "destroy", G_CALLBACK (on_shell_window_destroy), gpp); vbox0 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox0); gtk_container_add (GTK_CONTAINER (shell_window), vbox0); /* vid options TAB frame */ label_vid = gtk_label_new (_("Video Options")); gtk_widget_show (label_vid); if(gpp->stb_ptr) { frame0 = gimp_frame_new (gpp->stb_ptr->storyboardfile); } else { frame0 = gimp_frame_new (gpp->ainfo_ptr->basename); } gtk_widget_show (frame0); gpp->frame_with_name = frame0; spc_label = gtk_label_new(" "); gtk_widget_show (spc_label); spc_hbox0 = gtk_hbox_new (FALSE, 0); gtk_widget_show (spc_hbox0); gtk_box_pack_start (GTK_BOX (spc_hbox0), spc_label, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (spc_hbox0), frame0, TRUE, TRUE, 4); /* configure options TAB frame */ label_cfg = gtk_label_new (_("Preferences")); gtk_widget_show (label_cfg); spc_label = gtk_label_new(" "); gtk_widget_show (spc_label); frame0c = p_new_configframe (gpp); gtk_widget_show (frame0c); spc_hbox0c = gtk_hbox_new (FALSE, 0); gtk_widget_show (spc_hbox0c); gtk_box_pack_start (GTK_BOX (spc_hbox0c), spc_label, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (spc_hbox0c), frame0c, TRUE, TRUE, 4); #ifdef GAP_ENABLE_AUDIO_SUPPORT /* audio options TAB frame */ label_aud = gtk_label_new (_("Audio Options")); gtk_widget_show (label_aud); frame0a = p_new_audioframe (gpp); gtk_widget_show (frame0a); spc_label = gtk_label_new(" "); gtk_widget_show (spc_label); spc_hbox0a = gtk_hbox_new (FALSE, 0); gtk_widget_show (spc_hbox0a); gtk_box_pack_start (GTK_BOX (spc_hbox0a), spc_label, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (spc_hbox0a), frame0a, TRUE, TRUE, 4); #endif notebook = gtk_notebook_new(); gtk_widget_show (notebook); notebook_idx = 0; gtk_container_add (GTK_CONTAINER (notebook), spc_hbox0); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook) , gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), notebook_idx) , label_vid ); notebook_idx++; #ifdef GAP_ENABLE_AUDIO_SUPPORT gtk_container_add (GTK_CONTAINER (notebook), spc_hbox0a); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook) , gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), notebook_idx) , label_aud ); notebook_idx++; #endif gtk_container_add (GTK_CONTAINER (notebook), spc_hbox0c); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook) , gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), notebook_idx) , label_cfg ); notebook_idx++; gtk_box_pack_start (GTK_BOX (vbox0), notebook, TRUE, TRUE, 0); vbox1 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox1); gtk_container_add (GTK_CONTAINER (frame0), vbox1); /* the hbox for the go button array */ gobutton_hbox = gtk_hbox_new (TRUE, 0); gpp->gobutton_hbox = gobutton_hbox; if(gpp->show_go_buttons) { gtk_widget_show (gobutton_hbox); } else { gtk_widget_hide (gobutton_hbox); } if(gobutton_hbox) { gint go_number; gint max_go_buttons; GtkWidget *go_button; t_gobutton *gob; /* the gobutton array is be filled with [n] gobuttons */ max_go_buttons = GAP_PLAY_MAX_GOBUTTONS; if(gpp->docking_container) { max_go_buttons = GAP_PLAY_MAX_GOBUTTONS_DOCKED; } for(go_number=0; go_number < max_go_buttons; go_number++) { /* the go_button[s] */ gob = g_malloc0(sizeof(t_gobutton)); gob->gpp = gpp; gob->go_number = go_number; go_button = gtk_button_new (); gtk_widget_show (go_button); gtk_widget_set_events(go_button, GDK_ENTER_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK); gtk_box_pack_start (GTK_BOX (gobutton_hbox), go_button, FALSE, TRUE, 0); gtk_widget_set_size_request (go_button, -1, 40); if(go_number == 0) { gimp_help_set_help_data (go_button, _("Click: go to frame, Ctrl-Click: set 'From Frame', Alt-Click: set 'To Frame'"), NULL); } g_signal_connect (go_button, "enter_notify_event", G_CALLBACK (on_go_button_enter) ,gob); g_signal_connect (G_OBJECT (go_button), "button_press_event", G_CALLBACK (on_go_button_clicked), gob); } } /* Create an EventBox and for the gobutton_hbox leave Event */ event_box = gtk_event_box_new (); gtk_widget_show (event_box); gtk_container_add (GTK_CONTAINER (event_box), gobutton_hbox); gtk_widget_set_events(event_box , GDK_LEAVE_NOTIFY_MASK /* | gtk_widget_get_events (event_box) */ ); gtk_box_pack_start (GTK_BOX (vbox1), event_box, FALSE, FALSE, 0); g_signal_connect (event_box, "leave_notify_event", G_CALLBACK (on_gobutton_hbox_leave) ,gpp); /* the FRAMENR adjustment (for spinbutton and scale) */ { gdouble l_value; gdouble l_lower; gdouble l_upper; l_lower = MIN(gpp->ainfo_ptr->first_frame_nr, gpp->ainfo_ptr->last_frame_nr); l_upper = MAX(gpp->ainfo_ptr->first_frame_nr, gpp->ainfo_ptr->last_frame_nr); l_value = CLAMP(gpp->play_current_framenr, l_lower, l_upper); if(gap_debug) printf("CREATE framenr_spinbutton_adj: value: %d, lower:%d, upper:%d\n" ,(int)l_value ,(int)l_lower ,(int)l_upper ); framenr_spinbutton_adj = gtk_adjustment_new (l_value , l_lower , l_upper , 1.0 /* step_increment */ , 10.0 /* page_increment */ , 0.0 /* page_size must be 0 for simple scalar value */ ); } /* hbox for scale and time position label mm:ss:msec */ frame_scale_hbox = gtk_hbox_new (FALSE, 0); gpp->frame_scale_hbox = frame_scale_hbox; /* the framenr_scale (tool for positioning) */ framenr_scale = gtk_hscale_new (GTK_ADJUSTMENT (framenr_spinbutton_adj)); gpp->framenr_scale = framenr_scale; gtk_scale_set_digits (GTK_SCALE (framenr_scale), 0 /* digits */); /* gtk_scale_set_draw_value (GTK_SCALE (framenr_scale), FALSE); */ /* Dont know why, but without displaying the value * the scale and spinbutton value sometimes seems to differ by 1 * * Movinge the Scale sometimes displays frame nnnnn but spinbutton shows nnnnn +1 * (could not reproduce such differences with draw_value = TRUE) */ gtk_scale_set_draw_value (GTK_SCALE (framenr_scale), FALSE); gtk_range_set_update_policy (GTK_RANGE (framenr_scale), GTK_UPDATE_DELAYED); gimp_help_set_help_data (framenr_scale, _("The currently displayed frame number"), NULL); gtk_widget_show(framenr_scale); gtk_box_pack_start (GTK_BOX (frame_scale_hbox), framenr_scale, TRUE, TRUE, 0); g_signal_connect (framenr_scale, "button_press_event", G_CALLBACK (on_framenr_scale_clicked) ,gpp); /* the timepos label */ /* (had used an entry here before but had update performance problems * beginning at playback speed of 17 frames/sec on PII 300 Mhz) */ timepos_label = gtk_label_new ("00:00:000"); gpp->timepos_label = timepos_label; gtk_widget_show (timepos_label); gtk_box_pack_start (GTK_BOX (frame_scale_hbox), timepos_label, FALSE, FALSE, 4); if(gpp->show_position_scale) { gtk_widget_show(frame_scale_hbox); } else { gtk_widget_show(frame_scale_hbox); } gtk_box_pack_start (GTK_BOX (vbox1), frame_scale_hbox, FALSE, FALSE, 0); table1 = gtk_table_new (2, 2, FALSE); gtk_widget_show (table1); gtk_box_pack_start (GTK_BOX (vbox1), table1, TRUE, TRUE, 0); /* the frame2 for range and playback mode control widgets */ frame2 = gimp_frame_new (NULL); gtk_widget_show (frame2); gtk_table_attach (GTK_TABLE (table1), frame2, 1, 2, 0, 1 , (GtkAttachOptions) (0) , (GtkAttachOptions) (0) , 0, 0); /* table2 for range and playback mode control widgets */ table2 = gtk_table_new (18, 2, FALSE); gtk_widget_show (table2); gtk_table_set_col_spacings (GTK_TABLE (table2), 4); gtk_container_add (GTK_CONTAINER (frame2), table2); row = 0; /* the framenr buttons */ { GtkWidget *fnr_hbox; fnr_hbox = gtk_hbox_new (FALSE, 0); gtk_widget_show (fnr_hbox); gtk_table_attach (GTK_TABLE (table2), fnr_hbox, colbutton, colbutton+1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); /* the framenr 1 button (does set Begin of range) */ framenr_1_button = gtk_button_new_from_stock (GAP_STOCK_SET_RANGE_START); gtk_widget_show (framenr_1_button); gtk_box_pack_start (GTK_BOX (fnr_hbox), framenr_1_button, FALSE, FALSE, 0); g_object_set_data (G_OBJECT (framenr_1_button), KEY_FRAMENR_BUTTON_TYPE, (gpointer)FRAMENR_BUTTON_BEGIN); g_signal_connect (G_OBJECT (framenr_1_button), "button_press_event", G_CALLBACK (on_framenr_button_clicked), gpp); if((gpp->image_id >= 0) && (gpp->docking_container == NULL)) { gimp_help_set_help_data (framenr_1_button , _("Click: Set current framenr as selection range start 'From Frame',\n" "SHIFT-Click: load this frame into the calling image") , NULL); } else { /* there is no "calling image" if we are invoked from storyboard * or from the video extract plug-in * in this case there is no special SHIFT-click function available */ gimp_help_set_help_data (framenr_1_button , _("Set current framenr as selection range start 'From Frame'") , NULL); } /* the framenr 2 button (does set End of range) */ framenr_2_button = gtk_button_new_from_stock (GAP_STOCK_SET_RANGE_END); gtk_widget_show (framenr_2_button); gtk_box_pack_start (GTK_BOX (fnr_hbox), framenr_2_button, TRUE, TRUE, 0); g_object_set_data (G_OBJECT (framenr_2_button), KEY_FRAMENR_BUTTON_TYPE, (gpointer)FRAMENR_BUTTON_END); g_signal_connect (G_OBJECT (framenr_2_button), "button_press_event", G_CALLBACK (on_framenr_button_clicked), gpp); if((gpp->image_id >= 0) && (gpp->docking_container == NULL)) { gimp_help_set_help_data (framenr_2_button , _("Click: Set current framenr as selection range end 'To Frame',\n" "SHIFT-Click: load this frame into the calling image") , NULL); } else { /* there is no "calling image" if we are invoked from storyboard * or from the video extract plug-in * in this case there is no special SHIFT-click function available */ gimp_help_set_help_data (framenr_2_button , _("Set current framenr as selection range end 'To Frame'") , NULL); } } /* the FRAMENR spinbutton (current displayed frame) */ framenr_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (framenr_spinbutton_adj) , 1 /* climb_rate */ , 0 /* digits */ ); gtk_widget_show (framenr_spinbutton); gtk_table_attach (GTK_TABLE (table2), framenr_spinbutton, colspin, colspin+1, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (framenr_spinbutton, 80, -1); gimp_help_set_help_data (framenr_spinbutton, _("The currently displayed frame number"), NULL); g_signal_connect (G_OBJECT (framenr_spinbutton_adj), "value_changed", G_CALLBACK (on_framenr_spinbutton_changed), gpp); gtk_table_set_row_spacing (GTK_TABLE (table2), row, ROW_EXTRA_SPACING); row++; /* the from button */ from_button = gtk_button_new_from_stock (GAP_STOCK_RANGE_START); gpp->from_button = from_button; /* the from button */ gtk_widget_show (from_button); gtk_table_attach (GTK_TABLE (table2), from_button, colbutton, colbutton+1, row, row+1 , (GtkAttachOptions) (GTK_FILL) , (GtkAttachOptions) (0) , 0, 0); if(gpp->caller_range_linked) { gtk_widget_set_sensitive (from_button, FALSE); } else { if(gpp->fptr_set_range) { gimp_help_set_help_data (from_button, _("Add range to cliplist"), NULL); } else { gimp_help_set_help_data (from_button, _("Print range to stdout"), NULL); } g_signal_connect (G_OBJECT (from_button), "clicked", G_CALLBACK (on_from_button_clicked), gpp); } /* the FROM spinbutton (start of rangeselection) */ from_spinbutton_adj = gtk_adjustment_new ( gpp->begin_frame , gpp->ainfo_ptr->first_frame_nr , gpp->ainfo_ptr->last_frame_nr , 1.0 /* step_increment */ , 10.0 /* page_increment */ , 0.0 /* page_size must be 0 for simple scalar value */ ); from_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (from_spinbutton_adj), 1, 0); gtk_widget_show (from_spinbutton); gtk_table_attach (GTK_TABLE (table2), from_spinbutton, colspin, colspin+1, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (from_spinbutton, 80, -1); gimp_help_set_help_data (from_spinbutton, _("Start framenumber of selection range"), NULL); g_signal_connect (G_OBJECT (from_spinbutton_adj), "value_changed", G_CALLBACK (on_from_spinbutton_changed), gpp); row++; /* the to button */ to_button = gtk_button_new_from_stock (GAP_STOCK_RANGE_END); gpp->to_button = to_button; gtk_widget_show (to_button); gtk_table_attach (GTK_TABLE (table2), to_button, colbutton, colbutton+1, row, row+1 , (GtkAttachOptions) (GTK_FILL) , (GtkAttachOptions) (0) , 0, 0); if(gpp->caller_range_linked) { gtk_widget_set_sensitive (to_button, FALSE); } else { if(gpp->fptr_set_range) { gimp_help_set_help_data (to_button, _("Add inverse range to cliplist"), NULL); } else { gimp_help_set_help_data (to_button, _("Print inverse range to stdout"), NULL); } g_signal_connect (G_OBJECT (to_button), "clicked", G_CALLBACK (on_to_button_clicked), gpp); } /* the TO spinbutton (end of rangeselection) */ to_spinbutton_adj = gtk_adjustment_new ( gpp->end_frame , gpp->ainfo_ptr->first_frame_nr , gpp->ainfo_ptr->last_frame_nr , 1.0 /* step_increment */ , 10.0 /* page_increment */ , 0.0 /* page_size must be 0 for simple scalar value */ ); to_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (to_spinbutton_adj), 1, 0); gtk_widget_show (to_spinbutton); gtk_table_attach (GTK_TABLE (table2), to_spinbutton, colspin, colspin+1, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (to_spinbutton, 80, -1); gimp_help_set_help_data (to_spinbutton, _("End framenumber of selection range"), NULL); g_signal_connect (G_OBJECT (to_spinbutton_adj), "value_changed", G_CALLBACK (on_to_spinbutton_changed), gpp); gtk_table_set_row_spacing (GTK_TABLE (table2), row, ROW_EXTRA_SPACING); row++; /* the origspeed_button */ origspeed_button = gtk_button_new_from_stock (GAP_STOCK_SPEED); gtk_widget_show (origspeed_button); gtk_table_attach (GTK_TABLE (table2), origspeed_button, colbutton, colbutton+1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (origspeed_button, _("Reset playback speed to original (or previous) value"), NULL); g_signal_connect (G_OBJECT (origspeed_button), "clicked", G_CALLBACK (on_origspeed_button_clicked), gpp); /* the SPEED spinbutton * with the given timer resolution of millisecs the theoretical * maximum speed is 1000 frames/sec that would result in 1 timertick * this implementation allows a max speed of 250 frames/sec (4 timerticks) */ speed_spinbutton_adj = gtk_adjustment_new ( gpp->speed , 1.0 , 250.0 , 1.0 /* step_increment */ , 10.0 /* page_increment */ , 0.0 /* page_size must be 0 for simple scalar value */ ); speed_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (speed_spinbutton_adj), 1, 4); gtk_widget_show (speed_spinbutton); gtk_table_attach (GTK_TABLE (table2), speed_spinbutton, colspin, colspin+1, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (speed_spinbutton, 80, -1); gimp_help_set_help_data (speed_spinbutton, _("Current playback speed (frames/sec)"), NULL); g_signal_connect (G_OBJECT (speed_spinbutton_adj), "value_changed", G_CALLBACK (on_speed_spinbutton_changed), gpp); row++; /* the size button */ { /* we use the same icon as the gimp scaling tool */ GtkWidget *image; image = gtk_image_new_from_stock (GIMP_STOCK_TOOL_SCALE, GTK_ICON_SIZE_BUTTON); gtk_widget_show (image); size_button = gtk_button_new(); gtk_container_add (GTK_CONTAINER (size_button), image); } gtk_widget_show (size_button); gtk_widget_set_events(size_button, GDK_BUTTON_PRESS_MASK); gtk_table_attach (GTK_TABLE (table2), size_button, colbutton, colbutton+1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (size_button, _("Toggle size 128/256. Set 1:1 full image size"), NULL); g_signal_connect (G_OBJECT (size_button), "button_press_event", G_CALLBACK (on_size_button_button_press_event), gpp); /* the SIZE spinbutton */ size_spinbutton_adj = gtk_adjustment_new (gpp->pv_pixelsize , GAP_PLAYER_MIN_SIZE , GAP_PLAYER_MAX_SIZE , 1.0 /* step_increment */ , 10.0 /* page_increment */ , 0.0 /* page_size must be 0 for simple scalar value */ ); size_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (size_spinbutton_adj), 1, 0); gpp->size_spinbutton = size_spinbutton; gtk_widget_show (size_spinbutton); gtk_table_attach (GTK_TABLE (table2), size_spinbutton, colspin, colspin+1, row, row+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_size_request (size_spinbutton, 80, -1); gimp_help_set_help_data (size_spinbutton, _("Video preview size (pixels)"), NULL); g_signal_connect (G_OBJECT (size_spinbutton_adj), "value_changed", G_CALLBACK (on_size_spinbutton_changed), gpp); if(gpp->docking_container == NULL) { gtk_widget_set_events(size_spinbutton , GDK_ENTER_NOTIFY_MASK ); g_signal_connect (G_OBJECT (size_spinbutton), "enter_notify_event", G_CALLBACK (on_size_spinbutton_enter), gpp); } gtk_table_set_row_spacing (GTK_TABLE (table2), row, ROW_EXTRA_SPACING); row++; /* the playback mode checkbuttons */ /* Loop Toggle */ loop_checkbutton = gtk_check_button_new_with_label (_("Loop")); gpp->loop_checkbutton = loop_checkbutton; gtk_widget_show (loop_checkbutton); gtk_table_attach (GTK_TABLE (table2), loop_checkbutton, 0, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (loop_checkbutton, _("ON: Play in endless loop.\n" "OFF: Play only once"), NULL); if(gpp->play_loop) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (loop_checkbutton), TRUE); } g_signal_connect (G_OBJECT (loop_checkbutton), "toggled", G_CALLBACK (on_loop_checkbutton_toggled), gpp); row++; /* SelOnly Toggle (keep text short) */ selonly_checkbutton = gtk_check_button_new_with_label (_("Selection only")); gpp->selonly_checkbutton = selonly_checkbutton; gtk_widget_show (selonly_checkbutton); gtk_table_attach (GTK_TABLE (table2), selonly_checkbutton, 0, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (selonly_checkbutton, _("ON: Play only frames within the selected range.\n" "OFF: Play all frames"), NULL); if(gpp->play_selection_only) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (selonly_checkbutton), TRUE); } g_signal_connect (G_OBJECT (selonly_checkbutton), "toggled", G_CALLBACK (on_selonly_checkbutton_toggled), gpp); row++; /* PingPong Toggle (keep text short) */ pinpong_checkbutton = gtk_check_button_new_with_label (_("Ping pong")); gpp->pinpong_checkbutton = pinpong_checkbutton; gtk_widget_show (pinpong_checkbutton); gtk_table_attach (GTK_TABLE (table2), pinpong_checkbutton, 0, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (pinpong_checkbutton, _("ON: Play alternating forward/backward"), NULL); if(gpp->play_pingpong) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pinpong_checkbutton), TRUE); } g_signal_connect (G_OBJECT (pinpong_checkbutton), "toggled", G_CALLBACK (on_pinpong_checkbutton_toggled), gpp); row++; /* UseThumbnails Toggle (keep text short) */ use_thumb_checkbutton = gtk_check_button_new_with_label (_("Thumbnails")); gpp->use_thumb_checkbutton = use_thumb_checkbutton; gtk_widget_show (use_thumb_checkbutton); gtk_table_attach (GTK_TABLE (table2), use_thumb_checkbutton, 0, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (use_thumb_checkbutton, _("ON: Use thumbnails when available.\n" "OFF: Read full sized frames"), NULL); if(gpp->use_thumbnails) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (use_thumb_checkbutton), TRUE); } g_signal_connect (G_OBJECT (use_thumb_checkbutton), "toggled", G_CALLBACK (on_use_thumb_checkbutton_toggled), gpp); row++; /* ExactTiming Toggle (keep text short) */ exact_timing_checkbutton = gtk_check_button_new_with_label (_("Exact timing")); gpp->exact_timing_checkbutton = exact_timing_checkbutton; gtk_widget_show (exact_timing_checkbutton); gtk_table_attach (GTK_TABLE (table2), exact_timing_checkbutton, 0, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gimp_help_set_help_data (exact_timing_checkbutton, _("ON: Skip frames to hold exact timing.\n" "OFF: Disable frame skipping"), NULL); if(gpp->exact_timing) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (exact_timing_checkbutton), TRUE); } g_signal_connect (G_OBJECT (exact_timing_checkbutton), "toggled", G_CALLBACK (on_exact_timing_checkbutton_toggled), gpp); row++; /* the status value label */ status_label = gtk_label_new (_("Ready")); gtk_widget_show (status_label); gtk_table_attach (GTK_TABLE (table2), status_label, 0, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment (GTK_MISC (status_label), 0.0, 0.5); row++; /* the progress bar */ progress_bar = NULL; if(gpp->have_progress_bar) { progress_bar = gtk_progress_bar_new (); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress_bar), " "); gtk_widget_show (progress_bar); gtk_table_attach (GTK_TABLE (table2), progress_bar, 0, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); } gpp->progress_bar = progress_bar; /* a dummy label to fill up table1 until bottom */ label = gtk_label_new (" "); gtk_widget_show (label); // gtk_table_attach (GTK_TABLE (table1), label, 1, 2, 1, 2, // (GtkAttachOptions) (0), // (GtkAttachOptions) (GTK_FILL | GTK_SHRINK | GTK_EXPAND), 0, 0); /* the hbox */ hbox1 = gtk_hbox_new (TRUE, 0); gtk_widget_show (hbox1); gtk_box_pack_start (GTK_BOX (vbox0), hbox1, FALSE, FALSE, 0); /* the playback/pause button box (hidden while videoindex creation is running) */ play_n_stop_hbox = gtk_hbox_new (TRUE, 0); gpp->play_n_stop_hbox = play_n_stop_hbox; gtk_widget_show (play_n_stop_hbox); gtk_box_pack_start (GTK_BOX (hbox1), play_n_stop_hbox, FALSE, TRUE, 0); /* the Cancel Videoindex Creation button (only visible while creating vindex) */ cancel_vindex_button = gtk_button_new_with_label ( _("Cancel Videoindex creation")); gpp->cancel_vindex_button = cancel_vindex_button; gtk_widget_hide (cancel_vindex_button); gtk_box_pack_start (GTK_BOX (hbox1), cancel_vindex_button, FALSE, TRUE, 0); gimp_help_set_help_data (cancel_vindex_button, _("Cancel videoindex creation. " "Videoindex creation requires full scanning of the video " "but allows fast random access to frames afterwards. " "Without a videoindex, access is done by a very slow sequential read"), NULL); g_signal_connect (G_OBJECT (cancel_vindex_button), "clicked", G_CALLBACK (on_cancel_vindex_button_clicked), gpp); if(gpp->help_id && gimp_show_help_button ()) { GtkWidget *help_button; /* the HELP button */ help_button = gtk_button_new_from_stock (GTK_STOCK_HELP); gtk_widget_show (help_button); gtk_box_pack_start (GTK_BOX (play_n_stop_hbox), help_button, FALSE, TRUE, 0); gimp_help_set_help_data (help_button, _("Show help page"), NULL); g_signal_connect (G_OBJECT (help_button), "clicked", G_CALLBACK (on_help_button_clicked), gpp); } /* the PLAY button */ play_button = gtk_button_new_from_stock (GAP_STOCK_PLAY); gtk_widget_show (play_button); gtk_box_pack_start (GTK_BOX (play_n_stop_hbox), play_button, FALSE, TRUE, 0); gimp_help_set_help_data (play_button, _("Start playback. " "SHIFT: snapshot frames in a multilayer image at original size " "CTRL: snapshot at preview size " "ALT: force creation of new snapshot image"), NULL); g_signal_connect (G_OBJECT (play_button), "button_press_event", G_CALLBACK (on_play_button_clicked), gpp); /* the PAUSE button */ pause_button = gtk_button_new_from_stock (GAP_STOCK_PAUSE); gtk_widget_show (pause_button); gtk_widget_set_events(pause_button, GDK_BUTTON_PRESS_MASK); gtk_box_pack_start (GTK_BOX (play_n_stop_hbox), pause_button, FALSE, TRUE, 0); gimp_help_set_help_data (pause_button, _("Pause if playing (any mousebutton). " "Go to selection start/active/end (left/middle/right mousebutton) if not playing"), NULL); g_signal_connect (G_OBJECT (pause_button), "button_press_event", G_CALLBACK (on_pause_button_press_event), gpp); /* the PLAY_REVERSE button */ back_button = gtk_button_new_from_stock (GAP_STOCK_PLAY_REVERSE); gtk_widget_show (back_button); gtk_box_pack_start (GTK_BOX (play_n_stop_hbox), back_button, FALSE, TRUE, 0); gimp_help_set_help_data (back_button, _("Start reverse playback. " "SHIFT: snapshot frames in a multilayer image at original size " "CTRL: snapshot at preview size " "ALT: force creation of new snapshot image"), NULL); g_signal_connect (G_OBJECT (back_button), "button_press_event", G_CALLBACK (on_back_button_clicked), gpp); if(gpp->docking_container == NULL) { /* the CLOSE button */ close_button = gtk_button_new_from_stock (GTK_STOCK_CLOSE); gtk_widget_show (close_button); gtk_box_pack_start (GTK_BOX (play_n_stop_hbox), close_button, FALSE, TRUE, 0); gimp_help_set_help_data (close_button, _("Close window"), NULL); g_signal_connect (G_OBJECT (close_button), "clicked", G_CALLBACK (on_close_button_clicked), gpp); } /* aspect_frame is the CONTAINER for the video preview */ aspect_frame = gtk_aspect_frame_new (NULL /* without label */ , 0.5 /* xalign center */ , 0.5 /* yalign center */ , gpp->ainfo_ptr->width / gpp->ainfo_ptr->height /* ratio */ , TRUE /* obey_child */ ); gtk_widget_show (aspect_frame); /* table11 is used to center aspect_frame */ table11 = gtk_table_new (3, 3, FALSE); gtk_widget_show (table11); { gint ix; gint iy; GtkWidget *dummy; for(ix = 0; ix < 3; ix++) { for(iy = 0; iy < 3; iy++) { if((ix == 1) && (iy == 1)) { gtk_table_attach (GTK_TABLE (table11), aspect_frame, ix, ix+1, iy, iy+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); } else { /* dummy widgets to fill up table11 */ dummy = gtk_vbox_new (FALSE,3); gtk_widget_show (dummy); gtk_table_attach (GTK_TABLE (table11), dummy, ix, ix+1, iy, iy+1, (GtkAttachOptions) (GTK_FILL | GTK_SHRINK | GTK_EXPAND), (GtkAttachOptions) (GTK_FILL | GTK_SHRINK | GTK_EXPAND), 0, 0); } } } } { GtkWidget *wrap_frame; GtkWidget *wrap_event_box; wrap_event_box = gtk_event_box_new (); gtk_widget_show (wrap_event_box); wrap_frame= gimp_frame_new(NULL); gtk_container_set_border_width (GTK_CONTAINER (wrap_frame), 0); gpp->resize_box = wrap_frame; gtk_widget_show(wrap_frame); gtk_container_add (GTK_CONTAINER (wrap_frame), table11); gtk_container_add (GTK_CONTAINER (wrap_event_box), wrap_frame); gtk_table_attach (GTK_TABLE (table1), wrap_event_box, 0, 1, 0, 2, (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL), (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL), 0, 0); g_signal_connect (G_OBJECT (wrap_event_box), "scroll_event", G_CALLBACK (on_warp_frame_scroll_event), gpp); } gtk_widget_realize (shell_window); /* the preview drawing_area_widget */ /* ############################### */ gpp->pv_ptr = gap_pview_new(GAP_SMALL_PREVIEW_SIZE, GAP_SMALL_PREVIEW_SIZE, GAP_PLAYER_CHECK_SIZE, aspect_frame); vid_preview = gpp->pv_ptr->da_widget; gtk_container_add (GTK_CONTAINER (aspect_frame), vid_preview); gtk_widget_show (vid_preview); /* gpp copies of objects used outside this procedure */ gpp->from_spinbutton_adj = from_spinbutton_adj; gpp->to_spinbutton_adj = to_spinbutton_adj; gpp->framenr_spinbutton_adj = framenr_spinbutton_adj; gpp->speed_spinbutton_adj = speed_spinbutton_adj; gpp->size_spinbutton_adj = size_spinbutton_adj; gtk_widget_realize (gpp->pv_ptr->da_widget); p_update_pviewsize(gpp); /* the call to gtk_widget_set_events results in WARNING: * (gimp-1.3:13789): Gtk-CRITICAL **: file gtkwidget.c: line 5257 (gtk_widget_set_events): assertion `!GTK_WIDGET_REALIZED (widget)' failed * * must use gtk_widget_add_events because the widget is already realized at this time */ gtk_widget_add_events (vid_preview, GDK_BUTTON_PRESS_MASK | GDK_EXPOSURE_MASK); g_signal_connect (G_OBJECT (vid_preview), "button_press_event", G_CALLBACK (on_vid_preview_button_press_event), gpp); g_signal_connect (G_OBJECT (vid_preview), "expose_event", G_CALLBACK (on_vid_preview_expose_event), gpp); gpp->status_label = status_label; return shell_window; } /* end p_create_player_window */ /* ----------------------------- * p_connect_resize_handler * ----------------------------- */ static void p_connect_resize_handler(GapPlayerMainGlobalParams *gpp) { if(gpp->docking_container) { /* never connect resize handler when player is docked to a foreign container */ return; } if(gpp->resize_handler_id < 0) { gpp->resize_handler_id = g_signal_connect (G_OBJECT (gpp->resize_box), "size_allocate", G_CALLBACK (on_vid_preview_size_allocate), gpp); } } /* end p_connect_resize_handler */ /* ----------------------------- * p_disconnect_resize_handler * ----------------------------- */ static void p_disconnect_resize_handler(GapPlayerMainGlobalParams *gpp) { if(gpp->resize_handler_id >= 0) { g_signal_handler_disconnect(gpp->resize_box, gpp->resize_handler_id); gpp->resize_handler_id = -1; } } /* end p_disconnect_resize_handler */ /* --------------------------------- * gap_player_dlg_restart * --------------------------------- * This procedure re-initializes an * already running player dialog for playback * of a new storyboard or normal image frame playback. * IN: autostart if TRUE automatically start playback. * IN: image_id a gimp image_id of a GIMP_GAP typical animation frame * specify -1 if you want play videofiles or storyboard files. * IN: imagename name of an image or videofile. * IN: stb Ponter to a storyboard structure that should be played, * specify NULL for playback of simple frame ranges * or single videofiles. * IN: flip_request flag to specify simple transformation requests (0 none, 1 hor, 2 ver 3 rotate 180) * ignored for storyboard playback (stb_ptr != NULL) * IN: flip status same bits as flip_requst, specifies the transformation status of the * original input frames. * The rendering calculates the transformation by XOR * operation flip_request XOR flip_status. * (in other words: if the status is the same as the request * no transformation is performed.) * ignored for storyboard playback (stb_ptr != NULL) * IN: stb_in_track the storyboard track that should be played * a value of -1 selects the composite video fro playback * stb_in_track is ignored if stb_ptr == NULL */ void gap_player_dlg_restart(GapPlayerMainGlobalParams *gpp , gboolean autostart , gint32 image_id , char *imagename , gint32 imagewidth , gint32 imageheight , GapStoryBoard *stb_ptr , gint32 begin_frame , gint32 end_frame , gboolean play_selection_only , gint32 seltrack , gdouble delace , const char *preferred_decoder , gboolean force_open_as_video , gint32 flip_request , gint32 flip_status , gint32 stb_in_track ) { gboolean reverse_play; gint32 l_begin_frame; gint32 l_end_frame; gint32 l_curr_frame; if(gap_debug) printf("gap_player_dlg_restart: START begin_frame:%d end_frame:%d\n", (int)begin_frame, (int)end_frame); reverse_play = FALSE; if(begin_frame > end_frame) { gint32 val; val = end_frame; end_frame = begin_frame; begin_frame = val; reverse_play = TRUE; } if(gpp == NULL) { return; } p_stop_playback(gpp); if(gpp->audio_tmp_dialog_is_open) { /* ignore close as long as sub dialog is open */ return; } if(gpp->preferred_decoder) { g_free(gpp->preferred_decoder); gpp->preferred_decoder = NULL; } if(preferred_decoder) { gpp->preferred_decoder = g_strdup(preferred_decoder); } gpp->force_open_as_video = force_open_as_video; gpp->delace = delace; gpp->seltrack = seltrack; gpp->stb_ptr = stb_ptr; gpp->image_id = image_id; gpp->imagewidth = imagewidth; gpp->imageheight = imageheight; gpp->play_selection_only = play_selection_only; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gpp->selonly_checkbutton), play_selection_only); if(gpp->imagename) { g_free(gpp->imagename); gpp->imagename = NULL; } if(gpp->stb_ptr) { GapStoryBoard *stb; stb = gpp->stb_ptr; if(gpp->ainfo_ptr) { gap_lib_free_ainfo(&gpp->ainfo_ptr); } gpp->stb_in_track = stb_in_track; gpp->ainfo_ptr = gap_story_fake_ainfo_from_stb(stb, stb_in_track); if(stb->master_framerate > 0.0) { gpp->original_speed = stb->master_framerate; gpp->prev_speed = stb->master_framerate; } } else { if(imagename) { gpp->imagename = g_strdup(imagename); p_reload_ainfo_ptr(gpp, -1); if(gpp->ainfo_ptr == NULL) { return; } } else { p_reload_ainfo_ptr(gpp, image_id); if(gpp->ainfo_ptr == NULL) { return; } if(0 != gap_lib_chk_framerange(gpp->ainfo_ptr)) { return; } } } l_curr_frame = gpp->ainfo_ptr->curr_frame_nr; l_begin_frame = gpp->ainfo_ptr->curr_frame_nr; l_end_frame = gpp->ainfo_ptr->last_frame_nr; if(begin_frame >= 0) { l_begin_frame = CLAMP(begin_frame , gpp->ainfo_ptr->first_frame_nr , gpp->ainfo_ptr->last_frame_nr ); } if(end_frame >= 0) { l_end_frame = CLAMP(end_frame , gpp->ainfo_ptr->first_frame_nr , gpp->ainfo_ptr->last_frame_nr ); } l_curr_frame = CLAMP(l_curr_frame ,l_begin_frame ,l_end_frame ); gpp->begin_frame = l_begin_frame; gpp->end_frame = l_end_frame; gpp->play_current_framenr = l_curr_frame; /* modify player widgets */ p_update_pviewsize(gpp); p_update_ainfo_dependent_widgets(gpp); if(gap_debug) { printf(" -- -- RESTART l_begin_frame:%d l_end_frame:%d l_curr_frame:%d\n" ,(int)l_begin_frame ,(int)l_end_frame ,(int)l_curr_frame ); } gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->from_spinbutton_adj) , (gfloat)l_begin_frame ); gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->to_spinbutton_adj) , (gfloat)l_end_frame ); gtk_adjustment_set_value( GTK_ADJUSTMENT(gpp->framenr_spinbutton_adj) , (gfloat)l_curr_frame ); /* workaround: gtk_adjustment_set_value sometimes does not immediate * show the new value (especially in the to_spinbutton widget) * to force an update we emit a "value_changed" signal */ g_signal_emit_by_name (gpp->to_spinbutton_adj, "value_changed", 0); g_signal_emit_by_name (gpp->from_spinbutton_adj, "value_changed", 0); g_signal_emit_by_name (gpp->framenr_spinbutton_adj, "value_changed", 0); p_update_position_widgets(gpp); p_set_frame_with_name_label(gpp); gpp->flip_request = flip_request; gpp->flip_status = flip_status; /* now display current frame */ p_display_frame(gpp, gpp->play_current_framenr); gap_pview_repaint(gpp->pv_ptr); gdk_flush(); if((gpp->autostart) && ((gpp->play_current_framenr != gpp->begin_frame) || (gpp->play_current_framenr != gpp->end_frame))) { if(reverse_play) { on_back_button_clicked(NULL, NULL, gpp); } else { on_play_button_clicked(NULL, NULL, gpp); } } } /* end gap_player_dlg_restart */ /* ----------------------------- * gap_player_dlg_create * ----------------------------- * create the player widget (gpp->shell_window) */ void gap_player_dlg_create(GapPlayerMainGlobalParams *gpp) { gboolean reverse_play; reverse_play = FALSE; if(gpp->begin_frame > gpp->end_frame) { gint32 val; val = gpp->end_frame; gpp->end_frame = gpp->begin_frame; gpp->begin_frame = val; reverse_play = TRUE; } gpp->startup = TRUE; gpp->onion_delete = FALSE; gpp->shell_initial_width = -1; gpp->shell_initial_height = -1; p_init_video_playback_cache(gpp); p_init_layout_options(gpp); gpp->mtrace_image_id = -1; gpp->mtrace_mode = GAP_PLAYER_MTRACE_OFF; gpp->vindex_creation_is_running = FALSE; gpp->request_cancel_video_api = FALSE; gpp->cancel_video_api = FALSE; gpp->gvahand = NULL; gpp->gva_videofile = NULL; gpp->seltrack = 1; gpp->delace = 0.0; gpp->ainfo_ptr = NULL; gpp->original_speed = 24.0; /* default if framerate is unknown */ gpp->prev_speed = 24.0; /* default if framerate is unknown */ gpp->stb_comp_vidhand = NULL; gpp->stb_parttype = -1; gpp->stb_unique_id = -1; if(gpp->stb_ptr) { GapStoryBoard *stb; stb = gpp->stb_ptr; gpp->ainfo_ptr = gap_story_fake_ainfo_from_stb(stb, gpp->stb_in_track); if(stb->master_framerate > 0.0) { gpp->original_speed = stb->master_framerate; gpp->prev_speed = stb->master_framerate; } } else { if(gpp->imagename) { p_reload_ainfo_ptr(gpp, -1); if(gpp->ainfo_ptr == NULL) { return; } } else { p_reload_ainfo_ptr(gpp, gpp->image_id); if(gpp->ainfo_ptr == NULL) { return; } if (gpp->standalone_mode == TRUE) { if(0 != gap_lib_chk_framerange(gpp->ainfo_ptr)) { return; } } } } gpp->resize_handler_id = -1; gpp->play_is_active = FALSE; gpp->play_timertag = -1; gpp->go_timertag = -1; gpp->go_base_framenr = -1; gpp->go_base = -1; gpp->pingpong_count = 0; gpp->gtimer = g_timer_new(); gpp->cycle_time_secs = 0.3; gpp->rest_secs = 0.0; gpp->framecnt = 0.0; gpp->audio_volume = 1.0; gpp->audio_resync = 0; gpp->audio_frame_offset = 0; gpp->audio_filesel = NULL; gpp->audio_tmp_dialog_is_open = FALSE; gpp->audio_otone_atrack = 1; gpp->audio_enable_checkbutton = NULL; gpp->audio_auto_offset_by_framenr_checkbutton = NULL; gpp->audio_otone_extract_button = NULL; gpp->audio_otone_atrack_spinbutton = NULL; gpp->audio_otone_atrack_spinbutton_adj = NULL; gpp->progress_bar_audio = NULL; if((gpp->autostart) || (gpp->imagename)) { gpp->begin_frame = CLAMP(gpp->begin_frame , gpp->ainfo_ptr->first_frame_nr , gpp->ainfo_ptr->last_frame_nr); gpp->end_frame = CLAMP(gpp->end_frame , gpp->ainfo_ptr->first_frame_nr , gpp->ainfo_ptr->last_frame_nr); gpp->play_current_framenr = CLAMP(gpp->ainfo_ptr->curr_frame_nr , gpp->begin_frame , gpp->end_frame); } else { gpp->begin_frame = gpp->ainfo_ptr->curr_frame_nr; gpp->end_frame = gpp->ainfo_ptr->last_frame_nr; gpp->play_current_framenr = gpp->ainfo_ptr->curr_frame_nr; } gpp->pb_stepsize = 1; /* always startup at original speed */ gpp->speed = gpp->original_speed; gpp->prev_speed = gpp->original_speed; if((gpp->pv_pixelsize < GAP_PLAYER_MIN_SIZE) || (gpp->pv_pixelsize > GAP_PLAYER_MAX_SIZE)) { gpp->pv_pixelsize = GAP_STANDARD_PREVIEW_SIZE; } if ((gpp->pv_width < GAP_PLAYER_MIN_SIZE) || (gpp->pv_width > GAP_PLAYER_MAX_SIZE)) { gpp->pv_width = GAP_STANDARD_PREVIEW_SIZE; } if ((gpp->pv_height < GAP_PLAYER_MIN_SIZE) || (gpp->pv_height > GAP_PLAYER_MAX_SIZE)) { gpp->pv_height = GAP_STANDARD_PREVIEW_SIZE; } gpp->in_feedback = FALSE; gpp->in_timer_playback = FALSE; 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); p_display_frame(gpp, gpp->play_current_framenr); gap_pview_repaint(gpp->pv_ptr); gdk_flush(); p_check_tooltips(); /* set audio status to unchecked state * and do p_audio_startup_server(gpp); deferred on 1st attempt to enter audiofile */ gpp->audio_status = GAP_PLAYER_MAIN_AUSTAT_UNCHECKED; if(gpp->autostart) { if(reverse_play) { on_back_button_clicked(NULL, NULL, gpp); } else { on_play_button_clicked(NULL, NULL, gpp); } } if((gpp->docking_container == NULL) && (gpp->shell_window)) { gtk_widget_show (gpp->shell_window); g_signal_connect (G_OBJECT (gpp->shell_window), "size_allocate", G_CALLBACK (on_shell_window_size_allocate), gpp); g_signal_connect (G_OBJECT (gpp->shell_window), "leave_notify_event", G_CALLBACK (on_shell_window_leave), gpp); } gpp->startup = FALSE; /* close videofile after startup. * this is done to enable videoindex creation * at next p_open_videofile call */ p_close_videofile(gpp); p_connect_resize_handler(gpp); } /* end gap_player_dlg_create */ /* ----------------------------- * gap_player_dlg_cleanup * ----------------------------- */ void gap_player_dlg_cleanup(GapPlayerMainGlobalParams *gpp) { p_audio_shut_server(gpp); if(gpp->gtimer) { g_timer_destroy(gpp->gtimer); gpp->gtimer = NULL; } if(gpp->ainfo_ptr) { gap_lib_free_ainfo(&gpp->ainfo_ptr); } gap_player_cache_free_all(); } /* end gap_player_dlg_cleanup */ /* ------------------------------ * gap_player_dlg_playback_dialog * ------------------------------ * This procedure does Playback * in standalone mode. * (when invoked from an anim frame image via the Video/Playback Menu) */ void gap_player_dlg_playback_dialog(GapPlayerMainGlobalParams *gpp) { gimp_ui_init ("gap_player_dialog", FALSE); gap_stock_init(); p_check_tooltips(); gpp->fptr_set_range = NULL; gpp->user_data_ptr = NULL; gpp->imagename = NULL; gpp->docking_container = NULL; gpp->preferred_decoder = NULL; gpp->have_progress_bar = FALSE; gpp->progress_bar_idle_txt = g_strdup(" "); gpp->exact_timing = TRUE; gpp->caller_range_linked = FALSE; gpp->aspect_ratio = GAP_PLAYER_DONT_FORCE_ASPECT; gap_player_dlg_create(gpp); if(gpp->shell_window) { gpp->standalone_mode = TRUE; gtk_main (); gap_player_dlg_cleanup(gpp); } gpp->ainfo_ptr = NULL; gpp->stb_ptr = NULL; gpp->gvahand = NULL; gpp->gva_videofile = NULL; } /* end gap_player_dlg_playback_dialog */ gimp-gap-2.6.0+dfsg.orig/gap/gap_vex_main.c0000644000175000017500000004113611212030253020322 0ustar thibautthibaut/* * gap_vex_main.c * A GIMP / GAP Plugin to extract frames and/or audio from Videofiles * * This is a special kind of File Load Plugin, * based on gap_vid_api (GVA) (an API to read various Videoformats/CODECS) * if compiled without GAP_ENABLE_VIDEOAPI_SUPPORT this module * just displays a message */ /* * Changelog: * 2004/04/10 v2.1.0: integrated sourcecode into gimp-gap project * 2003/04/14 v1.2.1a: created */ /* * Copyright * * 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 "config.h" #include #include #include #include #include #include #include #include #include "gap-intl.h" #include #include #include #include #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* conditional Includes for video API */ #include #endif /* Include of sub modules */ #include "gap_vex_main.h" #include "gap_vex_dialog.h" #include "gap_vex_exec.h" int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */ static void query (void); static void run (const gchar *name, /* name of plugin */ gint nparams, /* number of in-paramters */ const GimpParam * param, /* in-parameters */ gint *nreturn_vals, /* number of out-parameters */ GimpParam ** return_vals); /* out-parameters */ GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; MAIN () static void query () { static GimpParamDef load_args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" }, { GIMP_PDB_IMAGE, "image", "(unused)"}, { GIMP_PDB_DRAWABLE, "drawable", "(unused)"}, { GIMP_PDB_STRING, "videoename", "The name of the Videofile to read (load)" }, { GIMP_PDB_INT32, "pos_unit", "2: begin_pos, and end_pos are percent (0.0 upto 100.0) 0: begin_pos, and end_pos are framenumbers" }, { GIMP_PDB_FLOAT, "begin_pos", "start of the affected range (percent or framenumber)" }, { GIMP_PDB_FLOAT, "end_pos", "end of the affected range (percent or framenumber)" }, { GIMP_PDB_STRING, "audiofile", "name for extracted audio output file (RIFF PCM Wave Format, should end with .wav)" }, { GIMP_PDB_STRING, "basename", "The name for extracted ouput frames _0001. is added" }, { GIMP_PDB_STRING, "extension", "select image save format by extension (.xcf, .ppm, .jpg, ...)" }, { GIMP_PDB_INT32, "basenum", "number for the 1.st extracted output frame, 0: use original framenr" }, { GIMP_PDB_INT32, "multilayer", "0: save each frame to one file, 1: load all frames into one multilayer image" }, { GIMP_PDB_INT32, "extract_videotrack", "0:ignore video frames, 1 upto n: extract frames from videotrack" }, { GIMP_PDB_INT32, "extract_audiotrack", "0:ignore audio, 1 upto n: extract audiotrack to .wav file" }, { GIMP_PDB_INT32, "overwrite_mode", "1: overwrite all existing files, other values: cancel if files already exists" }, { GIMP_PDB_INT32, "disable_mmx", "0: use (faster) MMX if available, 1: do not USE MMX (MMX is lossy on lowbitrate streams)" }, { GIMP_PDB_STRING, "preferred_decoder", "NULL, or one of: libmpeg3, quicktime4linux, libavformat" }, { GIMP_PDB_INT32, "exact_seek", "0: NO (enable faster seek ops if available), 1: YES use only sequential read ops, will find exact framenumbers" }, { GIMP_PDB_INT32, "deinterlace", "0: NO, 1: deinterlace odd rows only, 2: deinterlace even rows only, 3: deinterlace split into 2 frames where odd rows-frame is 1st, 4: deinterlace split into 2 frames where even rows-frame is 1st)" }, { GIMP_PDB_FLOAT, "delace_threshold", "0.0 .. no interpolation, 1.0 smooth interpolation at deinterlacing" }, { GIMP_PDB_INT32, "fn_digits", "1 <= fn_digits <= 8, number of digits to use in framenames (use 1 if you dont want leading zeroes) " }, { GIMP_PDB_INT32, "bluebox", "0: NO, 1: YES generate transparency by applying bluebox filter with last values" }, { GIMP_PDB_INT32, "graymask", "0: NO (extract frames 1:1), 1: YES extract generated transparency as gray mask" }, { GIMP_PDB_INT32, "layermask", "0: NO (bluebox shall generate aplha channel), 1: YES (bluebox shall generate layermask)" }, }; static GimpParamDef load_return_vals[] = { { GIMP_PDB_IMAGE, "image", "Output image" }, }; static int nload_args = sizeof (load_args) / sizeof (load_args[0]); static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]); static GimpParamDef ext_args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" }, { GIMP_PDB_STRING, "videoename", "The name of the Videofile to read (load)" }, { GIMP_PDB_INT32, "pos_unit", "2: begin_pos, and end_pos are percent (0.0 upto 100.0) 0: begin_pos, and end_pos are framenumbers" }, { GIMP_PDB_FLOAT, "begin_pos", "start of the affected range (percent or framenumber)" }, { GIMP_PDB_FLOAT, "end_pos", "end of the affected range (percent or framenumber)" }, { GIMP_PDB_STRING, "audiofile", "name for extracted audio output file (RIFF PCM Wave Format, should end with .wav)" }, { GIMP_PDB_STRING, "basename", "The name for extracted ouput frames _0001. is added" }, { GIMP_PDB_STRING, "extension", "select image save format by extension (.xcf, .ppm, .jpg, ...)" }, { GIMP_PDB_INT32, "basenum", "number for the 1.st extracted output frame, 0: use original framenr" }, { GIMP_PDB_INT32, "multilayer", "0: save each frame to one file, 1: load all frames into one multilayer image" }, { GIMP_PDB_INT32, "extract_videotrack", "0:ignore video frames, 1 upto n: extract frames from videotrack" }, { GIMP_PDB_INT32, "extract_audiotrack", "0:ignore audio, 1 upto n: extract audiotrack to .wav file" }, { GIMP_PDB_INT32, "overwrite_mode", "1: overwrite all existing files, other values: cancel if files already exists" }, { GIMP_PDB_INT32, "disable_mmx", "0: use (faster) MMX if available, 1: do not USE MMX (MMX is lossy on lowbitrate streams)" }, { GIMP_PDB_STRING, "preferred_decoder", "NULL, or one of: libmpeg3, quicktime4linux, libavformat" }, { GIMP_PDB_INT32, "exact_seek", "0: NO (enable faster seek ops if available), 1: YES use only sequential read ops, will find exact framenumbers" }, { GIMP_PDB_INT32, "deinterlace", "0: NO, 1: deinterlace odd rows only, 2: deinterlace even rows only, 3: deinterlace split into 2 frames where odd rows-frame is 1st, 4: deinterlace split into 2 frames where even rows-frame is 1st)" }, { GIMP_PDB_FLOAT, "delace_threshold", "0.0 .. no interpolation, 1.0 smooth interpolation at deinterlacing" }, { GIMP_PDB_INT32, "fn_digits", "1 <= fn_digits <= 8, number of digits to use in framenames (use 1 if you dont want leading zeroes) " }, { GIMP_PDB_INT32, "bluebox", "0: NO, 1: YES generate transparency by applying bluebox filter with last values" }, { GIMP_PDB_INT32, "graymask", "0: NO (extract frames 1:1), 1: YES extract generated transparency as gray mask" }, { GIMP_PDB_INT32, "layermask", "0: NO (bluebox shall generate aplha channel), 1: YES (bluebox shall generate layermask)" }, }; static int next_args = sizeof (ext_args) / sizeof (ext_args[0]); INIT_I18N(); gimp_install_procedure (GAP_VEX_PLUG_IN_NAME, "Extract frames from videofiles into animframes or multilayer image", "The specified range of frames (params: begin_pos upto end_pos) is extracted from" " the videofile (param: videoname) and stored as sequence of frame imagefiles" " on disk and load the 1st of the extracted frames as gimp image." " optional you may extract the specified range of frames into one multilayer gimp image" " instead of writing the frames as diskfiles. (par: multilayer == 1)" " Additional you can extract (one) stereo or mono audiotrack" " to uncompressed audiofile (RIFF Wave format .WAV)" " The specified range is used both for video and audio" " (see gap_vid_api docs for supported Videoformats and CODECS)", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Extract Videorange"), NULL, GIMP_PLUGIN, nload_args, nload_return_vals, load_args, load_return_vals); gimp_install_procedure (GAP_VEX_PLUG_IN_NAME_XTNS, "Extract frames from videofiles into animframes or multilayer image", "The specified range of frames (params: begin_pos upto end_pos) is extracted from" " the videofile (param: videoname) and stored as sequence of frame imagefiles" " on disk and load the 1st of the extracted frames as gimp image." " optional you may extract the specified range of frames into one multilayer gimp image" " instead of writing the frames as diskfiles. (par: multilayer == 1)" " Additional you can extract (one) stereo or mono audiotrack" " to uncompressed audiofile (RIFF Wave format .WAV)" " The specified range is used both for video and audio" " (see gap_vid_api docs for supported Videoformats and CODECS)", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Extract Videorange"), NULL, GIMP_PLUGIN, next_args, nload_return_vals, ext_args, load_return_vals); { /* Menu names */ const char *menupath_image_video_split = N_("/Video/Split Video into Frames/"); const char *menupath_toolbox_video_split = N_("/Xtns/Split Video into Frames/"); //gimp_plugin_menu_branch_register("", "Video"); //gimp_plugin_menu_branch_register("/Video", "Split Video into Frames"); //gimp_plugin_menu_branch_register("", "Video"); //gimp_plugin_menu_branch_register("/Video", "Split Video into Frames"); gimp_plugin_menu_register (GAP_VEX_PLUG_IN_NAME, menupath_image_video_split); gimp_plugin_menu_register (GAP_VEX_PLUG_IN_NAME_XTNS, menupath_toolbox_video_split); } } /* end query */ static void run (const gchar *name, /* name of plugin */ gint nparams, /* number of in-paramters */ const GimpParam * param, /* in-parameters */ gint *nreturn_vals, /* number of out-parameters */ GimpParam ** return_vals) /* out-parameters */ { gint argc = 1; gchar **argv = g_new (gchar *, 1); GapVexMainGlobalParams global_pars; GapVexMainGlobalParams *gpp; static GimpParam values[2]; int l_par; int expected_params; const char *l_env; gpp = &global_pars; l_env = g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = GIMP_PDB_CALLING_ERROR; *nreturn_vals = 1; *return_vals = values; gpp->val.run_mode = param[0].data.d_int32; if(gap_debug) printf("\nRUN PROCEDURE %s RUN_MODE %d nparams:%d\n" , name , (int)gpp->val.run_mode , (int)nparams ); gpp->val.generate_alpha_via_bluebox = FALSE; gpp->val.extract_alpha_as_gray_frames = FALSE; gpp->val.extract_with_layermask = FALSE; if(strcmp(name, GAP_VEX_PLUG_IN_NAME) == 0) { l_par = 2; } else { l_par = 0; if(strcmp (name, GAP_VEX_PLUG_IN_NAME_XTNS) != 0) { return; /* calling error */ } } argv[0] = g_strdup (_("MAIN_TST")); gtk_set_locale (); setlocale (LC_NUMERIC, "C"); /* is needed when after gtk_set_locale () * to make sure PASSING FLOAT PDB_PARAMETERS works * (thanks to sven for the tip) */ gtk_init (&argc, &argv); /* init return status * (if this plug-in is compiled without GAP_ENABLE_VIDEOAPI_SUPPORT * it will always fail) */ values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT gap_vex_dlg_init_gpp(gpp); if(gpp->val.run_mode == GIMP_RUN_NONINTERACTIVE) { /* ---------- get batch parameters ----------*/ expected_params = l_par + 21; if(nparams != expected_params) { printf("Calling Error wrong number of params %d (expected: %d)\n" ,(int) nparams ,(int) expected_params); return; /* calling error */ } if(param[l_par + 1].data.d_string != NULL) { g_snprintf(gpp->val.videoname, sizeof(gpp->val.videoname), "%s", param[l_par + 1].data.d_string); } gpp->val.pos_unit = param[l_par + 2].data.d_int32; if(gpp->val.pos_unit == 0) { gpp->val.begin_percent = -1.0; gpp->val.end_percent = -1.0; gpp->val.begin_frame = param[l_par + 3].data.d_float; gpp->val.end_frame = param[l_par + 4].data.d_float; } else { gpp->val.begin_percent = param[l_par + 3].data.d_float; gpp->val.end_percent = param[l_par + 4].data.d_float; gpp->val.begin_frame = -1; gpp->val.end_frame = -1; } if(param[l_par + 5].data.d_string != NULL) { g_snprintf(gpp->val.audiofile, sizeof(gpp->val.audiofile), "%s", param[l_par + 4].data.d_string); } if(param[l_par + 6].data.d_string != NULL) { g_snprintf(gpp->val.basename, sizeof(gpp->val.basename), "%s", param[l_par + 5].data.d_string); } if(param[l_par + 7].data.d_string != NULL) { g_snprintf(gpp->val.extension, sizeof(gpp->val.extension), "%s", param[l_par + 6].data.d_string); } gpp->val.basenum = param[l_par + 8].data.d_int32; gpp->val.multilayer = param[l_par + 9].data.d_int32; gpp->val.videotrack = param[l_par + 10].data.d_int32; gpp->val.audiotrack = param[l_par + 11].data.d_int32; gpp->val.ow_mode = param[l_par + 12].data.d_int32; if(gpp->val.ow_mode != 1) { gpp->val.ow_mode = -1; /* cancel at 1.st existing file (dont overwrite) */ } gpp->val.disable_mmx = param[l_par + 13].data.d_int32; if(param[l_par + 14].data.d_string != NULL) { g_snprintf(gpp->val.preferred_decoder, sizeof(gpp->val.preferred_decoder), "%s", param[l_par + 14].data.d_string); } gpp->val.exact_seek = param[l_par + 15].data.d_int32; gpp->val.deinterlace = param[l_par + 16].data.d_int32; gpp->val.delace_threshold = param[l_par + 17].data.d_float; gpp->val.fn_digits = param[l_par + 18].data.d_int32; gpp->val.generate_alpha_via_bluebox = param[l_par + 19].data.d_int32; gpp->val.extract_alpha_as_gray_frames = param[l_par + 20].data.d_int32; gpp->val.extract_with_layermask = param[l_par + 21].data.d_int32; gpp->val.run = TRUE; } else { /* ---------- dialog ----------*/ gap_vex_dlg_main_dialog (gpp); } /* ---------- extract ----------*/ if(gpp->val.run) { gap_vex_exe_extract_videorange(gpp); if (gpp->val.image_ID >= 0) { *nreturn_vals = 2; values[0].data.d_status = GIMP_PDB_SUCCESS; values[1].type = GIMP_PDB_IMAGE; values[1].data.d_image = gpp->val.image_ID; } else { values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; } } return; /* endif GAP_ENABLE_VIDEOAPI_SUPPORT */ #endif g_message(_("Videoextract is not available because " "GIMP-GAP was configured and compiled with\n " "--disable-videoapi-support") ); return; } /* end run */ gimp-gap-2.6.0+dfsg.orig/gap/gap_frontends_main.c0000644000175000017500000002620311212030253021520 0ustar thibautthibaut/* gap_frontends_main.c * 1999.11.20 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Package * * This Module contains: * - MAIN of GAP_Plugins that are frontends to external programs * those external programs are not available for all * operating systems. * * - query registration of GAP Procedures (Video Menu) in the PDB * - run invoke the selected GAP procedure by its PDB name * * * GAP provides Animation Functions for the gimp, * working on a series of Images stored on disk in gimps .xcf Format. * * Frames are Images with naming convention like this: * Imagename_. * Example: snoopy_0001.xcf, snoopy_0002.xcf, snoopy_0003.xcf * * if gzip is installed on your system you may optional * use gziped xcf frames with extensions ".xcfgz" * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 2.6.4; 2009/02/12 hof: moved gap_decode_mplayer to its own main program. * because all the other frontends are OLD and * will NO LONGER be installed per default but only on explicite * configuration request. * gimp 2.1.0; 2004/12/06 hof: added gap_decode_mplayer * gimp 1.1.29b; 2000/11/25 hof: use gap lock procedures, update e-mail adress + main version * gimp 1.1.11b; 1999/11/20 hof: added gap_decode_xanim, fixed typo in mpeg encoder menu path * based on parts that were found in gap_main.c before. */ /* SYTEM (UNIX) includes */ #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "config.h" #include "gap-intl.h" #include "libgimp/gimp.h" /* GAP includes */ #include "gap_lib.h" #include "gap_mpege.h" #include "gap_decode_xanim.h" #include "gap_arr_dialog.h" #include "gap_lock.h" /* ------------------------ * global gap DEBUG switch * ------------------------ */ /* int gap_debug = 1; */ /* print debug infos */ /* int gap_debug = 0; */ /* 0: dont print debug infos */ int gap_debug = 0; #define GAP_XANIM_PLUGIN_NAME "plug_in_gap_xanim_decode" #define GAP_XANIM_PLUGIN_NAME_TOOLBOX "plug_in_gap_xanim_decode_toolbox" #define GAP_MPEG_ENCODE_PLUGIN_NAME "plug_in_gap_mpeg_encode" #define GAP_MPEG2_ENCODE_PLUGIN_NAME "plug_in_gap_mpeg2encode" static void query(void); static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; MAIN () static void query () { static GimpParamDef args_xanim[] = { {GIMP_PDB_INT32, "run_mode", "Interactive"}, {GIMP_PDB_IMAGE, "image", "(unused)"}, {GIMP_PDB_DRAWABLE, "drawable", "(unused)"}, }; static GimpParamDef args_xanim_ext[] = { {GIMP_PDB_INT32, "run_mode", "Interactive"}, }; static GimpParamDef args_mpege[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (one of the video frames)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, }; static GimpParamDef *return_vals = NULL; static int nreturn_vals = 0; gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); gimp_install_procedure(GAP_XANIM_PLUGIN_NAME, "This plugin calls xanim to split any video to video frames. " "(xanim exporting edition must be installed on your system)", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("XANIM based extraction..."), NULL, GIMP_PLUGIN, G_N_ELEMENTS (args_xanim), nreturn_vals, args_xanim, return_vals); gimp_install_procedure(GAP_XANIM_PLUGIN_NAME_TOOLBOX, "This plugin calls xanim to split any video to video frames. " "(xanim exporting edition must be installed on your system)", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("XANIM based extraction..."), NULL, GIMP_PLUGIN, G_N_ELEMENTS (args_xanim_ext), nreturn_vals, args_xanim_ext, return_vals); gimp_install_procedure(GAP_MPEG_ENCODE_PLUGIN_NAME, "This plugin calls mpeg_encode to convert video frames to MPEG1, or just generates a param file for mpeg_encode. (mpeg_encode must be installed on your system)", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("MPEG1..."), "*", GIMP_PLUGIN, G_N_ELEMENTS (args_mpege), nreturn_vals, args_mpege, return_vals); gimp_install_procedure(GAP_MPEG2_ENCODE_PLUGIN_NAME, "This plugin calls mpeg2encode to convert video frames to MPEG1 or MPEG2, or just generates a param file for mpeg2encode. (mpeg2encode must be installed on your system)", "", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("MPEG2..."), "*", GIMP_PLUGIN, G_N_ELEMENTS (args_mpege), nreturn_vals, args_mpege, return_vals); { /* Menu names */ const char *menupath_image_video_encode = N_("/Video/Encode/"); const char *menupath_image_video_split = N_("/Video/Split Video into Frames/"); const char *menupath_toolbox_video_split = N_("/Xtns/Split Video into Frames/"); //gimp_plugin_menu_branch_register("", "Video"); //gimp_plugin_menu_branch_register("/Video", "Encode"); //gimp_plugin_menu_branch_register("/Video", "Split Video into Frames"); //gimp_plugin_menu_branch_register("", "Video"); //gimp_plugin_menu_branch_register("/Video", "Encode"); //gimp_plugin_menu_branch_register("/Video", "Split Video into Frames"); gimp_plugin_menu_register (GAP_XANIM_PLUGIN_NAME, menupath_image_video_split); gimp_plugin_menu_register (GAP_MPEG_ENCODE_PLUGIN_NAME, menupath_image_video_encode); gimp_plugin_menu_register (GAP_MPEG2_ENCODE_PLUGIN_NAME, menupath_image_video_encode); gimp_plugin_menu_register (GAP_XANIM_PLUGIN_NAME_TOOLBOX, menupath_toolbox_video_split); } } /* end query */ static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals) { const char *l_env; char l_extension[32]; static GimpParam values[2]; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; gint32 image_id; gint32 lock_image_id; gint32 nr; gint32 l_rc; *nreturn_vals = 1; *return_vals = values; nr = 0; l_rc = 0; INIT_I18N (); l_env = g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } run_mode = param[0].data.d_int32; image_id = -1; lock_image_id = image_id; if(gap_debug) fprintf(stderr, "\n\ngap_main: debug name = %s\n", name); if ((strcmp (name, GAP_MPEG_ENCODE_PLUGIN_NAME) == 0) || (strcmp (name, GAP_MPEG2_ENCODE_PLUGIN_NAME) == 0)) { image_id = param[1].data.d_image; lock_image_id = image_id; /* check for locks */ if(gap_lock_check_for_lock(lock_image_id, run_mode)) { status = GIMP_PDB_EXECUTION_ERROR; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; return ; } /* set LOCK on current image (for all gap_plugins) */ gap_lock_set_lock(lock_image_id); } if ((strcmp (name, GAP_XANIM_PLUGIN_NAME) == 0) || (strcmp (name, GAP_XANIM_PLUGIN_NAME_TOOLBOX) == 0)) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { status = GIMP_PDB_CALLING_ERROR; /* planed: define non interactive PARAMS */ } if (status == GIMP_PDB_SUCCESS) { /* planed: define non interactive PARAMS */ l_rc = gap_xanim_decode(run_mode /* more PARAMS */); } } else if (strcmp (name, GAP_MPEG_ENCODE_PLUGIN_NAME) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != 3) { status = GIMP_PDB_CALLING_ERROR; } else { /* planed: define non interactive PARAMS */ l_extension[sizeof(l_extension) -1] = '\0'; } } if (status == GIMP_PDB_SUCCESS) { image_id = param[1].data.d_image; /* planed: define non interactive PARAMS */ l_rc = gap_mpeg_encode(run_mode, image_id, GAP_MPEGE_MPEG_ENCODE /* more PARAMS */); } } else if (strcmp (name, GAP_MPEG2_ENCODE_PLUGIN_NAME) == 0) { if (run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != 3) { status = GIMP_PDB_CALLING_ERROR; } else { /* planed: define non interactive PARAMS */ l_extension[sizeof(l_extension) -1] = '\0'; } } if (status == GIMP_PDB_SUCCESS) { image_id = param[1].data.d_image; /* planed: define non interactive PARAMS */ l_rc = gap_mpeg_encode(run_mode, image_id, GAP_MPEGE_MPEG2ENCODE /* more PARAMS */); } } /* ---------- return handling --------- */ if(l_rc < 0) { status = GIMP_PDB_EXECUTION_ERROR; } if (run_mode != GIMP_RUN_NONINTERACTIVE) gimp_displays_flush(); values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; if ((strcmp (name, GAP_MPEG_ENCODE_PLUGIN_NAME) == 0) || (strcmp (name, GAP_MPEG2_ENCODE_PLUGIN_NAME) == 0)) { /* remove LOCK on this image for all gap_plugins */ gap_lock_remove_lock(lock_image_id); } } gimp-gap-2.6.0+dfsg.orig/gap/gap_lastvaldesc.h0000644000175000017500000000351311212030253021023 0ustar thibautthibaut/* gap_lastvaldesc.h * * GAP ... Gimp Animation Plugins * * This Module contains: * Headers and types to register a plugin's LAST_VALUES buffer description * (needed for animated filtercalls using a common iterator procedure) * * should be a part of future libgimp for easy use in many plugin's. * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 2002/09/21 hof: created. */ #ifndef __GAP_LASTVALDESC_H__ #define __GAP_LASTVALDESC_H__ /* gimplastvaldesc should become part of libgimp in the future. * if this will come true, HAVE_LASTVALDESC_H will also become DEFINED. */ #ifdef HAVE_LASTVALDESC_H #include "libgimp/gimp.h" #include "libgimp/gimplastvaldesc.h" #else /* for now GAP Sources include a private version of gimplastvaldesc.h gimplastvaldesc.c Modules * and must include them explicite because HAVE_LASTVALDESC_H is not defined * (i dont know, if gimplastvaldesc will be a part of libgimp someday -- hof) */ #include "libgimp/gimp.h" #include "gimplastvaldesc.h" #endif #endif /* __GAP_LASTVALDESC_H__ */ gimp-gap-2.6.0+dfsg.orig/gap/README0000644000175000017500000000014011212030253016367 0ustar thibautthibautThe content of this file was splitted into separate files and was moved to the docs directory. gimp-gap-2.6.0+dfsg.orig/gap/gap_pdb_calls.c0000644000175000017500000003415511212030253020442 0ustar thibautthibaut/* gap_pdb_calls.c * * this module contains wraper calls of procedures in the GIMPs Procedural Database * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 2005/04/03 carol: changed deprecated procedure 'gimp_rotate' to 'gimp_drawable_transform_rotate_default' * version 1.3.25a; 2004/01/20 hof: removed gap_pdb_gimp_file_load_thumbnail * version 1.3.14c; 2003/06/15 hof: take care of gimp_image_thumbnail 128x128 sizelimit * version 1.3.14b; 2003/06/03 hof: gboolean retcode for thumbnail procedures * version 1.3.14a; 2003/05/24 hof: moved vin Procedures to gap_vin module * version 1.3.5a; 2002/04/20 hof: gap_pdb_gimp_layer_new_from_drawable. (removed set_drabale) * version 1.3.4a; 2002/03/12 hof: removed duplicate wrappers that are available in libgimp too. * version 1.2.2b; 2001/12/09 hof: wrappers for tattoo procedures * version 1.1.16a; 2000/02/05 hof: path lockedstaus * version 1.1.15b; 2000/01/30 hof: image parasites * version 1.1.15a; 2000/01/26 hof: pathes * removed old gimp 1.0.x PDB Interfaces * version 1.1.14a; 2000/01/09 hof: thumbnail save/load, * Procedures for video_info file * version 0.98.00; 1998/11/28 hof: 1.st (pre) release (GAP port to GIMP 1.1) */ #include #include #include /* GIMP includes */ #include "libgimp/gimp.h" /* GAP includes */ #include "gap_pdb_calls.h" extern int gap_debug; /* ============================================================================ * p_status_to_string * ============================================================================ */ const char * p_status_to_string(int status) { switch (status) { case GIMP_PDB_EXECUTION_ERROR: return ("GIMP_PDB_EXECUTION_ERROR"); case GIMP_PDB_CALLING_ERROR: return ("GIMP_PDB_CALLING_ERROR"); case GIMP_PDB_PASS_THROUGH: return ("GIMP_PDB_PASS_THROUGH"); case GIMP_PDB_SUCCESS: return ("GIMP_PDB_SUCCESS"); case GIMP_PDB_CANCEL: return ("GIMP_PDB_CANCEL"); default: return ("* unknown *"); } } /* end p_status_to_string */ /* check if procedure name is available in the PDB. * this procedure reads all available pdb procedure names into static memory * when called 1st time. and checks the specified name against the memory. * Introduced with GIMP-2.6 that produces annoying Error messages on the GUI * when a plug attempt to query information for an unknown name. * This workaround help to avoid those error messages, * but makes GAP filter all layer feature slower. */ gboolean gap_pdb_procedure_name_available (const gchar *search_name) { static gboolean initialized = FALSE; static gchar **proc_list = NULL; static gint num_procs = 0; int loop; gboolean found; found = FALSE; if (!initialized) { /* query for all elements (only at 1.st call in this process) * if we apply the search string to gimp_plugins_query * we get no result, because the search will query MenuPath * and not for the realname of the plug-in) */ // gimp_procedural_db_query gimp_procedural_db_query (".*", ".*", ".*", ".*", ".*", ".*", ".*", &num_procs, &proc_list); initialized = TRUE; if(gap_debug) { for (loop = 0; loop < num_procs; loop++) { printf("PDBname:%s\t\search_name:%s\n", proc_list[loop], search_name); } } } if (initialized) { for (loop = 0; loop < num_procs; loop++) { if(strcmp(search_name, proc_list[loop]) == 0) { found = TRUE; break; /* stop at 1st match */ } } } /* Dont Destroy, but Keep the Returned Parameters for the lifetime of this process */ /* gimp_destroy_params (return_vals, nreturn_vals); */ return (found); } /* end gap_pdb_procedure_name_available */ /* ============================================================================ * gap_pdb_procedure_available * if requested procedure is available in the PDB return the number of args * (0 upto n) that are needed to call the procedure. * if not available return -1 * ============================================================================ */ gint gap_pdb_procedure_available(char *proc_name) { gint l_nparams; gint l_nreturn_vals; GimpPDBProcType l_proc_type; gchar *l_proc_blurb; gchar *l_proc_help; gchar *l_proc_author; gchar *l_proc_copyright; gchar *l_proc_date; GimpParamDef *l_params; GimpParamDef *l_return_vals; gint l_rc; l_rc = 0; /* Query the gimp application's procedural database * regarding a particular procedure. */ if (gimp_procedural_db_proc_info (proc_name, &l_proc_blurb, &l_proc_help, &l_proc_author, &l_proc_copyright, &l_proc_date, &l_proc_type, &l_nparams, &l_nreturn_vals, &l_params, &l_return_vals)) { /* procedure found in PDB */ return (l_nparams); } printf("Warning: Procedure %s not found.\n", proc_name); return -1; } /* end gap_pdb_procedure_available */ /* ---------------------- PDB procedure calls -------------------------- */ /* ============================================================================ * gap_pdb_gimp_rotate_degree * PDB call of 'gimp_rotate' * ============================================================================ */ gint32 gap_pdb_gimp_rotate_degree(gint32 drawable_id, gboolean interpolation, gdouble angle_deg) { gdouble l_angle_rad; l_angle_rad = (angle_deg * G_PI) / 180.0; return(gimp_drawable_transform_rotate_default(drawable_id , l_angle_rad , FALSE /* auto_center */ , 0 /* center_x */ , 0 /* center_y */ , interpolation , FALSE /* clip_results */ )); } /* end gap_pdb_gimp_rotate_degree */ /* ============================================================================ * gap_pdb_gimp_displays_reconnect * * ============================================================================ */ gboolean gap_pdb_gimp_displays_reconnect(gint32 old_image_id, gint32 new_image_id) { static char *l_called_proc = "gimp_displays_reconnect"; GimpParam *return_vals; int nreturn_vals; return_vals = gimp_run_procedure (l_called_proc, &nreturn_vals, GIMP_PDB_IMAGE, old_image_id, GIMP_PDB_IMAGE, new_image_id, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { gimp_destroy_params(return_vals, nreturn_vals); return (TRUE); /* OK */ } gimp_destroy_params(return_vals, nreturn_vals); printf("GAP: Error: PDB call of %s failed, d_status:%d %s\n" , l_called_proc , (int)return_vals[0].data.d_status , p_status_to_string(return_vals[0].data.d_status) ); return(FALSE); } /* end gap_pdb_gimp_displays_reconnect */ /* ============================================================================ * gap_pdb_gimp_layer_new_from_drawable * * ============================================================================ */ gint32 gap_pdb_gimp_layer_new_from_drawable(gint32 drawable_id, gint32 dst_image_id) { static char *l_called_proc = "gimp_layer_new_from_drawable"; GimpParam *return_vals; int nreturn_vals; gint32 layer_id; return_vals = gimp_run_procedure (l_called_proc, &nreturn_vals, GIMP_PDB_DRAWABLE, drawable_id, GIMP_PDB_IMAGE, dst_image_id, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { layer_id = return_vals[1].data.d_int32; gimp_destroy_params(return_vals, nreturn_vals); return(layer_id); /* return the resulting layer_id */ } gimp_destroy_params(return_vals, nreturn_vals); printf("GAP: Error: PDB call of %s failed, d_status:%d %s\n" , l_called_proc , (int)return_vals[0].data.d_status , p_status_to_string(return_vals[0].data.d_status) ); return(-1); } /* end gap_pdb_gimp_layer_new_from_drawable */ /* ============================================================================ * gap_pdb_gimp_file_save_thumbnail * * ============================================================================ */ gboolean gap_pdb_gimp_file_save_thumbnail(gint32 image_id, char* filename) { static char *l_called_proc = "gimp_file_save_thumbnail"; GimpParam *return_vals; int nreturn_vals; /*if(gap_debug) printf("gap_pdb_gimp_file_save_thumbnail: image_id:%d %s\n", (int)image_id, filename);*/ return_vals = gimp_run_procedure (l_called_proc, &nreturn_vals, GIMP_PDB_IMAGE, image_id, GIMP_PDB_STRING, filename, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { gimp_destroy_params(return_vals, nreturn_vals); return (TRUE); } gimp_destroy_params(return_vals, nreturn_vals); printf("GAP: Error: PDB call of %s failed on file: %s (image_id:%d), d_status:%d %s\n" , l_called_proc , filename , (int)image_id , (int)return_vals[0].data.d_status , p_status_to_string(return_vals[0].data.d_status) ); return(FALSE); } /* end gap_pdb_gimp_file_save_thumbnail */ /* ============================================================================ * gap_pdb_gimp_image_thumbnail * * ============================================================================ */ gboolean gap_pdb_gimp_image_thumbnail(gint32 image_id, gint32 width, gint32 height, gint32 *th_width, gint32 *th_height, gint32 *th_bpp, gint32 *th_data_count, unsigned char **th_data) { static char *l_called_proc = "gimp_image_thumbnail"; GimpParam *return_vals; int nreturn_vals; *th_data = NULL; /* gimp_image_thumbnail * has a limit of maximal 128x128 pixels. (in gimp-1.3.14) * On bigger sizes it returns success, along with a th_data == NULL. * THIS workaround makes a 2nd try with reduced size. * TODO: * - if gimp keeps the size limit until the stable 1.4 release * i suggest to check for sizs < 128 before the 1.st attemp. * (for better performance on bigger thumbnail sizes) * - if there will be no size limit in the future, * the 2.nd try cold be removed (just for cleanup reasons) * hof, 2003.06.17 */ workaround: return_vals = gimp_run_procedure (l_called_proc, &nreturn_vals, GIMP_PDB_IMAGE, image_id, GIMP_PDB_INT32, width, GIMP_PDB_INT32, height, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { /* in case of success dont gimp_destroy_params * because thumbnail data is returned without copying * for performance reasons */ *th_width = return_vals[1].data.d_int32; *th_height = return_vals[2].data.d_int32; *th_bpp = return_vals[3].data.d_int32; *th_data_count = return_vals[4].data.d_int32; *th_data = (unsigned char *)return_vals[5].data.d_int8array; if (*th_data == NULL) { if(gap_debug) { printf("(PDB_WRAPPER workaround for gimp_image_thumbnail GIMP_PDB_SUCCESS, th_data:%d (%d x %d) \n" , (int)return_vals[5].data.d_int8array , (int)return_vals[1].data.d_int32 , (int)return_vals[2].data.d_int32 ); } if(MAX(width, height) > 128) { if(width > height) { height = (128 * height) / width; width = 128; } else { width = (128 * width) / height; height = 128; } goto workaround; } return(FALSE); /* this is no success */ } return(TRUE); /* OK */ } gimp_destroy_params(return_vals, nreturn_vals); printf("GAP: Error: PDB call of %s failed, d_status:%d %s\n" , l_called_proc , (int)return_vals[0].data.d_status , p_status_to_string(return_vals[0].data.d_status) ); return(FALSE); } /* end gap_pdb_gimp_image_thumbnail */ gimp-gap-2.6.0+dfsg.orig/gap/gap_story_render_processor.h0000644000175000017500000002042311212030253023333 0ustar thibautthibaut/* gap_story_render_processor.h * * GAP storyboard rendering processor. * */ /* * 2006.06.25 hof - created (moved stuff from the former gap_gve_story modules to this new module) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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_STORY_RENDER_PROCESSOR_H #define GAP_STORY_RENDER_PROCESSOR_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 #include "gap_story_file.h" #include "gap_lib_common_defs.h" #include "gap_story_render_types.h" /* G_DIR_SEPARATOR (is defined in glib.h if you have glib-1.2.0 or later) */ #ifdef G_OS_WIN32 /* Filenames in WIN/DOS Style */ #ifndef G_DIR_SEPARATOR #define G_DIR_SEPARATOR '\\' #endif #define DIR_ROOT ':' #else /* !G_OS_WIN32 */ /* Filenames in UNIX Style */ #ifndef G_DIR_SEPARATOR #define G_DIR_SEPARATOR '/' #endif #define DIR_ROOT '/' #endif /* !G_OS_WIN32 */ #define GAP_STB_RENDER_GVA_FRAMES_TO_KEEP_CACHED 36 #define GAP_VID_ENC_SAVE_MULTILAYER "GAP_VID_ENC_SAVE_MULTILAYER" #define GAP_VID_ENC_SAVE_FLAT "GAP_VID_ENC_SAVE_FLAT" #define GAP_VID_ENC_MONITOR "GAP_VID_ENC_MONITOR" #define GAP_VID_CHCHK_FLAG_SIZE 1 #define GAP_VID_CHCHK_FLAG_MPEG_INTEGRITY 2 #define GAP_VID_CHCHK_FLAG_JPG 4 #define GAP_VID_CHCHK_FLAG_VCODEC_NAME 8 #define GAP_VID_CHCHK_FLAG_FULL_FRAME 16 #define GAP_VID_CHCHK_FLAG_PNG 32 /* codec name list element */ typedef struct GapCodecNameElem { guchar *codec_name; gint32 video_id; void *next; } GapCodecNameElem; /* --------------------------*/ /* PROCEDURE DECLARATIONS */ /* --------------------------*/ void gap_story_render_debug_print_framerange_list(GapStoryRenderFrameRangeElem *frn_list , gint32 track /* -1 show all tracks */ ); void gap_story_render_debug_print_audiorange_list(GapStoryRenderAudioRangeElem *aud_list , gint32 track /* -1 show all tracks */ ); void gap_story_render_drop_image_cache(void); void gap_story_render_remove_tmp_audiofiles(GapStoryRenderVidHandle *vidhand); void gap_story_render_drop_audio_cache(void); gint32 gap_story_render_fetch_composite_image(GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr /* starts at 1 */ , gint32 vid_width /* desired Video Width in pixels */ , gint32 vid_height /* desired Video Height in pixels */ , char *filtermacro_file /* NULL if no filtermacro is used */ , gint32 *layer_id /* output: Id of the only layer in the composite image */ ); gboolean gap_story_render_fetch_composite_image_or_chunk(GapStoryRenderVidHandle *vidhand , gint32 master_frame_nr /* starts at 1 */ , gint32 vid_width /* desired Video Width in pixels */ , gint32 vid_height /* desired Video Height in pixels */ , char *filtermacro_file /* NULL if no filtermacro is used */ , gint32 *layer_id /* output: Id of the only layer in the composite image */ , gint32 *image_id /* output: Id of the only layer in the composite image */ , gboolean dont_recode_flag /* IN: TRUE try to fetch comressed chunk if possible */ , GapCodecNameElem *vcodec_list /* IN: list of video_codec names that are compatible to the calling encoder program */ , gboolean *force_keyframe /* OUT: the calling encoder should encode an I-Frame */ , unsigned char *video_frame_chunk_data /* OUT: copy of the already compressed video frame from source video */ , gint32 *video_frame_chunk_size /* OUT: total size of frame (may include a videoformat specific frameheader) */ , gint32 video_frame_chunk_maxsize /* IN: sizelimit (larger chunks are not fetched) */ , gdouble master_framerate , gint32 max_master_frame_nr /* the number of frames that will be encoded in total */ , gint32 *video_frame_chunk_hdr_size /* OUT: size of videoformat specific frameheader (0 if has no hdr) */ , gint32 check_flags /* IN: combination of GAP_VID_CHCHK_FLAG_* flag values */ ); GapStoryRenderVidHandle * gap_story_render_open_vid_handle_from_stb( GapStoryBoard *stb_ptr ,gint32 *frame_count /* output total frame_count , or 0 on failure */ ); GapStoryRenderVidHandle * gap_story_render_open_vid_handle( GapLibTypeInputRange input_mode ,gint32 image_id ,const char *storyboard_file ,const char *basename ,const char *ext ,gint32 frame_from ,gint32 frame_to ,gint32 *frame_count /* output total frame_count , or 0 on failure */ ); GapStoryRenderVidHandle * gap_story_render_open_extended_video_handle( gboolean ignore_audio ,gboolean igore_video ,gboolean create_audio_tmp_files ,gdouble *progress_ptr ,char *status_msg ,gint32 status_msg_len ,GapLibTypeInputRange input_mode ,const char *imagename ,const char *storyboard_file ,const char *basename ,const char *ext ,gint32 frame_from ,gint32 frame_to ,gint32 *frame_count /* output total frame_count , or 0 on failure */ ); void gap_story_render_close_vid_handle(GapStoryRenderVidHandle *vidhand); void gap_story_render_set_audio_resampling_program( GapStoryRenderVidHandle *vidhand , char *util_sox , char *util_sox_options ); void gap_story_render_set_stb_error(GapStoryRenderErrors *sterr, char *errtext); void gap_story_render_set_stb_warning(GapStoryRenderErrors *sterr, char *errtext); void gap_story_render_calc_audio_playtime(GapStoryRenderVidHandle *vidhand, gdouble *aud_total_sec); gboolean gap_story_render_create_composite_audiofile(GapStoryRenderVidHandle *vidhand , char *comp_audiofile ); guchar * gap_story_convert_layer_to_RGB_thdata(gint32 l_layer_id, gint32 *RAW_size , gint32 *th_bpp , gint32 *th_width , gint32 *th_height ); guchar * gap_story_render_fetch_composite_vthumb(GapStoryRenderVidHandle *stb_comp_vidhand , gint32 framenumber , gint32 width, gint32 height ); #endif /* GAP_STORY_RENDER_PROCESSOR_H */ gimp-gap-2.6.0+dfsg.orig/gap/gap-dup-continue.scm0000644000175000017500000000327111212030253021402 0ustar thibautthibaut; The GIMP -- an image manipulation program ; Copyright (C) 1995 Spencer Kimball and Peter Mattis ; ; Duplicate the current AnimationImage ; and continue (== load the duplicate as new current frame) ; ; ; 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., 675 Mass Ave, Cambridge, MA 02139, USA. (define (script-fu-gap-dup-continue image drawable) (let* ( (rangefrom -1) (rangeto -1) (ncopies 1) ) ; rangefrom rangeto: value -1 refers to the current frame (plug-in-gap-dup RUN-NONINTERACTIVE image drawable ncopies rangefrom rangeto) (plug-in-gap-next RUN-NONINTERACTIVE image drawable) (gimp-displays-flush) ) ) (script-fu-register "script-fu-gap-dup-continue" _"/Video/Duplicate Continue" "Duplicate the current AnimationImage and load the duplicate as new current frame" "Wolfgang Hofer " "Wolfgang Hofer" "2004/06/12" "RGB RGBA GRAY GRAYA" SF-IMAGE "Image" 0 SF-DRAWABLE "Drawable" 0) gimp-gap-2.6.0+dfsg.orig/gap/gap_wr_color_levels.c0000644000175000017500000006437311212030253021724 0ustar thibautthibaut/* gap_wr_color_levels.c * 2002.Oct.27 hof (Wolfgang Hofer) * * Wrapper Plugin for GIMP Color Levels tool * * Warning: This is just a QUICK HACK to enable * Animated Filterapply in conjunction with the * GIMP Color Levels Tool. * * It provides a primitive Dialog Interface where you * can call the Color Levels Tool * * Further it has an Interface to 'Run_with_last_values' * and an Iterator Procedure. * (This enables the 'Animated Filter Call' from * the GAP's Menu Filters->Filter all Layers) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* Revision history * (2004/01/15) v1.3.24a hof: adapted for gimp-1.3.x and gtk+2.2 API * (2002/10/27) v1.03 hof: - created */ #include "config.h" #include #include #include #include #include #include #include "gap-intl.h" /* Defines */ #define PLUG_IN_NAME "plug-in-wr-color-levels" #define PLUG_IN_IMAGE_TYPES "RGB*, GRAY*" #define PLUG_IN_AUTHOR "Wolfgang Hofer (hof@gimp.org)" #define PLUG_IN_COPYRIGHT "Wolfgang Hofer" #define PLUG_IN_DESCRIPTION "Wrapper call for GIMP Levels Color Tool" #define PLUG_IN_ITER_NAME "plug-in-wr-color-levels-Iterator" #define PLUG_IN_DATA_ITER_FROM "plug-in-wr-color-levels-ITER-FROM" #define PLUG_IN_DATA_ITER_TO "plug-in-wr-color-levels-ITER-TO" #define PLUG_IN_HELP_ID "plug-in-wr-color-levels" typedef struct { gint32 channel; gint32 low_input; gint32 high_input; gdouble gamma; gint32 low_output; gint32 high_output; } wr_levels_val_t; typedef struct _WrDialog WrDialog; struct _WrDialog { gint run; gint show_progress; GtkWidget *shell; GtkWidget *radio_master; GtkWidget *radio_red; GtkWidget *radio_green; GtkWidget *radio_blue; GtkWidget *radio_alpha; wr_levels_val_t *vals; }; WrDialog *do_dialog (wr_levels_val_t *); static void query (void); static void run(const gchar *name , gint nparams , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals); /* Global Variables */ GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run /* run_proc */ }; gint gap_debug = 0; /* 0.. no debug, 1 .. print debug messages */ /* -------------- * procedures * -------------- */ /* * Delta Calculations for the iterator */ static void p_delta_gdouble (gdouble *val, gdouble val_from, gdouble val_to, gint32 total_steps, gdouble current_step) { gdouble delta; if(total_steps < 1) return; delta = ((gdouble)(val_to - val_from) / (gdouble)total_steps) * ((gdouble)total_steps - current_step); *val = val_from + delta; } static void p_delta_gint32 (gint32 *val, gint32 val_from, gint32 val_to, gint32 total_steps, gdouble current_step) { gdouble delta; if(total_steps < 1) return; delta = ((gdouble)(val_to - val_from) / (gdouble)total_steps) * ((gdouble)total_steps - current_step); *val = val_from + delta; } /* ============================================================================ * p_gimp_levels * * ============================================================================ */ gint32 p_gimp_levels (gint32 drawable_id, gint32 channel, gint32 low_input, gint32 high_input, gdouble gamma, gint32 low_output, gint32 high_output ) { static char *l_procname = "gimp_levels"; GimpParam *return_vals; int nreturn_vals; return_vals = gimp_run_procedure (l_procname, &nreturn_vals, GIMP_PDB_DRAWABLE, drawable_id, GIMP_PDB_INT32, channel, GIMP_PDB_INT32, low_input, GIMP_PDB_INT32, high_input, GIMP_PDB_FLOAT, gamma, GIMP_PDB_INT32, low_output, GIMP_PDB_INT32, high_output, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { gimp_destroy_params(return_vals, nreturn_vals); return (0); } gimp_destroy_params(return_vals, nreturn_vals); printf("Error: PDB call of %s failed status:%d\n", l_procname, (int)return_vals[0].data.d_status); return(-1); } /* end p_gimp_levels */ static void p_run_levels_tool(gint32 drawable_id, wr_levels_val_t *cuvals) { if(gap_debug) { printf("p_run_levels_tool: drawable_id :%d\n", (int)drawable_id); printf("p_run_levels_tool: channel:%d\n", (int)cuvals->channel); printf("p_run_levels_tool: low_input:%d\n", (int)cuvals->low_input); printf("p_run_levels_tool: high_input:%d\n", (int)cuvals->high_input); printf("p_run_levels_tool: gamma:%f\n", (float)cuvals->gamma); printf("p_run_levels_tool: low_output:%d\n", (int)cuvals->low_output); printf("p_run_levels_tool: high_output:%d\n", (int)cuvals->high_output); } p_gimp_levels(drawable_id , cuvals->channel , cuvals->low_input , cuvals->high_input , cuvals->gamma , cuvals->low_output , cuvals->high_output ); } MAIN () static void query (void) { static GimpParamDef args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, { GIMP_PDB_IMAGE, "image", "Input image" }, { GIMP_PDB_DRAWABLE, "drawable", "Input drawable (must be a layer without layermask)"}, { GIMP_PDB_INT32, "channel", " affected channel: VALUE_LUT (0), RED_LUT(1), GREENLUT(2), BLUE_LUT(3), ALPHA_LUT(4)"}, { GIMP_PDB_INT32, "low_input", "Intensity of lowest input (0 <= low_input <= 255) "}, { GIMP_PDB_INT32, "high_input", "Intensity of highest input (0 <= highest_input <= 255) "}, { GIMP_PDB_FLOAT, "gamma", "Gamma correction factor (0.1 <= gamma >= 10"}, { GIMP_PDB_INT32, "low_output", "Intensity of lowest output (0 <= low_output <= 255) "}, { GIMP_PDB_INT32, "high_output", "Intensity of highest output (0 <= highest_output <= 255) "}, }; static int nargs = sizeof(args) / sizeof(args[0]); static GimpParamDef return_vals[] = { { GIMP_PDB_DRAWABLE, "the_drawable", "the handled drawable" } }; static int nreturn_vals = sizeof(return_vals) / sizeof(return_vals[0]); static GimpParamDef args_iter[] = { {GIMP_PDB_INT32, "run_mode", "non-interactive"}, {GIMP_PDB_INT32, "total_steps", "total number of steps (# of layers-1 to apply the related plug-in)"}, {GIMP_PDB_FLOAT, "current_step", "current (for linear iterations this is the layerstack position, otherwise some value inbetween)"}, {GIMP_PDB_INT32, "len_struct", "length of stored data structure with id is equal to the plug_in proc_name"}, }; static int nargs_iter = sizeof(args_iter) / sizeof(args_iter[0]); static GimpParamDef *return_iter = NULL; static int nreturn_iter = 0; gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); /* the actual installation of the bend plugin */ gimp_install_procedure (PLUG_IN_NAME, PLUG_IN_DESCRIPTION, "This Plugin is a wrapper to call the GIMP Levels Color Tool (gimp_levels)" " it has a simplified Dialog (without preview) where you can enter the parameters" " this wrapper is useful for animated filtercalls and provides " " a PDB interface that runs in GIMP_RUN_WITH_LAST_VALUES mode" " and also provides an Iterator Procedure for animated calls" , PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("Levels..."), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, nargs, nreturn_vals, args, return_vals); /* the installation of the Iterator extension for the bend plugin */ gimp_install_procedure (PLUG_IN_ITER_NAME, "This extension calculates the modified values for one iterationstep for the call of plug_in_curve_bend", "", PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, NULL, /* do not appear in menus */ NULL, GIMP_PLUGIN, nargs_iter, nreturn_iter, args_iter, return_iter); { /* Menu names */ const char *menupath_image_video_layer_colors = N_("/Video/Layer/Colors/"); //gimp_plugin_menu_branch_register("", "Video"); //gimp_plugin_menu_branch_register("/Video", "Layer"); //gimp_plugin_menu_branch_register("/Video/Layer", "Colors"); gimp_plugin_menu_register (PLUG_IN_NAME, menupath_image_video_layer_colors); } } static void run(const gchar *name , gint nparams , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals) { wr_levels_val_t l_cuvals; WrDialog *wcd = NULL; gint32 l_image_id = -1; gint32 l_drawable_id = -1; gint32 l_handled_drawable_id = -1; /* Get the runmode from the in-parameters */ GimpRunMode run_mode = param[0].data.d_int32; if(gap_debug) { printf("START plug-in-wr-color-levels\n"); } /* status variable, use it to check for errors in invocation usualy only during non-interactive calling */ GimpPDBStatusType status = GIMP_PDB_SUCCESS; /*always return at least the status to the caller. */ static GimpParam values[2]; INIT_I18N(); /* initialize the return of the status */ values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; values[1].type = GIMP_PDB_DRAWABLE; values[1].data.d_int32 = -1; *nreturn_vals = 2; *return_vals = values; /* the Iterator Stuff */ if (strcmp (name, PLUG_IN_ITER_NAME) == 0) { gint32 len_struct; gint32 total_steps; gdouble current_step; wr_levels_val_t cval; /* current values while iterating */ wr_levels_val_t cval_from, cval_to; /* start and end values */ /* Iterator procedure for animated calls is usually called from * "plug_in_gap_layers_run_animfilter" * (always run noninteractive) */ if ((run_mode == GIMP_RUN_NONINTERACTIVE) && (nparams == 4)) { total_steps = param[1].data.d_int32; current_step = param[2].data.d_float; len_struct = param[3].data.d_int32; if(len_struct == sizeof(cval)) { /* get _FROM and _TO data, * This data was stored by plug_in_gap_layers_run_animfilter */ gimp_get_data(PLUG_IN_DATA_ITER_FROM, &cval_from); gimp_get_data(PLUG_IN_DATA_ITER_TO, &cval_to); memcpy(&cval, &cval_from, sizeof(cval)); /* do not iterate channel ! (makes no sense) */ p_delta_gint32 (&cval.low_input, cval_from.low_input, cval_to.low_input, total_steps, current_step); p_delta_gint32 (&cval.high_input, cval_from.high_input, cval_to.high_input, total_steps, current_step); p_delta_gdouble(&cval.gamma, cval_from.gamma, cval_to.gamma, total_steps, current_step); p_delta_gint32 (&cval.low_output, cval_from.low_output, cval_to.low_output, total_steps, current_step); p_delta_gint32 (&cval.high_output, cval_from.high_output, cval_to.high_output, total_steps, current_step); gimp_set_data(PLUG_IN_NAME, &cval, sizeof(cval)); } else status = GIMP_PDB_CALLING_ERROR; } else status = GIMP_PDB_CALLING_ERROR; values[0].data.d_status = status; return; } /* get image and drawable */ l_image_id = param[1].data.d_int32; l_drawable_id = param[2].data.d_drawable; if(status == GIMP_PDB_SUCCESS) { /* how are we running today? */ switch (run_mode) { case GIMP_RUN_INTERACTIVE: /* Initial values */ l_cuvals.channel = 0; l_cuvals.low_input = 0; l_cuvals.high_input = 255; l_cuvals.gamma = 1.0; l_cuvals.low_output = 0; l_cuvals.high_output = 255; /* Get information from the dialog */ wcd = do_dialog(&l_cuvals); wcd->show_progress = TRUE; break; case GIMP_RUN_NONINTERACTIVE: /* check to see if invoked with the correct number of parameters */ if (nparams >= 9) { wcd = g_malloc (sizeof (WrDialog)); wcd->run = TRUE; wcd->show_progress = FALSE; l_cuvals.channel = param[3].data.d_int32; l_cuvals.low_input = param[4].data.d_int32; l_cuvals.high_input = param[5].data.d_int32; l_cuvals.gamma = param[6].data.d_float; l_cuvals.low_output = param[7].data.d_int32; l_cuvals.high_output = param[8].data.d_int32; } else { status = GIMP_PDB_CALLING_ERROR; } break; case GIMP_RUN_WITH_LAST_VALS: wcd = g_malloc (sizeof (WrDialog)); wcd->run = TRUE; wcd->show_progress = TRUE; /* Possibly retrieve data from a previous run */ gimp_get_data (PLUG_IN_NAME, &l_cuvals); break; default: break; } } if (wcd == NULL) { status = GIMP_PDB_EXECUTION_ERROR; } if (status == GIMP_PDB_SUCCESS) { /* Run the main function */ if(wcd->run) { gimp_image_undo_group_start (l_image_id); p_run_levels_tool(l_drawable_id, &l_cuvals); l_handled_drawable_id = l_drawable_id; gimp_image_undo_group_end (l_image_id); /* Store variable states for next run */ if (run_mode == GIMP_RUN_INTERACTIVE) { gimp_set_data(PLUG_IN_NAME, &l_cuvals, sizeof(l_cuvals)); } } else { status = GIMP_PDB_EXECUTION_ERROR; /* dialog ended with cancel button */ } /* If run mode is interactive, flush displays, else (script) don't do it, as the screen updates would make the scripts slow */ if (run_mode != GIMP_RUN_NONINTERACTIVE) { gimp_displays_flush (); } } values[0].data.d_status = status; values[1].data.d_int32 = l_handled_drawable_id; /* return the id of handled layer */ } /* end run */ /* * DIALOG and callback stuff */ static void radio_callback(GtkWidget *wgt, gpointer user_data) { WrDialog *wcd; if(gap_debug) printf("radio_callback: START\n"); wcd = (WrDialog*)user_data; if(wcd != NULL) { if(wcd->vals != NULL) { if(wgt == wcd->radio_alpha) { wcd->vals->channel = 4; } if(wgt == wcd->radio_blue) { wcd->vals->channel = 3; } if(wgt == wcd->radio_green) { wcd->vals->channel = 2; } if(wgt == wcd->radio_red) { wcd->vals->channel = 1; } if(wgt == wcd->radio_master) { wcd->vals->channel = 0; } if(gap_debug) printf("radio_callback: value: %d\n", (int)wcd->vals->channel); } } } /* --------------------------------- * wr_levels_response * --------------------------------- */ static void wr_levels_response (GtkWidget *widget, gint response_id, WrDialog *wcd) { GtkWidget *dialog; switch (response_id) { case GTK_RESPONSE_OK: if(wcd) { if (GTK_WIDGET_VISIBLE (wcd->shell)) gtk_widget_hide (wcd->shell); wcd->run = TRUE; } default: dialog = NULL; if(wcd) { dialog = wcd->shell; if(dialog) { wcd->shell = NULL; gtk_widget_destroy (dialog); } } gtk_main_quit (); break; } } /* end wr_levels_response */ WrDialog * do_dialog (wr_levels_val_t *cuvals) { WrDialog *wcd; GtkWidget *vbox; GtkWidget *dialog1; GtkWidget *dialog_vbox1; GtkWidget *frame1; GtkWidget *hbox1; GtkWidget *vbox1; GtkWidget *label1; GSList *vbox1_group = NULL; GtkWidget *radiobutton1; GtkWidget *radiobutton2; GtkWidget *radiobutton3; GtkWidget *radiobutton4; GtkWidget *radiobutton5; GtkWidget *table1; GtkWidget *label2; GtkWidget *label3; GtkWidget *label4; GtkWidget *label5; GtkWidget *label6; GtkObject *spinbutton_low_input_adj; GtkWidget *spinbutton_low_input; GtkObject *spinbutton_high_input_adj; GtkWidget *spinbutton_high_input; GtkObject *spinbutton_gamma_adj; GtkWidget *spinbutton_gamma; GtkObject *spinbutton_low_output_adj; GtkWidget *spinbutton_low_output; GtkObject *spinbutton_high_output_adj; GtkWidget *spinbutton_high_output; GtkWidget *dialog_action_area1; /* Init UI */ gimp_ui_init ("wr_curves", FALSE); /* The dialog1 */ wcd = g_malloc (sizeof (WrDialog)); wcd->run = FALSE; wcd->vals = cuvals; /* The dialog1 and main vbox */ dialog1 = gimp_dialog_new (_("Color Levels"), "levels_wrapper", NULL, 0, gimp_standard_help_func, PLUG_IN_HELP_ID, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); wcd->shell = dialog1; g_signal_connect (G_OBJECT (dialog1), "response", G_CALLBACK (wr_levels_response), wcd); /* the vbox */ vbox = gtk_vbox_new (FALSE, 2); gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog1)->vbox), vbox, TRUE, TRUE, 0); gtk_widget_show (vbox); dialog_vbox1 = GTK_DIALOG (dialog1)->vbox; gtk_widget_show (dialog_vbox1); /* the frame */ frame1 = gimp_frame_new (_("Color Levels Adjustments ")); gtk_widget_show (frame1); gtk_box_pack_start (GTK_BOX (dialog_vbox1), frame1, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (frame1), 2); hbox1 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox1); gtk_container_add (GTK_CONTAINER (frame1), hbox1); gtk_container_set_border_width (GTK_CONTAINER (hbox1), 4); vbox1 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox1); gtk_box_pack_start (GTK_BOX (hbox1), vbox1, TRUE, TRUE, 0); /* Channel the label */ label1 = gtk_label_new (_("Channel:")); gtk_widget_show (label1); gtk_box_pack_start (GTK_BOX (vbox1), label1, FALSE, FALSE, 0); gtk_misc_set_alignment (GTK_MISC (label1), 0, 0.5); /* Channel the radio buttons */ radiobutton1 = gtk_radio_button_new_with_label (vbox1_group, _("Master")); vbox1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton1)); gtk_widget_show (radiobutton1); gtk_box_pack_start (GTK_BOX (vbox1), radiobutton1, FALSE, FALSE, 0); radiobutton2 = gtk_radio_button_new_with_label (vbox1_group, _("Red")); vbox1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton2)); gtk_widget_show (radiobutton2); gtk_box_pack_start (GTK_BOX (vbox1), radiobutton2, FALSE, FALSE, 0); radiobutton3 = gtk_radio_button_new_with_label (vbox1_group, _("Green")); vbox1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton3)); gtk_widget_show (radiobutton3); gtk_box_pack_start (GTK_BOX (vbox1), radiobutton3, FALSE, FALSE, 0); radiobutton4 = gtk_radio_button_new_with_label (vbox1_group, _("Blue")); vbox1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton4)); gtk_widget_show (radiobutton4); gtk_box_pack_start (GTK_BOX (vbox1), radiobutton4, FALSE, FALSE, 0); radiobutton5 = gtk_radio_button_new_with_label (vbox1_group, _("Alpha")); vbox1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton5)); gtk_widget_show (radiobutton5); gtk_box_pack_start (GTK_BOX (vbox1), radiobutton5, FALSE, FALSE, 0); /* table1 for spinbuttons */ table1 = gtk_table_new (6, 2, FALSE); gtk_widget_show (table1); gtk_box_pack_start (GTK_BOX (hbox1), table1, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (table1), 4); label2 = gtk_label_new (_("Low Input:")); gtk_widget_show (label2); gtk_table_attach (GTK_TABLE (table1), label2, 0, 1, 1, 2, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment (GTK_MISC (label2), 0, 0.5); label3 = gtk_label_new (_("High Input:")); gtk_widget_show (label3); gtk_table_attach (GTK_TABLE (table1), label3, 0, 1, 2, 3, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment (GTK_MISC (label3), 0, 0.5); label4 = gtk_label_new (_("Gamma:")); gtk_widget_show (label4); gtk_table_attach (GTK_TABLE (table1), label4, 0, 1, 3, 4, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment (GTK_MISC (label4), 0, 0.5); label5 = gtk_label_new (_("Low Output:")); gtk_widget_show (label5); gtk_table_attach (GTK_TABLE (table1), label5, 0, 1, 4, 5, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment (GTK_MISC (label5), 0, 0.5); label6 = gtk_label_new (_("High Output:")); gtk_widget_show (label6); gtk_table_attach (GTK_TABLE (table1), label6, 0, 1, 5, 6, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment (GTK_MISC (label6), 0, 0.5); /* SPINBUTTONS */ spinbutton_low_input_adj = gtk_adjustment_new (0, 0, 255, 1, 10, 0); spinbutton_low_input = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_low_input_adj), 1, 0); gtk_widget_show (spinbutton_low_input); gtk_table_attach (GTK_TABLE (table1), spinbutton_low_input, 1, 2, 1, 2, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); spinbutton_high_input_adj = gtk_adjustment_new (255, 0, 255, 1, 10, 0); spinbutton_high_input = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_high_input_adj), 1, 0); gtk_widget_show (spinbutton_high_input); gtk_table_attach (GTK_TABLE (table1), spinbutton_high_input, 1, 2, 2, 3, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); spinbutton_gamma_adj = gtk_adjustment_new (1, 0.1, 10, 0.1, 1, 0); spinbutton_gamma = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_gamma_adj), 0.1, 2); gtk_widget_show (spinbutton_gamma); gtk_table_attach (GTK_TABLE (table1), spinbutton_gamma, 1, 2, 3, 4, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); spinbutton_low_output_adj = gtk_adjustment_new (0, 0, 255, 1, 10, 0); spinbutton_low_output = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_low_output_adj), 1, 0); gtk_widget_show (spinbutton_low_output); gtk_table_attach (GTK_TABLE (table1), spinbutton_low_output, 1, 2, 4, 5, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); spinbutton_high_output_adj = gtk_adjustment_new (255, 0, 255, 1, 10, 0); spinbutton_high_output = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_high_output_adj), 1, 0); gtk_widget_show (spinbutton_high_output); gtk_table_attach (GTK_TABLE (table1), spinbutton_high_output, 1, 2, 5, 6, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); dialog_action_area1 = GTK_DIALOG (dialog1)->action_area; gtk_widget_show (dialog_action_area1); gtk_container_set_border_width (GTK_CONTAINER (dialog_action_area1), 10); wcd->radio_master = radiobutton1; wcd->radio_red = radiobutton2; wcd->radio_green = radiobutton3; wcd->radio_blue = radiobutton4; wcd->radio_alpha = radiobutton5; /* signals */ g_signal_connect (G_OBJECT (wcd->radio_master), "clicked", G_CALLBACK (radio_callback), wcd); g_signal_connect (G_OBJECT (wcd->radio_red), "clicked", G_CALLBACK (radio_callback), wcd); g_signal_connect (G_OBJECT (wcd->radio_green), "clicked", G_CALLBACK (radio_callback), wcd); g_signal_connect (G_OBJECT (wcd->radio_blue), "clicked", G_CALLBACK (radio_callback), wcd); g_signal_connect (G_OBJECT (wcd->radio_alpha), "clicked", G_CALLBACK (radio_callback), wcd); g_signal_connect (G_OBJECT (spinbutton_gamma_adj), "value_changed", G_CALLBACK (gimp_double_adjustment_update), &cuvals->gamma); g_signal_connect (G_OBJECT (spinbutton_high_input_adj), "value_changed", G_CALLBACK (gimp_int_adjustment_update), &cuvals->high_input); g_signal_connect (G_OBJECT (spinbutton_low_input_adj), "value_changed", G_CALLBACK (gimp_int_adjustment_update), &cuvals->low_input); g_signal_connect (G_OBJECT (spinbutton_high_output_adj), "value_changed", G_CALLBACK (gimp_int_adjustment_update), &cuvals->high_output); g_signal_connect (G_OBJECT (spinbutton_low_output_adj), "value_changed", G_CALLBACK (gimp_int_adjustment_update), &cuvals->low_output); gtk_widget_show (dialog1); gtk_main (); gdk_flush (); return wcd; } gimp-gap-2.6.0+dfsg.orig/gap/gap_vex_exec.c0000644000175000017500000004630111212030253020321 0ustar thibautthibaut/* * gap_vex_exec.c * Video Extract GUI and worker procedures * based on gap_vid_api (GVA) */ /* * Changelog: * 2003/04/19 v1.2.1a: created */ /* * Copyright * * 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 #include "gap_vex_exec.h" #include "gap_vex_dialog.h" #include "gap_audio_wav.h" #include "gap_audio_extract.h" #include "gap_bluebox.h" /* ------------------- * p_gap_set_framerate * ------------------- */ static void p_gap_set_framerate(gint32 image_id, gdouble framerate) { GimpParam *l_params; gint l_retvals; if (gap_debug) printf("DEBUG: before p_gap_set_framerate %f\n", (float)framerate); l_params = gimp_run_procedure ("plug_in_gap_set_framerate", &l_retvals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, image_id, GIMP_PDB_DRAWABLE, 0, GIMP_PDB_FLOAT, framerate, GIMP_PDB_END); g_free(l_params); } /* end p_gap_set_framerate */ /* -------------------- * p_vex_apply_bluebox * -------------------- * apply bluebox settings on the specified layer */ static void p_vex_apply_bluebox(gint32 layer_id ) { GapBlueboxGlobalParams *bbp; /* blubox parameters are not provided by the caller. * in this case we init with default values and try to fetch * values from previous bluebox filter runs */ bbp = gap_bluebox_bbp_new(layer_id);; if(bbp) { bbp->image_id = gimp_drawable_get_image(layer_id); bbp->drawable_id = layer_id; bbp->layer_id = layer_id; bbp->run_mode = GIMP_RUN_NONINTERACTIVE; bbp->run_flag = TRUE; gap_bluebox_apply(bbp); } } /* end p_vex_apply_bluebox */ /* ---------------------- * p_frame_postprocessing * ---------------------- * generate transpareny as alpha channel or layermask * via bluebox effect (if requested) */ static void p_frame_postprocessing(t_GVA_Handle *gvahand ,GapVexMainGlobalParams *gpp) { gint32 l_bbox_layer_id; gint32 l_layermask_id; l_bbox_layer_id = gvahand->layer_id; if (gpp->val.generate_alpha_via_bluebox == TRUE) { if ((gpp->val.extract_with_layermask == TRUE) || (gpp->val.extract_with_layermask == TRUE)) { l_bbox_layer_id = gimp_layer_copy(gvahand->layer_id); gimp_image_add_layer(gvahand->image_id, l_bbox_layer_id, -1); if(gap_debug) { printf("created bb_layer_id:%d\n", l_bbox_layer_id); } } if (!gimp_drawable_has_alpha(l_bbox_layer_id)) { gimp_layer_add_alpha(l_bbox_layer_id); } p_vex_apply_bluebox(l_bbox_layer_id); } if (gimp_drawable_has_alpha(l_bbox_layer_id)) { if (gpp->val.extract_alpha_as_gray_frames == TRUE) { l_layermask_id = gimp_layer_create_mask(l_bbox_layer_id, GIMP_ADD_ALPHA_MASK); if(gap_debug) { printf("GRAY created layermask_id:%d\n", l_layermask_id); } gap_layer_copy_paste_drawable(gvahand->image_id, gvahand->layer_id, l_layermask_id); } else if (gpp->val.extract_with_layermask == TRUE) { l_layermask_id = gimp_layer_create_mask(l_bbox_layer_id, GIMP_ADD_ALPHA_MASK); if(gap_debug) { printf("LAYERMASK created layermask_id:%d\n", l_layermask_id); } gimp_layer_add_mask(gvahand->layer_id, l_layermask_id); } if (l_bbox_layer_id != gvahand->layer_id) { if(gap_debug) { printf("remove bb_layer_id:%d\n", l_bbox_layer_id); } /* remove the temporyry bluebox layer */ gimp_image_remove_layer(gvahand->image_id, l_bbox_layer_id); //gimp_drawable_delete(l_bbox_layer_id); } } } /* end p_frame_postprocessing */ /* ------------------------------ * gap_vex_exe_extract_videorange * ------------------------------ * - the productive procedure for extracting frames and/or audio * from a videofile. */ void gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp) { #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT t_GVA_Handle *gvahand; t_GVA_PosUnit l_pos_unit; t_GVA_RetCode l_rc; GimpRunMode l_save_run_mode; gchar *framename; gint32 framenumber; gint32 framenumber1; gint32 framenumber1_delta; gdouble l_pos; gdouble l_pos_end; gdouble l_progress; gdouble l_expected_frames; gint l_overwrite_mode; gint l_overwrite_mode_audio; l_overwrite_mode_audio = 0; if(gap_debug) { printf("RUN gap_vex_exe_extract_videorange with parameters:\n"); printf("videoname : %s\n", gpp->val.videoname); printf("begin_percent: %f\n", (float)gpp->val.begin_percent); printf("end_percent : %f\n", (float)gpp->val.end_percent); printf("begin_frame : %d\n", (int)gpp->val.begin_frame); printf("end_frame : %d\n", (int)gpp->val.end_frame); printf("pos_unit : %d\n", (int)gpp->val.pos_unit); printf("audiofile : %s\n", gpp->val.audiofile); printf("basename : %s\n", gpp->val.basename); printf("extension : %s\n", gpp->val.extension); printf("basenum : %d\n", (int)gpp->val.basenum); printf("fn_digits : %d\n", (int)gpp->val.fn_digits); printf("multilayer : %d\n", (int)gpp->val.multilayer); printf("disable_mmx : %d\n", (int)gpp->val.disable_mmx); printf("videotrack : %d\n", (int)gpp->val.videotrack); printf("audiotrack : %d\n", (int)gpp->val.audiotrack); printf("ow_mode : %d\n", (int)gpp->val.ow_mode); printf("preferred_decoder : %s\n", gpp->val.preferred_decoder); printf("exact_seek : %d\n", (int)gpp->val.exact_seek); printf("deinterlace : %d\n", (int)gpp->val.deinterlace); printf("delace_threshold: %f\n", (float)gpp->val.delace_threshold); printf("generate_alpha_via_bluebox: %d\n", (int)gpp->val.generate_alpha_via_bluebox); printf("extract_alpha_as_gray_frames: %d\n", (int)gpp->val.extract_alpha_as_gray_frames); printf("extract_with_layermask: %d\n", (int)gpp->val.extract_with_layermask); } l_save_run_mode = GIMP_RUN_INTERACTIVE; /* for the 1.st call of saving a non xcf frame */ l_overwrite_mode = 0; gpp->val.image_ID = -1; /* --------- OPEN the videofile --------------- */ gvahand = GVA_open_read_pref(gpp->val.videoname ,gpp->val.videotrack ,gpp->val.audiotrack ,gpp->val.preferred_decoder , FALSE /* use MMX if available (disable_mmx == FALSE) */ ); if(gvahand == NULL) { return; } /* ------ check if we have to extract audio (ask for audio overwrite) ---------- */ if((gvahand->atracks > 0) && (gpp->val.audiotrack > 0)) { l_overwrite_mode_audio = 0; l_overwrite_mode_audio = gap_vex_dlg_overwrite_dialog(gpp , gpp->val.audiofile , l_overwrite_mode_audio ); } framenumber = gpp->val.basenum; if(gpp->val.pos_unit == 0) { l_pos_unit = GVA_UPOS_FRAMES; l_pos_end = gpp->val.end_frame; l_pos = gpp->val.begin_frame; l_expected_frames = 1 + (l_pos_end - l_pos); framenumber1_delta = framenumber - l_pos; if(gpp->val.basenum <= 0) { framenumber = l_pos; framenumber1_delta = 0; } } else { l_pos_unit = GVA_UPOS_PRECENTAGE; l_pos_end = (gpp->val.end_percent / 100.0); l_pos = (gpp->val.begin_percent / 100.0); l_expected_frames = gvahand->total_frames * (l_pos_end - l_pos); framenumber1_delta = framenumber - (gvahand->total_frames * l_pos); if(gpp->val.basenum <= 0) { framenumber = gvahand->total_frames * l_pos; framenumber1_delta = 0; } } framenumber1 = framenumber; /* ------ extract Video ---------- */ if((gvahand->vtracks > 0) && (gpp->val.videotrack > 0)) { gint32 delace[2]; gint32 framenumber_fil; gint iid; gint iid_max; iid_max = 1; delace[0] = gpp->val.deinterlace; if((gpp->val.deinterlace == GAP_VEX_DELACE_ODD_X2) || (gpp->val.deinterlace == GAP_VEX_DELACE_EVEN_X2)) { iid_max = 2; framenumber_fil = (framenumber * 2) -1; if(gpp->val.deinterlace == GAP_VEX_DELACE_ODD_X2) { delace[0] = GAP_VEX_DELACE_ODD; delace[1] = GAP_VEX_DELACE_EVEN; } else { delace[0] = GAP_VEX_DELACE_EVEN; delace[1] = GAP_VEX_DELACE_ODD; } } /* check if we need an INTERACTIVE Dummy save to set default parameters * for further frame save operation. * The dummy save is done at begin of processing * because the handling of the 1st frame may * occure after a significant delay, caused by seeking in large videofiles. */ if((strcmp(gpp->val.extension, ".xcf") == 0) || (strcmp(gpp->val.extension, ".XCF") == 0)) { /* Native GIMP format needs no save params * and can be called NON_INTERACTIVE for all frames */ l_save_run_mode = GIMP_RUN_NONINTERACTIVE; } else { gchar *l_dummyname; gint32 l_dummy_image_id; gint32 l_empty_layer_id; l_dummy_image_id = gimp_image_new(32, 32, GIMP_RGB); l_empty_layer_id = gimp_layer_new(l_dummy_image_id, "background", 32, 32, GIMP_RGB_IMAGE, 100.0, /* Opacity full opaque */ GIMP_NORMAL_MODE); gimp_image_add_layer(l_dummy_image_id, l_empty_layer_id, 0); gap_layer_clear_to_color(l_empty_layer_id, 0.0, 0.0, 0.0, 1.0); l_save_run_mode = GIMP_RUN_INTERACTIVE; /* for the 1.st call of saving a non xcf frame */ /* must use same basename and extension for the dummyname * because setup of jpeg save params for further non interactive save operation * depend on a key that includes the same basename and extension. */ l_dummyname = gap_lib_alloc_fname6(&gpp->val.basename[0] ,99999999 ,&gpp->val.extension[0] ,8 /* use full 8 digits for the numberpart */ ); gimp_image_set_filename(l_dummy_image_id, l_dummyname); gap_lib_save_named_image(l_dummy_image_id , l_dummyname , l_save_run_mode ); gap_image_delete_immediate(l_dummy_image_id); g_remove(l_dummyname); g_free(l_dummyname); l_save_run_mode = GIMP_RUN_WITH_LAST_VALS; /* for all further calls */ } if (gpp->val.run_mode != GIMP_RUN_NONINTERACTIVE) { if(gpp->val.videotrack > 0) { gimp_progress_init (_("Seek Frame Position...")); gvahand->do_gimp_progress = TRUE; } } if(gpp->val.exact_seek != 0) /* exact frame_seek */ { gint32 l_seekstep; gint32 l_seek_framenumber; if(1==1) { gvahand->emulate_seek = TRUE; /* force seq. reads even if we have a video index */ l_rc = GVA_seek_frame(gvahand, l_pos, l_pos_unit); } else { /* dead code (older and slower seek emulation * implementation outside the API) */ l_seek_framenumber = l_pos; if(l_pos_unit == GVA_UPOS_PRECENTAGE) { l_seek_framenumber = gvahand->total_frames * l_pos; } for(l_seekstep = 1; l_seekstep < l_seek_framenumber; l_seekstep++) { /* fetch one frame to buffer gvahand->frame_data * (and proceed position to next frame) */ l_rc = GVA_get_next_frame(gvahand); if(l_rc != GVA_RET_OK) { break; } l_progress = (gdouble)l_seekstep / l_seek_framenumber; if (gpp->val.run_mode != GIMP_RUN_NONINTERACTIVE) { gimp_progress_update (l_progress); } } } } else { l_rc = GVA_seek_frame(gvahand, l_pos, l_pos_unit); } if (gpp->val.run_mode != GIMP_RUN_NONINTERACTIVE) { gimp_progress_init (_("Extracting Frames...")); } while(1) { /* fetch one frame to buffer gvahand->frame_data * (and proceed position to next frame) */ l_rc = GVA_get_next_frame(gvahand); if(l_rc != GVA_RET_OK) { break; } if(gpp->val.multilayer == 0) { if((gpp->val.deinterlace == GAP_VEX_DELACE_ODD_X2) || (gpp->val.deinterlace == GAP_VEX_DELACE_EVEN_X2)) { framenumber_fil = (framenumber * 2) -1; } else { framenumber_fil = framenumber; } /* loop once (or twice for splitting deinterlace modes) */ for(iid=0; iid < iid_max; iid++) { /* convert fetched frame from buffer to gimp image gvahand->image_id */ l_rc = GVA_frame_to_gimp_layer(gvahand ,TRUE /* delete_mode */ ,framenumber - framenumber1_delta ,delace[iid] ,gpp->val.delace_threshold ); if(l_rc != GVA_RET_OK) { break; } framename = gap_lib_alloc_fname6(&gpp->val.basename[0] ,(long)(framenumber_fil + iid) ,&gpp->val.extension[0] ,gpp->val.fn_digits ); gimp_image_set_filename(gvahand->image_id, framename); gpp->val.image_ID = gvahand->image_id; l_overwrite_mode = gap_vex_dlg_overwrite_dialog(gpp , framename , l_overwrite_mode ); if (l_overwrite_mode < 0) { g_free(framename); break; } else { gint32 l_sav_rc; gint32 l_sav_image_id; l_sav_image_id = gvahand->image_id; p_frame_postprocessing(gvahand, gpp); if (gpp->val.extract_alpha_as_gray_frames == TRUE) { l_sav_image_id = gimp_image_duplicate(gvahand->image_id); gimp_image_convert_grayscale(l_sav_image_id); } l_sav_rc = gap_lib_save_named_image(l_sav_image_id , framename , l_save_run_mode ); if (l_sav_image_id != gvahand->image_id) { /* delete temporary grayscale image */ gap_image_delete_immediate(l_sav_image_id); } if (l_sav_rc < 0) { g_message(_("failed to save file:\n'%s'"), framename); break; } } g_free(framename); } } else { /* creeate one multilayer image */ l_rc = GVA_frame_to_gimp_layer(gvahand ,FALSE /* delete_mode FALSE: keep layers */ ,framenumber - framenumber1_delta ,delace[0] ,gpp->val.delace_threshold ); p_frame_postprocessing(gvahand, gpp); if(l_rc != GVA_RET_OK) { break; } gpp->val.image_ID = gvahand->image_id; if((gpp->val.deinterlace == GAP_VEX_DELACE_ODD_X2) || (gpp->val.deinterlace == GAP_VEX_DELACE_EVEN_X2)) { /* deinterlace the other set of rows as extra layer (even/odd) */ l_rc = GVA_frame_to_gimp_layer(gvahand ,FALSE /* delete_mode FALSE: keep layers */ ,framenumber - framenumber1_delta ,delace[1] ,gpp->val.delace_threshold ); if(l_rc != GVA_RET_OK) { break; } } } framenumber++; l_progress = 0.95 * ((gdouble)(framenumber - framenumber1) / l_expected_frames); if(gap_debug) printf("\nPROGRESS expected N[%d] frames:%f PROGRESS: %f\n\n" , (int)(framenumber - framenumber1) , (float)l_expected_frames , (float)l_progress); if (gpp->val.run_mode != GIMP_RUN_NONINTERACTIVE) { gimp_progress_update (l_progress); } if((framenumber - framenumber1) >= l_expected_frames) { break; } } } /* ------ extract Audio ---------- */ if((gvahand->atracks > 0) && (gpp->val.audiotrack > 0)) { if (l_overwrite_mode_audio >= 0) { gdouble l_extracted_frames; gboolean do_progress; l_extracted_frames = framenumber - framenumber1; do_progress = TRUE; if(gpp->val.run_mode != GIMP_RUN_NONINTERACTIVE) { do_progress = FALSE; } gap_audio_extract_from_videofile(gpp->val.videoname , gpp->val.audiofile , gpp->val.audiotrack , gpp->val.preferred_decoder , gpp->val.exact_seek , l_pos_unit , l_pos , l_extracted_frames , l_expected_frames , do_progress , NULL /* GtkWidget *progressBar using NULL for gimp_progress */ , NULL /* fptr_progress_callback */ , NULL /* user_data */ ); } } if((gpp->val.image_ID >= 0) && (gpp->val.multilayer == 0) && (gpp->val.videotrack > 0)) { p_gap_set_framerate(gpp->val.image_ID, gvahand->framerate); } l_progress = 1.0; if (gpp->val.run_mode != GIMP_RUN_NONINTERACTIVE) { gimp_progress_update (l_progress); } if(gpp->val.image_ID >= 0) { gimp_image_undo_enable(gpp->val.image_ID); gimp_display_new(gpp->val.image_ID); gimp_displays_flush(); gvahand->image_id = -1; /* prenvent API from deleting that image at close */ } GVA_close(gvahand); /* endif GAP_ENABLE_VIDEOAPI_SUPPORT */ #endif return; } /* end gap_vex_exe_extract_videorange */ gimp-gap-2.6.0+dfsg.orig/gap/gap_onion_worker.c0000644000175000017500000003345111212030253021230 0ustar thibautthibaut/* gap_onion_worker.c procedures * 2003.05.22 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains GAP Onionskin Worker Procedures */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.16c; 2003.07.09 hof: splitted off gap_onion_base.c (for automatic apply) * version 1.3.16b; 2003.07.06 hof: bugfixes, added parameter asc_opacity * version 1.3.14a; 2003.05.24 hof: integration into gimp-gap-1.3.14 * version 1.2.2a; 2001.11.24 hof: created */ #include #include extern int gap_debug; /* ============================================================================ * p_find_frame_in_img_cache * return delete image (with workaround to ensure that most of the * return -1 if nothing was found. * ============================================================================ */ gint32 p_find_frame_in_img_cache(void *gpp_void , gint32 framenr, gint32 *image_id, gint32 *layer_id) { GapOnionMainGlobalParams *gpp; gint32 l_idx; *image_id = -1; *layer_id = -1; gpp = (GapOnionMainGlobalParams *)gpp_void; for(l_idx = 0; l_idx < MIN(gpp->cache.count, GAP_ONION_CACHE_SIZE); l_idx++) { if(framenr == gpp->cache.framenr[l_idx]) { *image_id = gpp->cache.image_id[l_idx]; *layer_id = gpp->cache.layer_id[l_idx]; return (l_idx); } } return (-1); } /* end p_find_frame_in_img_cache */ /* ============================================================================ * p_add_img_to_cache * add image_id and layer_id to the image cache. * the image cache is a list of temporary images (without display) * and contains frames that were processed in the previous steps * of the onionskin layer processing. * - a layer_id of -1 is used, if the image was loaded, but not * merged. * - If the framenr is already in the cache * ?? * - If the cache is full, the oldest image_id is deleted * and removed from the cache * - Do not add the current image to the cache !! * ============================================================================ */ void p_add_img_to_cache (void *gpp_void, gint32 framenr, gint32 image_id, gint32 layer_id) { GapOnionMainGlobalParams *gpp; gint32 l_idx; gpp = (GapOnionMainGlobalParams *)gpp_void; if(gap_debug) { printf("p_add_img_to_cache: cache.count: %d)\n", (int)gpp->cache.count); printf("PARAMS framenr: %d image_id: %d layer_id: %d\n" , (int)framenr , (int)image_id , (int)layer_id ); } for(l_idx = 0; l_idx < MIN(gpp->cache.count, GAP_ONION_CACHE_SIZE); l_idx++) { if(framenr == gpp->cache.framenr[l_idx]) { /* an image with this framenr is already in the cache */ if(gap_debug) printf("p_add_img_to_cache: framenr already in cache at index: %d)\n", (int)l_idx); if( gpp->cache.layer_id[l_idx] >= 0) { /* the cached image has aready merged layers */ return; } if(layer_id >= 0) { /* update the chache with the id of the merged layer */ gpp->cache.image_id[l_idx] = image_id; gpp->cache.layer_id[l_idx] = layer_id; } return; } } if(l_idx < GAP_ONION_CACHE_SIZE) { gpp->cache.count++; } else { if(gap_debug) { printf("p_add_img_to_cache: FULL CACHE delete oldest entry\n"); } /* cache is full, so delete 1.st (oldest) entry */ gap_image_delete_immediate(gpp->cache.image_id[0]); /* shift all entries down one index step */ for(l_idx = 0; l_idx < GAP_ONION_CACHE_SIZE -1; l_idx++) { gpp->cache.framenr[l_idx] = gpp->cache.framenr[l_idx +1]; gpp->cache.image_id[l_idx] = gpp->cache.image_id[l_idx +1]; gpp->cache.layer_id[l_idx] = gpp->cache.layer_id[l_idx +1]; } /* l_idx = GAP_ONION_CACHE_SIZE -1; */ } if(gap_debug) { printf("p_add_img_to_cache: new entry ADDED at IMAGECACHE index: %d\n", (int)l_idx); } gpp->cache.framenr[l_idx] = framenr; gpp->cache.image_id[l_idx] = image_id; gpp->cache.layer_id[l_idx] = layer_id; } /* end p_add_img_to_cache */ /* ============================================================================ * p_delete_img_cache * delete all images in the cache, and set the cache empty. * ============================================================================ */ static void p_delete_img_cache (GapOnionMainGlobalParams *gpp) { gint32 l_idx; if(gap_debug) printf("gap_image_delete_immediate: cache.count: %d)\n", (int)gpp->cache.count); for(l_idx = 0; l_idx < MIN(gpp->cache.count, GAP_ONION_CACHE_SIZE); l_idx++) { gap_image_delete_immediate(gpp->cache.image_id[l_idx]); } gpp->cache.count = 0; } /* end p_delete_img_cache */ /* ============================================================================ * gap_onion_worker_plug_in_gap_get_animinfo * get informations about the animation * ============================================================================ */ void gap_onion_worker_plug_in_gap_get_animinfo(gint32 image_ID, GapOnionMainAinfo *ainfo) { static char *l_called_proc = "plug_in_gap_get_animinfo"; GimpParam *return_vals; int nreturn_vals; gint32 dummy_layer_id; dummy_layer_id = gap_image_get_any_layer(image_ID); return_vals = gimp_run_procedure (l_called_proc, &nreturn_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, image_ID, GIMP_PDB_DRAWABLE, dummy_layer_id, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { ainfo->first_frame_nr = return_vals[1].data.d_int32; ainfo->last_frame_nr = return_vals[2].data.d_int32; ainfo->curr_frame_nr = return_vals[3].data.d_int32; ainfo->frame_cnt = return_vals[4].data.d_int32; g_snprintf(ainfo->basename, sizeof(ainfo->basename), "%s", return_vals[5].data.d_string); g_snprintf(ainfo->extension, sizeof(ainfo->extension), "%s", return_vals[6].data.d_string); ainfo->framerate = return_vals[7].data.d_float; } else { printf("Error: PDB call of %s failed, image_ID: %d\n", l_called_proc, (int)image_ID); } gimp_destroy_params(return_vals, nreturn_vals); } /* end gap_onion_worker_plug_in_gap_get_animinfo */ /* wrappers for gap_onoin_base procedures */ gint gap_onion_worker_set_data_onion_cfg(GapOnionMainGlobalParams *gpp, char *key) { if(gap_debug) printf("gap_onion_worker_set_data_onion_cfg: START\n"); return (gap_vin_set_common_onion(&gpp->vin, &gpp->ainfo.basename[0])); } gint gap_onion_worker_get_data_onion_cfg(GapOnionMainGlobalParams *gpp) { GapVinVideoInfo *l_vin; if(gap_debug) printf("gap_onion_worker_get_data_onion_cfg: START\n"); /* try to read configuration params */ l_vin = gap_vin_get_all(&gpp->ainfo.basename[0]); if(l_vin) { memcpy(&gpp->vin, l_vin, sizeof(GapVinVideoInfo)); g_free(l_vin); return 0; } return -1; } gint gap_onion_worker_onion_visibility(GapOnionMainGlobalParams *gpp, gint visi_mode) { return (gap_onion_base_onionskin_visibility(gpp->image_ID, visi_mode)); } /* ============================================================================ * gap_onion_worker_onion_delete * remove onion layer(s) from the current image. * ============================================================================ */ gint gap_onion_worker_onion_delete(GapOnionMainGlobalParams *gpp) { if(gap_debug) { printf("gap_onion_worker_onion_delete: START\n"); printf(" image_ID: %d\n", (int)gpp->image_ID); } gap_onion_base_onionskin_delete(gpp->image_ID); if(gap_debug) printf("gap_onion_worker_onion_delete: END\n"); return 0; } /* end gap_onion_worker_onion_delete */ /* ============================================================================ * gap_onion_worker_onion_apply * create or replace onion layer(s) in the current image. * Onion layers do show one (or more) merged copies of previos (or next) * videoframe(s). * This procedure first removes onion layers (if there are any) * then reads the other videoframes, merges them (according to config params) * and imports the merged layer(s) as onion layer(s). * Onion Layers are marked by tattoo and parasite * use_chache TRUE: * check if desired frame is already in the image cache we can skip loading * if the cached image is already merged we can simply copy the layer. * Further we update the cache with merged layer. * use_cache is for processing multiple frames (speeds up remarkable) * use_cache FALSE: * always load frames and perform merge, * but we can steal layer from the tmp_image. * (faster than copy when processing a single frame only) * * * returns value >= 0 if all is ok * (or -1 on error) * ============================================================================ */ gint gap_onion_worker_onion_apply(GapOnionMainGlobalParams *gpp, gboolean use_cache) { gint l_rc; if(gap_debug) { printf("gap_onion_worker_onion_apply: START\n"); } l_rc = gap_onion_base_onionskin_apply(gpp , gpp->image_ID , &gpp->vin , gpp->ainfo.curr_frame_nr , gpp->ainfo.first_frame_nr , gpp->ainfo.last_frame_nr , &gpp->ainfo.basename[0] , &gpp->ainfo.extension[0] , p_add_img_to_cache , p_find_frame_in_img_cache , use_cache ); if(gap_debug) printf("gap_onion_worker_onion_apply: END\n\n"); return 0; } /* end gap_onion_worker_onion_apply */ /* ============================================================================ * gap_onion_worker_onion_range * Apply or delete onionskin layers in selected framerange * ============================================================================ */ gint gap_onion_worker_onion_range(GapOnionMainGlobalParams *gpp) { int l_rc; gint32 l_frame_nr; gint32 l_step, l_begin, l_end; gint32 l_current_image_id; gint32 l_curr_frame_nr; gdouble l_percentage, l_percentage_step; gchar *l_new_filename; l_percentage = 0.0; l_current_image_id = gpp->image_ID; if(gpp->vin.ref_delta < 0) { /* for references to previous frames we step up (from low to high frame numbers) */ l_begin = MIN(gpp->range_from, gpp->range_to); l_end = MAX(gpp->range_from, gpp->range_to); l_step = 1; l_percentage_step = 1.0 / ((1.0 + l_end) - l_begin); } else { /* for references to next frames we step down (from high to low frame numbers) */ l_begin = MAX(gpp->range_from, gpp->range_to); l_end = MIN(gpp->range_from, gpp->range_to); l_step = -1; l_percentage_step = 1.0 / ((1.0 + l_begin) - l_end); } if(gpp->run_mode == GIMP_RUN_INTERACTIVE) { if(gpp->run == GAP_ONION_RUN_APPLY) { gimp_progress_init( _("Creating onionskin layers...")); } else { gimp_progress_init( _("Removing onionskin layers...")); } } /* save current image */ l_new_filename = gimp_image_get_filename(l_current_image_id); l_rc = gap_lib_save_named_frame(gpp->image_ID, l_new_filename); if(l_rc < 0) return -1; l_curr_frame_nr = gpp->ainfo.curr_frame_nr; l_frame_nr = l_begin; while(1) { if(gap_debug) printf("gap_onion_worker_onion_range processing frame %d\n", (int)l_frame_nr); gpp->ainfo.curr_frame_nr = l_frame_nr; if(l_new_filename != NULL) { g_free(l_new_filename); l_new_filename = NULL; } if (l_curr_frame_nr == l_frame_nr) { l_new_filename = gimp_image_get_filename(l_current_image_id); gpp->image_ID = l_current_image_id; /* never add the current image to the cache * (to prevent it from merging !!) */ } else { /* build the frame name */ l_new_filename = gap_lib_alloc_fname(gpp->ainfo.basename, l_frame_nr, gpp->ainfo.extension); /* load frame */ gpp->image_ID = gap_lib_load_image(l_new_filename); if(gpp->image_ID < 0) return -1; /* add image to cache */ p_add_img_to_cache(gpp, l_frame_nr, gpp->image_ID, -1); } if(gpp->run == GAP_ONION_RUN_APPLY) { gap_onion_worker_onion_apply(gpp, TRUE /* use_cache */); } else if(gpp->run == GAP_ONION_RUN_DELETE) { gap_onion_worker_onion_delete(gpp); } else { printf("operation not implemented\n"); } l_rc = gap_lib_save_named_frame(gpp->image_ID, l_new_filename); if(l_rc < 0) return -1; if(gpp->run_mode == GIMP_RUN_INTERACTIVE) { l_percentage += l_percentage_step; gimp_progress_update (l_percentage); } if(l_frame_nr == l_end) { break; } l_frame_nr += l_step; } /* clean up the cache (delete all cached temp images) */ p_delete_img_cache(gpp); return 0; /* OK */ } /* end gap_onion_worker_onion_range */ gimp-gap-2.6.0+dfsg.orig/gap/gap_filter_pdb.h0000644000175000017500000000435011212030253020630 0ustar thibautthibaut/* gap_filter_pdb.h * * GAP ... Gimp Animation Plugins * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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_FILTER_PDB_H #define _GAP_FILTER_PDB_H #include "libgimp/gimp.h" typedef enum { GAP_PTYP_ANY = 0, GAP_PTYP_ITERATOR = 1, GAP_PTYP_CAN_OPERATE_ON_DRAWABLE = 2 } GapFiltPdbProcType; typedef enum { GAP_PAPP_CONSTANT = 0, GAP_PAPP_VARYING_LINEAR = 1 } GapFiltPdbApplyMode; /* ------------------------ * gap_filter_pdb.h * ------------------------ */ gint gap_filt_pdb_call_plugin(char *plugin_name, gint32 image_id, gint32 layer_id, GimpRunMode run_mode); int gap_filt_pdb_save_xcf(gint32 image_id, char *sav_name); 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(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); int gap_filt_pdb_constraint_proc(gchar *proc_name, gint32 image_id); gboolean gap_filter_iterator_call(const char *iteratorname , gint32 total_steps , gdouble current_step , const char *plugin_name , gint32 plugin_data_len ); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_fmac_context.h0000644000175000017500000000743411212030253021176 0ustar thibautthibaut/* 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 * * * 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 gimp-gap-2.6.0+dfsg.orig/gap/gap_filter_pdb.c0000644000175000017500000005747311212030253020641 0ustar thibautthibaut/* gap_filter_pdb.c * 1998.10.14 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * - GAP_filter pdb: functions for calling any Filter (==Plugin Proc) * that operates on a drawable * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 2.1.0a; 2004/11/16 hof: init string args with "\0" rather than NULL * when calling a PDB-Procedure * gimp 1.3.12a; 2003/05/02 hof: merge into CVS-gimp-gap project, re-added support of iter_ALT procedures * gimp 1.3.8a; 2002/09/21 hof: gap_lastvaldesc * gimp 1.3.4b; 2002/03/24 hof: gap_filt_pdb_get_iterator_proc supports COMMON_ITERATOR, removed support of iter_ALT procedures * gimp 1.1.28a; 2000/11/05 hof: check for GIMP_PDB_SUCCESS (not for FALSE) * version gimp 1.1.17b 2000.02.22 hof: - removed limit PLUGIN_DATA_SIZE * - removed support for old gimp 1.0.x PDB-interface. * version 0.97.00 hof: - created module (as extract gap_filter_foreach) */ #include "config.h" /* SYTEM (UNIX) includes */ #include #include #include #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" /* GAP includes */ #include "gap_lastvaldesc.h" #include "gap_arr_dialog.h" #include "gap_filter.h" #include "gap_filter_pdb.h" #include "gap_pdb_calls.h" #include "gap_dbbrowser_utils.h" #include "gap_lib.h" /* ------------------------ * global gap DEBUG switch * ------------------------ */ /* int gap_debug = 1; */ /* print debug infos */ /* int gap_debug = 0; */ /* 0: dont print debug infos */ extern int gap_debug; static char *global_plugin_data = NULL; static char * p_filt_pdb_get_alternative_iterator_proc(char *plugin_name, gint *count); static gint p_count_iterable_params(gchar *key_description, gint desc_size); /* ------------------------ * gap_filt_pdb_call_plugin * ------------------------ */ gint gap_filt_pdb_call_plugin(char *plugin_name, gint32 image_id, gint32 layer_id, GimpRunMode run_mode) { GimpParam *l_ret_params; GimpParam *l_argv; gint l_retvals; gint l_idx; gint l_nparams; gint l_nreturn_vals; GimpPDBProcType l_proc_type; gchar *l_proc_blurb; gchar *l_proc_help; gchar *l_proc_author; gchar *l_proc_copyright; gchar *l_proc_date; GimpParamDef *l_params; GimpParamDef *l_return_vals; gint l_rc; /* query for plugin_name to get its argument types */ if (!gimp_procedural_db_proc_info (plugin_name, &l_proc_blurb, &l_proc_help, &l_proc_author, &l_proc_copyright, &l_proc_date, &l_proc_type, &l_nparams, &l_nreturn_vals, &l_params, &l_return_vals)) { printf("ERROR: Plugin not available, Name was %s\n", plugin_name); return -1; } /* construct the procedures arguments */ l_argv = g_new (GimpParam, l_nparams); memset (l_argv, 0, (sizeof (GimpParam) * l_nparams)); /* initialize the argument types */ for (l_idx = 0; l_idx < l_nparams; l_idx++) { l_argv[l_idx].type = l_params[l_idx].type; switch(l_params[l_idx].type) { case GIMP_PDB_DISPLAY: l_argv[l_idx].data.d_display = -1; break; case GIMP_PDB_DRAWABLE: case GIMP_PDB_LAYER: case GIMP_PDB_CHANNEL: l_argv[l_idx].data.d_drawable = layer_id; break; case GIMP_PDB_IMAGE: l_argv[l_idx].data.d_image = image_id; break; case GIMP_PDB_INT32: case GIMP_PDB_INT16: case GIMP_PDB_INT8: l_argv[l_idx].data.d_int32 = 0; break; case GIMP_PDB_FLOAT: l_argv[l_idx].data.d_float = 0.0; break; case GIMP_PDB_STRING: l_argv[l_idx].data.d_string = g_strdup("\0"); break; default: l_argv[l_idx].data.d_int32 = 0; break; } } /* init the standard parameters, that should be common to all plugins */ l_argv[0].data.d_int32 = run_mode; l_argv[1].data.d_image = image_id; l_argv[2].data.d_drawable = layer_id; /* run the plug-in procedure */ l_ret_params = gimp_run_procedure2 (plugin_name, &l_retvals, l_nparams, l_argv); /* free up arguments and values */ gimp_destroy_params (l_argv, l_nparams); /* free the query information */ g_free (l_proc_blurb); g_free (l_proc_help); g_free (l_proc_author); g_free (l_proc_copyright); g_free (l_proc_date); g_free (l_params); g_free (l_return_vals); l_rc = -1; if (l_ret_params[0].data.d_status != GIMP_PDB_SUCCESS) { printf("ERROR: gap_filt_pdb_call_plugin %s failed.\n", plugin_name); } else { if(gap_debug) printf("DEBUG: gap_filt_pdb_call_plugin: %s successful.\n", plugin_name); l_rc = 0; /* OK */ } gimp_destroy_params(l_ret_params, l_retvals); return(l_rc); } /* end gap_filt_pdb_call_plugin */ /* ------------------------ * gap_filt_pdb_save_xcf * ------------------------ */ int gap_filt_pdb_save_xcf(gint32 image_id, char *sav_name) { GimpParam* l_params; gint l_retvals; gint l_rc; /* save current image as xcf file * xcf_save does operate on the complete image, * the drawable is ignored. (we can supply a dummy value) */ l_params = gimp_run_procedure ("gimp_xcf_save", &l_retvals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, image_id, GIMP_PDB_DRAWABLE, 0, GIMP_PDB_STRING, sav_name, GIMP_PDB_STRING, sav_name, /* raw name ? */ GIMP_PDB_END); l_rc = -1; if (l_params[0].data.d_status == GIMP_PDB_SUCCESS) { l_rc = 0; /* OK */ } gimp_destroy_params (l_params, l_retvals); return (l_rc); } /* end gap_filt_pdb_save_xcf */ /* ------------------------ * gap_filt_pdb_get_data * ------------------------ * gap_filt_pdb_get_data * try to get the plugin's data (key is usually the name of the plugin) * and check for the length of the retrieved data. * if all done OK return the length of the retrieved data, * return -1 in case of errors. */ gint gap_filt_pdb_get_data(char *key) { int l_len; l_len = gimp_get_data_size (key); if(l_len < 1) { printf("ERROR gap_filt_pdb_get_data: no stored data found for Key %s\n", key); return -1; } if(global_plugin_data) { g_free(global_plugin_data); } global_plugin_data = g_malloc0(l_len+1); gimp_get_data(key, global_plugin_data); if(gap_debug) printf("DEBUG gap_filt_pdb_get_data Key:%s retrieved bytes %d\n", key, (int)l_len); return (l_len); } /* end gap_filt_pdb_get_data */ /* ------------------------ * gap_filt_pdb_set_data * ------------------------ * set global_plugin_data */ void gap_filt_pdb_set_data(char *key, gint plugin_data_len) { if(global_plugin_data) { gimp_set_data(key, global_plugin_data, plugin_data_len); } } /* end gap_filt_pdb_set_data */ /* -------------------------------- * gap_filt_pdb_procedure_available * -------------------------------- * return 0 if available, -1 if not available * * if ptype is GAP_PTYP_ITERATOR then check for typical iterator procedure PDB parameters * and return -1 if the procedure is available but has no typical parameters. * * if ptype is GAP_PTYP_CAN_OPERATE_ON_DRAWABLE: * return -1 if procedure has not the 3 typical parameters INT32, IMAGE, DRAWABLE */ gint gap_filt_pdb_procedure_available(char *proc_name, GapFiltPdbProcType ptype) { gint l_nparams; gint l_nreturn_vals; GimpPDBProcType l_proc_type; gchar *l_proc_blurb; gchar *l_proc_help; gchar *l_proc_author; gchar *l_proc_copyright; gchar *l_proc_date; GimpParamDef *l_params; GimpParamDef *l_return_vals; gint l_rc; l_rc = 0; if(gap_pdb_procedure_name_available (proc_name) != TRUE) { if(gap_debug) { printf("DEBUG: NOT found in PDB %s\n", proc_name); } return -1; } /* Query the gimp application's procedural database * regarding a particular procedure. */ if (gimp_procedural_db_proc_info (proc_name, &l_proc_blurb, &l_proc_help, &l_proc_author, &l_proc_copyright, &l_proc_date, &l_proc_type, &l_nparams, &l_nreturn_vals, &l_params, &l_return_vals)) { /* procedure found in PDB */ if(gap_debug) { printf("DEBUG: found in PDB %s\n", proc_name); } switch(ptype) { case GAP_PTYP_ITERATOR: /* check exactly for Input Parametertypes (common to all Iterators) */ if (l_proc_type != GIMP_PLUGIN ) { l_rc = -1; break; } if (l_nparams != 4) { l_rc = -1; break; } if (l_params[0].type != GIMP_PDB_INT32) { l_rc = -1; break; } if (l_params[1].type != GIMP_PDB_INT32) { l_rc = -1; break; } if (l_params[2].type != GIMP_PDB_FLOAT) { l_rc = -1; break; } if (l_params[3].type != GIMP_PDB_INT32) { l_rc = -1; break; } break; case GAP_PTYP_CAN_OPERATE_ON_DRAWABLE: /* check if plugin can be a typical one, that works on one drawable */ if (l_proc_type != GIMP_PLUGIN) { l_rc = -1; break; } if (l_nparams < 3) { l_rc = -1; break; } if (l_params[0].type != GIMP_PDB_INT32) { l_rc = -1; break; } if (l_params[1].type != GIMP_PDB_IMAGE) { l_rc = -1; break; } if (l_params[2].type != GIMP_PDB_DRAWABLE) { l_rc = -1; break; } break; default: break; } /* free the query information */ g_free (l_proc_blurb); g_free (l_proc_help); g_free (l_proc_author); g_free (l_proc_copyright); g_free (l_proc_date); g_free (l_params); g_free (l_return_vals); } else { /* procedure is not n the PDB */ return -1; } return l_rc; } /* end gap_filt_pdb_procedure_available */ /* ------------------------ * p_count_iterable_params * ------------------------ * Count iterable Parameters in the last_values_description. */ static gint p_count_iterable_params(gchar *key_description, gint desc_size) { GimpLastvalDescType *lastval_desc_arr; gint l_idx; gint arg_cnt; gint l_count; l_count = 0; lastval_desc_arr = g_malloc(desc_size); arg_cnt = desc_size / sizeof(GimpLastvalDescType); gimp_get_data(key_description, lastval_desc_arr); for(l_idx = 0; l_idx < arg_cnt; l_idx++) { if(lastval_desc_arr[l_idx].lastval_type == GIMP_LASTVAL_END) { break; } if(lastval_desc_arr[l_idx].iter_flag == GIMP_ITER_TRUE && lastval_desc_arr[l_idx].lastval_type > GIMP_LASTVAL_STRUCT_END) { l_count++; } } if (gap_debug) printf("p_count_iterable_params: %s COUNT: %d\n", key_description, (int)l_count); return (l_count); } /* end p_count_iterable_params */ /* ----------------------------------------------- * p_filt_pdb_get_alternative_iterator_proc * ----------------------------------------------- */ static char * p_filt_pdb_get_alternative_iterator_proc(char *plugin_name, gint *count) { char *l_plugin_iterator; gchar *l_key_description; gint l_desc_size; l_plugin_iterator = NULL; /* read all last value descriptions from file and set data in memory */ gimp_lastval_desc_update(); /* check for a description of LAST_VALUES buffer (we use a COMMON ITERATOR if available) */ l_key_description = gimp_lastval_desc_keyname (plugin_name); l_desc_size = gimp_get_data_size(l_key_description); if(l_desc_size > 0) { *count = p_count_iterable_params(l_key_description, l_desc_size); l_plugin_iterator = g_strdup(GIMP_PLUGIN_GAP_COMMON_ITER); } g_free(l_key_description); if(l_plugin_iterator == NULL) { l_plugin_iterator = g_strdup_printf("%s%s", plugin_name, GAP_ITERATOR_ALT_SUFFIX); /* check for alternative Iterator -Iterator-ALT * for gimp-1.3.x i made some Iterator Plugins using the ending -ALT, * If New plugins were added or existing ones were updated * the Authors should supply original _Iterator Procedures * to be used instead of my Hacked versions without name conflicts. * -Iterator-ALT procedures should be replaced by common iterator in future gimp releases */ if(gap_filt_pdb_procedure_available(l_plugin_iterator, GAP_PTYP_ITERATOR) < 0) { /* no iterator available */ g_free(l_plugin_iterator); l_plugin_iterator = NULL; } else { *count = 1; } } return (l_plugin_iterator); } /* end p_filt_pdb_get_alternative_iterator_proc */ /* -------------------------------- * gap_filt_pdb_get_iterator_proc * -------------------------------- * check the PDB for Iterator Procedures in the following order: * 1.) a PDB procedurename with suffix "-Iterator" or * 1.1) a PDB procedurename in old naming style with underscore character * and suffix "-Iterator" * 2.) search for a description of LAST_VALUES buffer in file * (and set all available descriptions in memory, * to speed up further searches in this session) * 3.) a PDB procedurename with suffix "-Iterator-ALT" * return Pointer to the name of the Iterator Procedure * or NULL if not found * * The name of the common iterator procedure "plug_in_gap_COMMON_ITERATOR" * is returned for * the case when the description of LAST_VALUES buffer is available * and there is no individual Iterator Procedure. */ char * gap_filt_pdb_get_iterator_proc(const char *plugin_name, gint *count) { char *l_plugin_iterator; char *canonical_name; canonical_name = gimp_canonicalize_identifier(plugin_name); /* check for matching Iterator PluginProcedures */ l_plugin_iterator = g_strdup_printf("%s%s", canonical_name, GAP_ITERATOR_SUFFIX); /* check if iterator (new naming style) is available in PDB */ if(gap_filt_pdb_procedure_available(l_plugin_iterator, GAP_PTYP_ITERATOR) < 0) { g_free(l_plugin_iterator); *count = 0; l_plugin_iterator = p_filt_pdb_get_alternative_iterator_proc(canonical_name, count); } else { *count = 1; } if(gap_debug) { printf("gap_filt_pdb_get_iterator_proc: END\n plugin:%s\n canonical:%s\n iterator_proc:%s\n" , plugin_name , canonical_name , l_plugin_iterator ); } g_free(canonical_name); return (l_plugin_iterator); } /* end gap_filt_pdb_get_iterator_proc */ /* --------------------------------- * gap_filt_pdb_constraint_proc_sel1 * --------------------------------- * constraint procedures * * are responsible for: * - sensitivity of the dbbrowser's Apply Buttons * - filter for dbbrowser's listbox */ int gap_filt_pdb_constraint_proc_sel1(gchar *proc_name, gint32 image_id) { /* here we should check, if proc_name * can operate on the current Imagetype (RGB, INDEXED, GRAY) * if not, 0 should be returned. */ return 1; #ifdef THIS_IS_A_COMMENT_DONT_COMPILE { int l_rc; GimpImageBaseType l_base_type; l_rc = 0; /* 0 .. set Apply Button in_sensitive */ l_base_type = gimp_image_base_type(image_id); switch(l_base_type) { case GIMP_RGB: case GIMP_GRAY: case GIMP_INDEXED: l_rc = 1; break; } return l_rc; } #endif } int gap_filt_pdb_constraint_proc_sel2(gchar *proc_name, gint32 image_id) { char *l_plugin_iterator; int l_rc; gint l_count; l_rc = gap_filt_pdb_constraint_proc_sel1(proc_name, image_id); if(l_rc != 0) { l_plugin_iterator = gap_filt_pdb_get_iterator_proc(proc_name, &l_count); if(l_plugin_iterator != NULL) { g_free(l_plugin_iterator); if(l_count > 0) { /* Plug-In has Iterator and is able to iterate at least 1 Parameter */ return 1; /* 1 .. set "Apply Varying" Button sensitive */ } } } return 0; /* 0 .. set "Apply Varying" Button in_sensitive */ } /* end */ /* ------------------------------------------------- * gap_filt_pdb_check_additional_supported_procedure * ------------------------------------------------- * check for procedures that are able to run with filter all layers * (limited to Constant apply) without having an iterator. * most of them have no dialog for the interactive runmode. * * some of them operate without a LAST_VALUES buffer * to support even those plug-ins a dummy buffer is added here * * this hardcoded check is based on tests with gimp-2.2pre1 */ gboolean gap_filt_pdb_check_additional_supported_procedure(const char *proc_name) { static gint buf; /* if(strcmp(proc_name, "plug_in_autocrop_layer") == 0) { return (TRUE); } */ if(strcmp(proc_name, "plug-in-autostretch-hsv") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-blur") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-c-astretch") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-color-adjust") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-color-enhance") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-deinterlace") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-dilate") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-erode") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-gradmap") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-hot") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-laplace") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-make-seamless") == 0) { /* add a dummy LAST_VALUE buffer if there is none */ if(gimp_get_data_size(proc_name) == 0) { gimp_set_data(proc_name, &buf, sizeof(buf)); } return (TRUE); } if(strcmp(proc_name, "plug-in-max-rgb") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-normalize") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-pixelize2") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-qbist") == 0) { return (TRUE); } if(strcmp(proc_name, "plug-in-vinvert") == 0) { /* add a dummy LAST_VALUE buffer if there is none */ if(gimp_get_data_size(proc_name) == 0) { gimp_set_data(proc_name, &buf, sizeof(buf)); } return (TRUE); } return (FALSE); } /* end gap_filt_pdb_check_additional_supported_procedure */ /* ---------------------------- * gap_filt_pdb_constraint_proc * ---------------------------- * checks if the specified proc_name * is relevant to be available in the GIMP-GAP filter browser. * * returns 1 for relevant proc_names * returns 0 for NON-relevant proc_names */ int gap_filt_pdb_constraint_proc(gchar *proc_name, gint32 image_id) { int l_rc; char *l_plugin_iterator; gint l_count; if(strncmp(proc_name, "file", 4) == 0) { /* Do not add file Plugins (check if name starts with "file") */ return 0; } if(strncmp(proc_name, "plug-in-gap-", 12) == 0) { /* Do not add GAP Plugins (check if name starts with "plug-in-gap-") */ return 0; } if(strncmp(proc_name, "plug_in_gap_", 12) == 0) { /* Do not add GAP Plugins (check if name starts with "plug_in_gap_" (old name style)) */ return 0; } l_rc = gap_filt_pdb_procedure_available(proc_name, GAP_PTYP_CAN_OPERATE_ON_DRAWABLE); if(l_rc < 0) { /* Do not add, Plug-in not available or wrong type */ return 0; } if(gap_debug) { /* skip the last check for iterator in debug mode * want to see the other procedures too in that case (hof) */ return 1; /* 1 add the plugin procedure */ } l_plugin_iterator = gap_filt_pdb_get_iterator_proc(proc_name, &l_count); if(l_plugin_iterator == NULL) { /* hardcoded check for some known exceptions * that are useful for constant apply * (even if they have no iterator) */ if(gap_filt_pdb_check_additional_supported_procedure(proc_name)) { return 1; /* 1 add the plugin procedure */ } /* do not add Plug-In without Iterator or Common Iterator */ return 0; } g_free(l_plugin_iterator); return 1; /* 1 add the plugin procedure */ } /* end gap_filt_pdb_constraint_proc */ /* ------------------------ * gap_filter_iterator_call * ------------------------ * performs one iteration step * for varying the last value buffer for the plug in plugin_name * by calling the relevant terator procedure * specified by iteratorname. * */ gboolean gap_filter_iterator_call(const char *iteratorname , gint32 total_steps , gdouble current_step , const char *plugin_name , gint32 plugin_data_len ) { GimpParam *l_params; gint l_retvals; gboolean l_rc; l_rc = TRUE; /* call plugin-specific iterator (or the common iterator), to modify * the plugin's last_values */ if(gap_debug) { printf("DEBUG: calling iterator %s current step:%f total:%d\n" , iteratorname , (float)current_step , (int)total_steps ); } if(strcmp(iteratorname, GIMP_PLUGIN_GAP_COMMON_ITER) == 0) { l_params = gimp_run_procedure (iteratorname, &l_retvals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_INT32, total_steps, GIMP_PDB_FLOAT, current_step, GIMP_PDB_INT32, plugin_data_len, /* length of stored data struct */ GIMP_PDB_STRING, plugin_name, /* the common iterator needs the plugin name as additional param */ GIMP_PDB_END); } else { l_params = gimp_run_procedure (iteratorname, &l_retvals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_INT32, total_steps, GIMP_PDB_FLOAT, current_step, GIMP_PDB_INT32, plugin_data_len, /* length of stored data struct */ GIMP_PDB_END); } if (l_params[0].data.d_status != GIMP_PDB_SUCCESS) { printf("ERROR: iterator %s failed\n", iteratorname); l_rc = FALSE; } gimp_destroy_params(l_params, l_retvals); return (l_rc); } /* end gap_filter_iterator_call */ gimp-gap-2.6.0+dfsg.orig/gap/gap_range_ops.h0000644000175000017500000000761611212030253020503 0ustar thibautthibaut/* gap_range_ops.h * 1998.07.03 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * GAP operations on frame Ranges (from - to) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 1.3.5a; 2002/04/20 hof: API cleanup * 1.1.10a; 1999/10/22 hof: extended dither options in gap_range_conv * 0.97.00; 1998/10/19 hof: extended gap_range_to_multilayer layer seletion * 0.96.03; 1998/08/31 hof: gap_range_to_multilayer: all params available * in non-interactive runmode * 0.96.00; 1998/07/02 hof: (extracted from gap_lib.h) * 0.94.01; 1998/04/27 hof: added flatten_mode to plugin: gap_range_to_multilayer */ #ifndef _GAP_RANGE_OPS_H #define _GAP_RANGE_OPS_H #include "libgimp/gimp.h" /* flatten mode bits used in gap_range_to_multilayer */ #define GAP_RANGE_OPS_FLAM_MERG_EXPAND 0 #define GAP_RANGE_OPS_FLAM_MERG_CLIP_IMG 1 #define GAP_RANGE_OPS_FLAM_MERG_CLIP_BG 2 #define GAP_RANGE_OPS_FLAM_MERG_FLAT 3 /* region selection modes used in gap_range_to_multilayer */ #define GAP_RANGE_OPS_SEL_IGNORE 0 #define GAP_RANGE_OPS_SEL_INITIAL 1 #define GAP_RANGE_OPS_SEL_FRAME_SPECIFIC 2 /* Animation sizechange modes */ typedef enum { GAP_ASIZ_SCALE , GAP_ASIZ_RESIZE , GAP_ASIZ_CROP } GapRangeOpsAsiz; gint32 gap_range_to_multilayer(GimpRunMode run_mode, gint32 image_id, long range_from, long range_to, long flatten_mode, long bg_visible, long framerate, char *frame_basename, int frame_basename_len, gint32 sel_mode, gint32 sel_case, gint32 sel_invert, char *sel_pattern, gint32 selection_mode ); gint32 gap_range_flatten(GimpRunMode run_mode, gint32 image_id, long range_from, long range_to); gint32 gap_range_layer_del(GimpRunMode run_mode, gint32 image_id, long range_from, long range_to, long position); gint32 gap_range_conv(GimpRunMode run_mode, gint32 image_id, long range_from, long range_to, long flatten, GimpImageBaseType dest_type, gint32 dest_colors, gint32 dest_dither, char *basename, char *extension, gint32 palette_type, gint32 alpha_dither, gint32 remove_unused, char *palette ); int gap_range_anim_sizechange(GimpRunMode run_mode, GapRangeOpsAsiz asiz_mode, gint32 image_id, long size_x, long size_y, long offs_x, long offs_y); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_wr_color_curve.c0000644000175000017500000012306511212030253021550 0ustar thibautthibaut/* gap_wr_color_curve.c * 2000.Feb.21 hof (Wolfgang Hofer) * * Wrapper Plugin for GIMP Curves tool * * This HACK enables * Animated Filterapply in conjunction with the * GIMP Curve Tool. * * It provides a primitive Dialog Interface where you * can load Curves (from Files saved by the Curve Tool of GIMP releases 1.2 up to GIMP-2.6) * and run The Curve Tool with these values as a Plugin on the current Drawable. * * Further it has an Interface to 'Run_with_last_values' * and an Iterator Procedure. * (This enables the 'Animated Filter Call' from * the GAP's Menu Filters->Filter all Layers * and You can create Curves based Coloranimations) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* Revision history * (2005/01/29) v2.1 hof: added Help * (2004/01/15) v1.3 hof: integrated into GIMP-GAP * (2003/10/30) v1.3 hof: adapted for gimp-1.3.x and gtk+2.2 API * (2002/10/27) v1.03 hof: appear in menu (enable filtermacro use) * (2002/01/01) v1.02 hof: removed GIMP_ENABLE_COMPAT_CRUFT (gimp 1.2.x) * (2000/10/06) v1.01 hof: - GIMP_ENABLE_COMPAT_CRUFT to compile with gimptool 1.1.26 * (2000/02/22) v1.0 hof: first public release * (2000/02/21) v0.0 hof: coding started, */ #include "config.h" #include #include #include #include #include #include #include "gap_libgapbase.h" #include "gap_stock.h" #include "gap-intl.h" /* Defines */ #define PLUG_IN_NAME "plug-in-wr-curves" #define PLUG_IN_IMAGE_TYPES "RGB*, GRAY*" #define PLUG_IN_AUTHOR "Wolfgang Hofer (hof@gimp.org)" #define PLUG_IN_COPYRIGHT "Wolfgang Hofer" #define PLUG_IN_DESCRIPTION "Wrapper for GIMP Curves Tool call based on Curves file" #define PLUG_IN_ITER_NAME "plug-in-wr-curves-Iterator" #define PLUG_IN_DATA_ITER_FROM "plug-in-wr-curves-ITER-FROM" #define PLUG_IN_DATA_ITER_TO "plug-in-wr-curves-ITER-TO" #define PLUG_IN_HELP_ID "plug-in-wr-curves" /* pointval_t * wanted to use gdouble to store plugin data * but in older version of gap_filter_pdb.h * there is a hardcoded limt * * PLUGIN_DATA_SIZE 8192 * * pointval_t guint8 precision will do it for the * curves tool. * But you may set pointval_t to gdouble * if you have a gimp/gap version newer than 1.1.17 */ typedef guint8 pointval_t; /* typedef gdouble pointval_t; */ typedef struct { pointval_t val_curve[5][256]; } wr_curves_val_t; /* The Stuff for calculating the Curve * was taken from gimp-1.1.17/app/curves.c * (and reduced for non-ineracive usage) */ #define SMOOTH 0 #define GFREE 1 typedef double CRMatrix[4][4]; typedef struct _CurvesDialog CurvesDialog; struct _CurvesDialog { gint channel; gint curve_type[5]; gint points[5][17][2]; guchar curve[5][256]; gint col_value[5]; }; typedef struct _WrCurveDialog WrCurveDialog; struct _WrCurveDialog { gint run; gint show_progress; gchar *filename; GtkWidget *shell; GtkWidget *filesel; GtkWidget *entry; }; /* stuff to parse curves format introduced with GIMP-2.6 */ #define TOKEN_SAMPLES "samples" #define TOKEN_CHANNEL "channel" #define TOKEN_CURVE "curve" #define MAX_CHANNELS 5 #define MAX_FILESIZE 800000 typedef struct { /* nick cpc */ gchar *buffer; /* holds the complete file content without the header line */ gchar *ptr; /* (Do not g_free this) pointer to current parsing position in the buffer */ gint channel_index; /* curent channel */ gint point_index; /* current point in the current channel */ gboolean channel_found[MAX_CHANNELS]; gboolean samples_found[MAX_CHANNELS]; wr_curves_val_t *cuvals; /* (Do not g_free this) reference */ } CurveParserContext; /* ============= stuff for curves format of GIMP-1.1 up to GIMP-2.4 release */ static void curves_CR_compose (CRMatrix, CRMatrix, CRMatrix); static void curves_plot_curve (CurvesDialog *, int, int, int, int); static void curves_calculate_curve (CurvesDialog *cd); static gboolean read_curves_from_file (const char *filename, FILE *fp, wr_curves_val_t *cuvals); /* ============== stuff for curves format of GIMP-2.6 release */ static CurveParserContext* p_new_CurveParserContext(gint32 fileSize, FILE *fp, wr_curves_val_t *cuvals); static gint32 p_read_gint32_value(CurveParserContext *cpc); static gdouble p_read_gdouble_value(CurveParserContext *cpc); static void p_skip_whitespace(CurveParserContext *cpc); static void p_skip_until_opening_bracket(CurveParserContext *cpc); static void p_skip_until_closing_bracket(CurveParserContext *cpc); static void p_read_channel(CurveParserContext *cpc); static void p_read_samples(CurveParserContext *cpc); static void p_read_curve(CurveParserContext *cpc); static gboolean p_read_curves_from_file_gimp2_6_format (const char *filename, FILE *fp, wr_curves_val_t *cuvals, gchar *buf); static int p_load_curve(gchar *filename, wr_curves_val_t *cuvals); static void p_delta_pointval_t (pointval_t *val, pointval_t val_from, pointval_t val_to, gint32 total_steps, gdouble current_step); static gint32 p_gimp_curves_explicit (gint32 drawable_id, gint32 channel, gint32 num_bytes, gint8 *curve_points); static void p_run_curves_tool(gint32 drawable_id, wr_curves_val_t *cuvals); /* stuff for the dialog */ static void p_filesel_close_cb (GtkWidget *widget, gpointer data); static void p_filesel_ok_callback (GtkWidget *widget, gpointer data); static void wr_curve_load_callback (GtkWidget *w, WrCurveDialog *wcd); static void text_entry_callback(GtkWidget *widget, WrCurveDialog *wcd); static void wr_curve_response (GtkWidget *widget, gint response_id, WrCurveDialog *gpp); WrCurveDialog *do_dialog (wr_curves_val_t *); /* required stuff for gimp-plug-ins */ static void query (void); static void run(const gchar *name , gint nparams , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals); static gboolean p_read_curves_from_file_gimp2_6_format (const char *filename, FILE *fp, wr_curves_val_t *cuvals, gchar *buf); /* Global Variables */ GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run /* run_proc */ }; static CRMatrix CR_basis = { { -0.5, 1.5, -1.5, 0.5 }, { 1.0, -2.5, 2.0, -0.5 }, { -0.5, 0.0, 0.5, 0.0 }, { 0.0, 1.0, 0.0, 0.0 }, }; /* Global Variables */ int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */ /* -------------- * procedures * -------------- */ /* ============================ START curve calculation from GIMP-2.4 curves fileformat ====================== */ static void curves_CR_compose (CRMatrix a, CRMatrix b, CRMatrix ab) { gint i, j; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { ab[i][j] = (a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j] + a[i][3] * b[3][j]); } } } static void curves_plot_curve (CurvesDialog *cd, gint p1, gint p2, gint p3, gint p4) { CRMatrix geometry; CRMatrix tmp1, tmp2; CRMatrix deltas; double x, dx, dx2, dx3; double y, dy, dy2, dy3; double d, d2, d3; int lastx, lasty; gint32 newx, newy; int i; /* construct the geometry matrix from the segment */ for (i = 0; i < 4; i++) { geometry[i][2] = 0; geometry[i][3] = 0; } for (i = 0; i < 2; i++) { geometry[0][i] = cd->points[cd->channel][p1][i]; geometry[1][i] = cd->points[cd->channel][p2][i]; geometry[2][i] = cd->points[cd->channel][p3][i]; geometry[3][i] = cd->points[cd->channel][p4][i]; } /* subdivide the curve 1000 times */ /* n can be adjusted to give a finer or coarser curve */ d = 1.0 / 1000; d2 = d * d; d3 = d * d * d; /* construct a temporary matrix for determining the forward differencing deltas */ tmp2[0][0] = 0; tmp2[0][1] = 0; tmp2[0][2] = 0; tmp2[0][3] = 1; tmp2[1][0] = d3; tmp2[1][1] = d2; tmp2[1][2] = d; tmp2[1][3] = 0; tmp2[2][0] = 6*d3; tmp2[2][1] = 2*d2; tmp2[2][2] = 0; tmp2[2][3] = 0; tmp2[3][0] = 6*d3; tmp2[3][1] = 0; tmp2[3][2] = 0; tmp2[3][3] = 0; /* compose the basis and geometry matrices */ curves_CR_compose (CR_basis, geometry, tmp1); /* compose the above results to get the deltas matrix */ curves_CR_compose (tmp2, tmp1, deltas); /* extract the x deltas */ x = deltas[0][0]; dx = deltas[1][0]; dx2 = deltas[2][0]; dx3 = deltas[3][0]; /* extract the y deltas */ y = deltas[0][1]; dy = deltas[1][1]; dy2 = deltas[2][1]; dy3 = deltas[3][1]; lastx = CLAMP (x, 0, 255); lasty = CLAMP (y, 0, 255); cd->curve[cd->channel][lastx] = lasty; /* loop over the curve */ for (i = 0; i < 1000; i++) { /* increment the x values */ x += dx; dx += dx2; dx2 += dx3; /* increment the y values */ y += dy; dy += dy2; dy2 += dy3; newx = CLAMP0255 (ROUND (x)); newy = CLAMP0255 (ROUND (y)); /* if this point is different than the last one...then draw it */ if ((lastx != newx) || (lasty != newy)) cd->curve[cd->channel][newx] = newy; lastx = newx; lasty = newy; } } static void curves_calculate_curve (CurvesDialog *cd) { int i; int points[17]; int num_pts; int p1, p2, p3, p4; switch (cd->curve_type[cd->channel]) { case GFREE: break; case SMOOTH: /* cycle through the curves */ num_pts = 0; for (i = 0; i < 17; i++) if (cd->points[cd->channel][i][0] != -1) points[num_pts++] = i; /* Initialize boundary curve points */ if (num_pts != 0) { for (i = 0; i < cd->points[cd->channel][points[0]][0]; i++) cd->curve[cd->channel][i] = cd->points[cd->channel][points[0]][1]; for (i = cd->points[cd->channel][points[num_pts - 1]][0]; i < 256; i++) cd->curve[cd->channel][i] = cd->points[cd->channel][points[num_pts - 1]][1]; } for (i = 0; i < num_pts - 1; i++) { p1 = (i == 0) ? points[i] : points[(i - 1)]; p2 = points[i]; p3 = points[(i + 1)]; p4 = (i == (num_pts - 2)) ? points[(num_pts - 1)] : points[(i + 2)]; curves_plot_curve (cd, p1, p2, p3, p4); } break; } } /* ---------------------------------------- * read_curves_from_file * ---------------------------------------- */ static gboolean read_curves_from_file (const char *filename, FILE *fp, wr_curves_val_t *cuvals) { gint i, j, fields; gchar buf[50]; gint index[5][17]; gint value[5][17]; gint current_channel; CurvesDialog curves_dialog_struct; CurvesDialog *curves_dialog = &curves_dialog_struct; if (!fgets (buf, 50, fp)) { return FALSE; } /* check old format used in GIMP-2.4.x and older GIMP releases */ if (strcmp (buf, "# GIMP Curves File\n") != 0) { /* check new format introduced with GIMP-2.6.x release */ return (p_read_curves_from_file_gimp2_6_format (filename, fp, cuvals, buf)); } for (i = 0; i < 5; i++) { for (j = 0; j < 17; j++) { fields = fscanf (fp, "%d %d ", &index[i][j], &value[i][j]); if (fields != 2) { g_print ("fields != 2"); return FALSE; } } } for (i = 0; i < 5; i++) { curves_dialog->curve_type[i] = SMOOTH; for (j = 0; j < 17; j++) { curves_dialog->points[i][j][0] = index[i][j]; curves_dialog->points[i][j][1] = value[i][j]; } } /* this is ugly, but works ... */ current_channel = curves_dialog->channel; for (i = 0; i < 5; i++) { curves_dialog->channel = i; curves_calculate_curve (curves_dialog); for(j = 0; j < 256; j++) { cuvals->val_curve[i][j] = (pointval_t)curves_dialog->curve[i][j]; } } curves_dialog->channel = current_channel; return TRUE; } /* ============================ START parsing GIMP-2.6 curves file ====================== */ /* ---------------------------------------- * p_new_CurveParserContext * ---------------------------------------- * loads the Curve settings from the specified file, * (starting at current position, (typically full content that follows the header line) * and sts up a context for parsing. */ static CurveParserContext* p_new_CurveParserContext(gint32 fileSize, FILE *fp, wr_curves_val_t *cuvals) { CurveParserContext *cpc; gint ii; cpc = g_new(CurveParserContext, 1); cpc->buffer = (gchar *) g_malloc0(fileSize+1); /* read all the rest of the file into buffer */ fread(cpc->buffer, 1, (size_t)fileSize, fp); cpc->ptr = cpc->buffer; cpc->channel_index = 0; cpc->point_index = 0; cpc->cuvals = cuvals; for(ii=0; ii < MAX_CHANNELS; ii++) { cpc->channel_found[ii] = FALSE; cpc->samples_found[ii] = FALSE; } return (cpc); } /* end p_new_CurveParserContext */ /* ---------------------------------------- * p_read_gint32_value * ---------------------------------------- * read integer value and advance scan ptr to char after the number */ static gint32 p_read_gint32_value(CurveParserContext *cpc) { gchar *l_end_ptr; long l_num; l_num = 0; if(cpc->ptr) { if(*cpc->ptr != '\0') { l_end_ptr = cpc->ptr; l_num = strtol(cpc->ptr, &l_end_ptr, 10); if (cpc->ptr != l_end_ptr) { cpc->ptr = l_end_ptr; return ((gint32)l_num); } printf("ERROR incompatible Curve settings, scan of int value failed\n"); } } return (l_num); } /* end p_read_gint32_value */ /* ---------------------------------------- * p_read_gdouble_value * ---------------------------------------- * read doble value and advance scan ptr to char after the number */ static gdouble p_read_gdouble_value(CurveParserContext *cpc) { char *l_end_ptr; double l_doubleValue; l_doubleValue = 0.0; if(cpc->ptr) { if(*cpc->ptr != '\0') { l_end_ptr = cpc->ptr; l_doubleValue = g_ascii_strtod(cpc->ptr, &l_end_ptr); if (cpc->ptr != l_end_ptr) { cpc->ptr = l_end_ptr; return ((gdouble)l_doubleValue); } printf("ERROR incompatible Curve settings, scan of double value failed\n"); } } return (l_doubleValue); } /* end p_read_gdouble_value */ /* ---------------------------------------- * p_skip_whitespace * ---------------------------------------- */ static void p_skip_whitespace(CurveParserContext *cpc) { while(*cpc->ptr != '\0') { switch (*cpc->ptr) { case ' ': case '\t': case '\r': case '\n': break; case '#': while (*cpc->ptr != '\n') { cpc->ptr++; if (*cpc->ptr == '\0') { return; } } break; default: return; break; } cpc->ptr++; } } /* end p_skip_whitespace */ /* ---------------------------------------- * p_skip_until_opening_bracket * ---------------------------------------- * advance scan ptr to position after the next opening bracket */ static void p_skip_until_opening_bracket(CurveParserContext *cpc) { while(*cpc->ptr != '\0') { if (*cpc->ptr == '(') { cpc->ptr++; return; } cpc->ptr++; } } /* end p_skip_until_opening_bracket */ /* ---------------------------------------- * p_skip_until_closing_bracket * ---------------------------------------- * advance scan ptr to position after the closing bracket */ static void p_skip_until_closing_bracket(CurveParserContext *cpc) { int countBr; countBr = 0; while(*cpc->ptr != '\0') { switch (*cpc->ptr) { case '(': countBr++; break; case ')': countBr--; if (countBr < 0) { cpc->ptr++; return; } break; } cpc->ptr++; } } /* end p_skip_until_closing_bracket */ /* ---------------------------------------- * p_read_channel * ---------------------------------------- */ static void p_read_channel(CurveParserContext *cpc) { static const char *channel_name[] = {"value", "red", "green", "blue", "alpha" }; gint ii; cpc->ptr += strlen(TOKEN_CHANNEL); p_skip_whitespace(cpc); for (ii = 0; ii < MAX_CHANNELS; ii++) { int lenChannelName; lenChannelName = strlen(channel_name[ii]); if(strncmp(cpc->ptr, channel_name[ii], lenChannelName) == 0) { cpc->channel_index = ii; cpc->channel_found[ii] = TRUE; if(gap_debug) { printf("\nCHANNEL token %s index:%d\n", channel_name[ii], cpc->channel_index ); } } } p_skip_until_closing_bracket(cpc); } /* end p_read_channel */ /* ---------------------------------------- * p_read_samples * ---------------------------------------- * read the samples token followed by one integer and 256 double values * set scan position after the closing bracket of the samples token. */ static void p_read_samples(CurveParserContext *cpc) { gint32 intValue; gdouble doubleValue; cpc->ptr += strlen(TOKEN_SAMPLES); p_skip_whitespace(cpc); intValue = p_read_gint32_value(cpc); cpc->point_index = 0; while(*cpc->ptr != '\0') { p_skip_whitespace(cpc); doubleValue = p_read_gdouble_value(cpc); cpc->cuvals->val_curve[cpc->channel_index][cpc->point_index] = CLAMP0255 (ROUND (doubleValue * 255)); if(gap_debug) { printf(" [%d] [%03d] %d %f\n" , (int) cpc->channel_index , (int) cpc->point_index , (int) cpc->cuvals->val_curve[cpc->channel_index][cpc->point_index] , (float) doubleValue ); } cpc->point_index++; /* check if all sample points done */ if (cpc->point_index >= 256) { cpc->samples_found[cpc->channel_index] = TRUE; p_skip_until_closing_bracket(cpc); return; } if (*cpc->ptr == ')') { cpc->ptr++; return; } } } /* end p_read_samples */ /* ---------------------------------------- * p_read_curve * ---------------------------------------- * read curve description * this implementation read only the expected 256 samples and ignores (e.g. skips) other parts * of the curve description * the scan ptr is set to the character after the closing bracket. */ static void p_read_curve(CurveParserContext *cpc) { cpc->ptr += strlen(TOKEN_CURVE); while(*cpc->ptr != '\0') { p_skip_whitespace(cpc); p_skip_until_opening_bracket(cpc); if(gap_debug) { printf("\n\np_read_curve cpc->ptr:%100.100s\n", cpc->ptr); } if(strncmp(cpc->ptr, TOKEN_SAMPLES, strlen(TOKEN_SAMPLES)) == 0) { p_read_samples(cpc); } else { /* ignore other tokens within the curve description */ p_skip_until_closing_bracket(cpc); } /* check if closing bracket of the curves description is reached */ if (*cpc->ptr == ')') { cpc->ptr++; return; } } } /* end p_read_curve */ /* ---------------------------------------- * p_read_curves_from_file_gimp2_6_format * ---------------------------------------- * Parse curve points from file * in the new # GIMP curves tool settings * fileformat. * Example content of such a file: * =============================== * # GIMP curves tool settings * (time 0) * (channel value) * (curve * (curve-type smooth) * (n-points 17) * (points 34 0.000000 0.000000 -1.000000 -1.000000 .... * .... -1.000000 -1.000000 1.000000 1.000000) * (n-samples 256) * (samples 256 0.000000 0.003922 0.007843 0.011765 0.015686 ..... * ...... 0.988235 0.992157 0.996078 1.000000)) * (time 0) * (channel red) (curve ............) * (channel green) (curve ............) * (channel blue) (curve ............) * (channel alpha) (curve ............) * * * opposite to the 2.4 format, there is no need to calculate the 256 points in the 2.6 format. * that typically are already provides all 256 points for all 5 channels. * * RESTRICTIONS: * ------------ * the parser is limited to read only the 256 sample points for the 5 channels * value, red, green, blue, alpha * that are required for the non-interactive calls (see also: p_gimp_curves_explicit) * all other tokens in the file are ignored. (even the n-samples token is ignored) * load will fail in case the file does not contain the expected 256 sample points per channel. */ static gboolean p_read_curves_from_file_gimp2_6_format (const char *filename, FILE *fp, wr_curves_val_t *cuvals, gchar *buf) { int ii; gboolean success; gint32 l_fileSize; CurveParserContext *cpc; if(gap_debug) { printf("START p_read_curves_from_file_gimp2_6_format\n"); } l_fileSize = gap_file_get_filesize(filename); if (l_fileSize > MAX_FILESIZE) { printf("ERROR: file %s length %d is larger than plausible size %d\n" , filename , l_fileSize , MAX_FILESIZE ); return FALSE; } if (strcmp (buf, "# GIMP curves tool settings\n") != 0) { printf("ERROR: file %s does not start with '%s'\n", "# GIMP curves tool settings"); return FALSE; } success = TRUE; cpc = p_new_CurveParserContext(l_fileSize, fp, cuvals); while(*cpc->ptr != '\0') { p_skip_whitespace(cpc); p_skip_until_opening_bracket(cpc); if(gap_debug) { printf("\n\nCurves file cpc->ptr:%80.80s\n", cpc->ptr); } if(strncmp(cpc->ptr, TOKEN_CHANNEL, strlen(TOKEN_CHANNEL)) == 0) { p_read_channel(cpc); } else if(strncmp(cpc->ptr, TOKEN_CURVE, strlen(TOKEN_CURVE)) == 0) { p_read_curve(cpc); } else { p_skip_until_closing_bracket(cpc); } } /* check if samples for all channels have been loaded successfully */ for(ii=0; ii < MAX_CHANNELS; ii++) { if ((cpc->channel_found[ii] != TRUE) || (cpc->samples_found[ii] != TRUE)) { success = FALSE; break; } } g_free(cpc->buffer); g_free(cpc); return success; } /* end p_read_curves_from_file_gimp2_6_format */ /* ---------------------------------------- * p_load_curve * ---------------------------------------- * load curve from file, * supports curve file formats of the gimp-2.4.x and gimp-2.6.x releases */ static int p_load_curve(gchar *filename, wr_curves_val_t *cuvals) { FILE *fp; fp = g_fopen (filename, "rt"); if (!fp) { g_message (_("Unable to open file %s"), filename); return -1; } if (!read_curves_from_file (filename, fp, cuvals)) { g_message (("Error in reading file %s"), filename); fclose (fp); return -1; } fclose (fp); return 0; } /* ---------------------------------------- * p_delta_pointval_t * ---------------------------------------- * Delta Calculations for the iterator */ static void p_delta_pointval_t (pointval_t *val, pointval_t val_from, pointval_t val_to, gint32 total_steps, gdouble current_step) { gdouble delta; if(total_steps < 1) return; delta = ((gdouble)(val_to - val_from) / (gdouble)total_steps) * ((gdouble)total_steps - current_step); *val = val_from + delta; } /* ---------------------------------------- * p_gimp_curves_explicit * ---------------------------------------- * PDB call of the curves feature of the gimp color curves tool * for one channel. */ static gint32 p_gimp_curves_explicit (gint32 drawable_id, gint32 channel, gint32 num_bytes, gint8 *curve_points) { static char *l_procname = "gimp_curves_explicit"; GimpParam *return_vals; int nreturn_vals; return_vals = gimp_run_procedure (l_procname, &nreturn_vals, GIMP_PDB_DRAWABLE, drawable_id, GIMP_PDB_INT32, channel, GIMP_PDB_INT32, num_bytes, GIMP_PDB_INT8ARRAY, curve_points, GIMP_PDB_END); if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) { gimp_destroy_params(return_vals, nreturn_vals); return (0); } gimp_destroy_params(return_vals, nreturn_vals); printf("Error: PDB call of %s failed status:%d\n", l_procname, (int)return_vals[0].data.d_status); return(-1); } /* end p_gimp_curves_explicit */ /* ---------------------------------------- * p_run_curves_tool * ---------------------------------------- * run the curves feature of the gimp color curves tool * for all relevant histogram channels */ static void p_run_curves_tool(gint32 drawable_id, wr_curves_val_t *cuvals) { gint32 l_idx; gint32 l_channel; gint32 l_channel_histogram; gint8 curve_points[256]; for(l_channel=4; l_channel >= 0; l_channel--) { gboolean isChannelRelevant; for(l_idx=0; l_idx < 256; l_idx++) { /* curve_points[l_idx] = (gint8)ROUND(cuvals->val_curve[l_channel][l_idx]); */ curve_points[l_idx] = (gint8)cuvals->val_curve[l_channel][l_idx]; } l_channel_histogram = l_channel; isChannelRelevant = FALSE; switch (l_channel) { case 0: /* HISTOGRAM-VALUE */ if (gimp_drawable_is_gray(drawable_id)) { isChannelRelevant = TRUE; } else if (gimp_drawable_is_rgb(drawable_id)) { isChannelRelevant = TRUE; } break; case 1: /* HISTOGRAM-RED */ case 2: /* HISTOGRAM-GREEN */ case 3: /* HISTOGRAM-BLUE */ if (gimp_drawable_is_rgb(drawable_id)) { isChannelRelevant = TRUE; } break; case 4: /* HISTOGRAM-ALPHA */ if (gimp_drawable_has_alpha(drawable_id)) { isChannelRelevant = TRUE; } break; default: isChannelRelevant = FALSE; break; } if (isChannelRelevant) { p_gimp_curves_explicit(drawable_id, l_channel_histogram, 256, curve_points); } } } /* * ===== START of DIALOG and callback stuff =========== */ /* --------------------------------- * wr_curve_load_callback * --------------------------------- */ static void p_filesel_close_cb (GtkWidget *widget, gpointer data) { WrCurveDialog *wcd; wcd = (WrCurveDialog *) data; if(wcd->filesel == NULL) return; gtk_widget_destroy(GTK_WIDGET(wcd->filesel)); wcd->filesel = NULL; /* now filesel is closed */ } /* --------------------------------- * wr_curve_load_callback * --------------------------------- */ static void p_filesel_ok_callback (GtkWidget *widget, gpointer data) { WrCurveDialog *wcd; wr_curves_val_t cuvals; wcd = (WrCurveDialog *) data; if(wcd->filesel == NULL) return; if(wcd->filename) g_free(wcd->filename); wcd->filename = g_strdup(gtk_file_selection_get_filename (GTK_FILE_SELECTION (wcd->filesel))); gtk_entry_set_text(GTK_ENTRY(wcd->entry), wcd->filename); gtk_widget_destroy(GTK_WIDGET(wcd->filesel)); wcd->filesel = NULL; /* try to read the file, * (and make a g_message on errors) */ p_load_curve(wcd->filename, &cuvals); } /* --------------------------------- * wr_curve_load_callback * --------------------------------- */ static void wr_curve_load_callback (GtkWidget *w, WrCurveDialog *wcd) { GtkWidget *filesel; if(wcd == NULL) { return; } if(wcd->filesel != NULL) { gtk_window_present(GTK_WINDOW(wcd->filesel)); return; /* filesel is already open */ } filesel = gtk_file_selection_new ( _("Load color curve from file")); wcd->filesel = filesel; gtk_window_set_position (GTK_WINDOW (filesel), GTK_WIN_POS_MOUSE); g_signal_connect (GTK_FILE_SELECTION (filesel)->ok_button, "clicked", (GtkSignalFunc) p_filesel_ok_callback, wcd); g_signal_connect (GTK_FILE_SELECTION (filesel)->cancel_button, "clicked", (GtkSignalFunc) p_filesel_close_cb, wcd); g_signal_connect (filesel, "destroy", (GtkSignalFunc) p_filesel_close_cb, wcd); if(wcd->filename) { gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), wcd->filename); } gtk_widget_show (filesel); } /* --------------------------------- * text_entry_callback * --------------------------------- */ static void text_entry_callback(GtkWidget *widget, WrCurveDialog *wcd) { if(wcd) { if(wcd->filename) g_free(wcd->filename); wcd->filename = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget))); } } /* --------------------------------- * wr_curve_response * --------------------------------- */ static void wr_curve_response (GtkWidget *widget, gint response_id, WrCurveDialog *wcd) { GtkWidget *dialog; switch (response_id) { case GTK_RESPONSE_OK: if(wcd) { if (GTK_WIDGET_VISIBLE (wcd->shell)) gtk_widget_hide (wcd->shell); wcd->run = TRUE; } default: dialog = NULL; if(wcd) { dialog = wcd->shell; if(dialog) { wcd->shell = NULL; gtk_widget_destroy (dialog); } } gtk_main_quit (); break; } } /* end wr_curve_response */ WrCurveDialog * do_dialog (wr_curves_val_t *cuvals) { WrCurveDialog *wcd; GtkWidget *dialog; GtkWidget *vbox; GtkWidget *hbox; GtkWidget *button; GtkWidget *entry; /* Init UI */ gimp_ui_init ("wr_curves", FALSE); gap_stock_init(); /* The curve_bend dialog */ wcd = g_malloc (sizeof (WrCurveDialog)); wcd->run = FALSE; wcd->filesel = NULL; /* The dialog and main vbox */ dialog = gimp_dialog_new (_("CurvesFile"), "curves_wrapper", NULL, 0, gimp_standard_help_func, PLUG_IN_HELP_ID, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); wcd->shell = dialog; g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (wr_curve_response), wcd); /* the vbox */ vbox = gtk_vbox_new (FALSE, 2); gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, TRUE, TRUE, 0); gtk_widget_show (vbox); /* the hbox */ hbox = gtk_hbox_new (FALSE, 2); gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); gtk_widget_show (hbox); /* The Load button */ button = gtk_button_new_with_label (_("Load Curve")); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (wr_curve_load_callback), wcd); gtk_widget_show (button); gimp_help_set_help_data (button, _("Load curve from a GIMP curve file " "(that was saved with the GIMP's color curve tool)"), NULL); /* The filename entry */ entry = gtk_entry_new(); gtk_widget_set_size_request(entry, 350, -1); gtk_entry_set_text(GTK_ENTRY(entry), ""); gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK (text_entry_callback), wcd); gtk_widget_show (entry); wcd->entry = entry; gtk_widget_show (dialog); gtk_main (); gdk_flush (); return wcd; } MAIN () /* ---------------------------------------- * query * ---------------------------------------- * register as PDB procedure (both the wrapper and iterator) */ static void query (void) { static GimpParamDef args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, { GIMP_PDB_IMAGE, "image", "Input image" }, { GIMP_PDB_DRAWABLE, "drawable", "Input drawable (must be a layer)"}, { GIMP_PDB_STRING, "filename", "Name of a #GIMP curves file (saved by the original Curve Tool)"}, }; static int nargs = sizeof(args) / sizeof(args[0]); static GimpParamDef return_vals[] = { { GIMP_PDB_DRAWABLE, "the_drawable", "the handled drawable" } }; static int nreturn_vals = sizeof(return_vals) / sizeof(return_vals[0]); static GimpParamDef args_iter[] = { {GIMP_PDB_INT32, "run_mode", "non-interactive"}, {GIMP_PDB_INT32, "total_steps", "total number of steps (# of layers-1 to apply the related plug-in)"}, {GIMP_PDB_FLOAT, "current_step", "current (for linear iterations this is the layerstack position, otherwise some value inbetween)"}, {GIMP_PDB_INT32, "len_struct", "length of stored data structure with id is equal to the plug_in proc_name"}, }; static int nargs_iter = sizeof(args_iter) / sizeof(args_iter[0]); static GimpParamDef *return_iter = NULL; static int nreturn_iter = 0; gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); /* the actual installation of the bend plugin */ gimp_install_procedure (PLUG_IN_NAME, PLUG_IN_DESCRIPTION, "This Plugin loads a # GIMP Curves File," " that was saved by the GIMP 2.0pre1 Curves Tool" " then calculates the curves (256 points foreach channel val,r,g,b,a)" " and calls the Curve Tool via PDB interface with the calculated curve points" " It also stores the points, and offers a GIMP_RUN_WITH_LAST_VALUES" " Interface and an Iterator Procedure for animated calls" " of the Curves Tool with varying values" , PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, N_("CurvesFile..."), PLUG_IN_IMAGE_TYPES, GIMP_PLUGIN, nargs, nreturn_vals, args, return_vals); /* the installation of the Iterator extension for the bend plugin */ gimp_install_procedure (PLUG_IN_ITER_NAME, "This extension calculates the modified values for one iterationstep for the call of plug_in_curve_bend", "", PLUG_IN_AUTHOR, PLUG_IN_COPYRIGHT, GAP_VERSION_WITH_DATE, NULL, /* do not appear in menus */ NULL, GIMP_PLUGIN, nargs_iter, nreturn_iter, args_iter, return_iter); { /* Menu names */ const char *menupath_image_video_layer_colors = N_("/Video/Layer/Colors/"); //gimp_plugin_menu_branch_register("", "Video"); //gimp_plugin_menu_branch_register("/Video", "Layer"); //gimp_plugin_menu_branch_register("/Video/Layer", "Colors"); gimp_plugin_menu_register (PLUG_IN_NAME, menupath_image_video_layer_colors); } } /* ---------------------------------------- * run * ---------------------------------------- * the main entry point when the filter is started via the GIMP menu. */ static void run(const gchar *name , gint nparams , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals) { wr_curves_val_t l_cuvals; WrCurveDialog *wcd = NULL; gint32 l_image_id = -1; gint32 l_drawable_id = -1; gint32 l_handled_drawable_id = -1; /* Get the runmode from the in-parameters */ GimpRunMode run_mode = param[0].data.d_int32; /* status variable, use it to check for errors in invocation usualy only during non-interactive calling */ GimpPDBStatusType status = GIMP_PDB_SUCCESS; /*always return at least the status to the caller. */ static GimpParam values[2]; INIT_I18N(); /* initialize the return of the status */ values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; values[1].type = GIMP_PDB_DRAWABLE; values[1].data.d_int32 = -1; *nreturn_vals = 2; *return_vals = values; /* the Iterator Stuff */ if (strcmp (name, PLUG_IN_ITER_NAME) == 0) { gint32 len_struct; gint32 total_steps; gdouble current_step; wr_curves_val_t cval; /* current values while iterating */ wr_curves_val_t cval_from, cval_to; /* start and end values */ gint l_idi, l_idx; /* Iterator procedure for animated calls is usually called from * "plug_in_gap_layers_run_animfilter" * (always run noninteractive) */ if ((run_mode == GIMP_RUN_NONINTERACTIVE) && (nparams == 4)) { total_steps = param[1].data.d_int32; current_step = param[2].data.d_float; len_struct = param[3].data.d_int32; if(len_struct == sizeof(cval)) { /* get _FROM and _TO data, * This data was stored by plug_in_gap_layers_run_animfilter */ gimp_get_data(PLUG_IN_DATA_ITER_FROM, &cval_from); gimp_get_data(PLUG_IN_DATA_ITER_TO, &cval_to); memcpy(&cval, &cval_from, sizeof(cval)); for(l_idi = 0; l_idi < 5; l_idi++) { for(l_idx = 0; l_idx < 256; l_idx++) { p_delta_pointval_t(&cval.val_curve[l_idi][l_idx], cval_from.val_curve[l_idi][l_idx], cval_to.val_curve[l_idi][l_idx], total_steps, current_step); } } gimp_set_data(PLUG_IN_NAME, &cval, sizeof(cval)); } else status = GIMP_PDB_CALLING_ERROR; } else status = GIMP_PDB_CALLING_ERROR; values[0].data.d_status = status; return; } /* get image and drawable */ l_image_id = param[1].data.d_int32; l_drawable_id = param[2].data.d_drawable; if(status == GIMP_PDB_SUCCESS) { /* how are we running today? */ switch (run_mode) { case GIMP_RUN_INTERACTIVE: /* Get information from the dialog */ wcd = do_dialog(&l_cuvals); wcd->show_progress = TRUE; if(wcd->filename == NULL) { status = GIMP_PDB_EXECUTION_ERROR; } else { if(p_load_curve(wcd->filename, &l_cuvals) < 0) { status = GIMP_PDB_EXECUTION_ERROR; } } break; case GIMP_RUN_NONINTERACTIVE: /* check to see if invoked with the correct number of parameters */ if (nparams >= 4) { wcd = g_malloc (sizeof (WrCurveDialog)); wcd->run = TRUE; wcd->show_progress = FALSE; wcd->filename = g_strdup(param[3].data.d_string); } else { status = GIMP_PDB_CALLING_ERROR; } break; case GIMP_RUN_WITH_LAST_VALS: wcd = g_malloc (sizeof (WrCurveDialog)); wcd->run = TRUE; wcd->show_progress = TRUE; /* Possibly retrieve data from a previous run */ gimp_get_data (PLUG_IN_NAME, &l_cuvals); break; default: break; } } if (wcd == NULL) { status = GIMP_PDB_EXECUTION_ERROR; } if (status == GIMP_PDB_SUCCESS) { /* Run the main function */ if(wcd->run) { gimp_image_undo_group_start(l_image_id); p_run_curves_tool(l_drawable_id, &l_cuvals); l_handled_drawable_id = l_drawable_id; gimp_image_undo_group_end(l_image_id); /* Store variable states for next run */ if (run_mode == GIMP_RUN_INTERACTIVE) { gimp_set_data(PLUG_IN_NAME, &l_cuvals, sizeof(l_cuvals)); } } else { status = GIMP_PDB_EXECUTION_ERROR; /* dialog ended with cancel button */ } /* If run mode is interactive, flush displays, else (script) don't do it, as the screen updates would make the scripts slow */ if (run_mode != GIMP_RUN_NONINTERACTIVE) { gimp_displays_flush (); } } values[0].data.d_status = status; values[1].data.d_int32 = l_handled_drawable_id; /* return the id of handled layer */ } /* end run */ gimp-gap-2.6.0+dfsg.orig/gap/gap_fmac_varying_main.c0000644000175000017500000001743511212030253022172 0ustar thibautthibaut/* gap_fmac_varying_main.c * 2006.12.11 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * - filtermacro execution with varying values * For NON-INTERACTIVE callers (e.g the storyboard processor) * Allows to apply filters with a mix of parametervalues * where the parameters are provided in 2 filtermacro files * * see also gap_fmac_main.c for basic filtermacro implementation * * WARNING: * filtermacros are a temporary solution, useful for animations * but do not expect support for filtermacros in future releases of GIMP-GAP * because GIMP may have real makro features in the future ... * * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* SYTEM (UNIX) includes */ #include #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" #include "libgimp/gimpui.h" /* GAP includes */ #include "config.h" #include "gap-intl.h" #include "gap_lib.h" #include "gap_filter.h" #include "gap_filter_pdb.h" #include "gap_fmac_name.h" #include "gap_fmac_base.h" /* revision history: * gimp 2.2.x; 2006/12/11 hof: created. */ /* from gap_fmac_name.h: GAP_FMACNAME_PLUG_IN_NAME_FMAC_VARYING */ #define FMAC_FILE_LENGTH 1500 /* ------------------------ * global gap DEBUG switch * ------------------------ */ /* int gap_debug = 1; */ /* print debug infos */ /* int gap_debug = 0; */ /* 0: dont print debug infos */ int gap_debug = 0; /* ############################################################# */ static void query(void); static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; MAIN () static void query () { static GimpParamDef args_fmac_varying[] = { {GIMP_PDB_INT32, "run_mode", "Interactive"}, {GIMP_PDB_IMAGE, "image", "Input image"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable to be affected by the filtermacro"}, {GIMP_PDB_STRING, "filtermacro_1", "Name of the 1st filtermacro_file to execute on the input drawable)"}, {GIMP_PDB_STRING, "filtermacro_2", "Name of the 2nd filtermacro_file to execute on the input drawable)"}, {GIMP_PDB_FLOAT, "current_step", "current_step. (e.g curently processed frame) " " valid range is 0.0 upto total_steps, " " where 0.0 uses the parameter definitions from filtermacro_1. " " current_step divided by total_steps defines the value mix ratio" " A value mix ratio of 1.0 will use the parameter values of filtermacro_2."}, {GIMP_PDB_INT32, "total_steps", "total number of steps of varying iterations (e.g. number of frames to process)"}, }; static GimpParamDef *return_vals = NULL; static int nreturn_vals = 0; gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); gimp_install_procedure(GAP_FMACNAME_PLUG_IN_NAME_FMAC_VARYING, "This plug-in executes 2 filtermacro scripts, where parameter values of script 1 and 2 are mixed.", "This plug-in allows the non-interactive caller to execute correlated filters " "that have already been recorded in 2 filtermacro files where the parameter " "values are a mix of filtermacro from file1 and file2 related to progress. " "progress is specified by the total_steps and current_step parameters " "if current_step is 0.0 use the values as defined in filtermacro file1. " "the mix increases the influence of parameter values as definewd in filtermacro file2 " " the more current_step approaches total_steps." "Correlation is done by name of the filter and position in the filtermacro file1. " "filternames that are only present in filtermacro file2 are ignored. " "filternames that have no correlated matching filtername in filtermacro file2 " "are executed with values as defined in filtermacro file1, independent from current_step. " "This non-interactive API is typically used by the GAP storyboard processor for " "applying filtermacros with varying values. " "WARNING: filtermacro scriptfiles are a temporary solution. " "They are machine dependent. Support may be dropped in future gimp " "versions.", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, NULL, /* dont appear in menus */ "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, G_N_ELEMENTS (args_fmac_varying), nreturn_vals, args_fmac_varying, return_vals); } /* end query */ static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals) { static GimpParam values[1]; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; gint32 image_id; gint32 drawable_id; char *filtermacro_file1; char *filtermacro_file2; gdouble current_step; gint32 total_steps; gint32 l_rc; const char *l_env; *nreturn_vals = 1; *return_vals = values; l_rc = 0; l_env = g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } run_mode = param[0].data.d_int32; image_id = param[1].data.d_image; drawable_id = param[2].data.d_drawable; filtermacro_file1 = NULL; filtermacro_file2 = NULL; current_step = 0.0; total_steps = 1; INIT_I18N (); if(gap_debug) { fprintf(stderr, "\n\ngap_fmac_varying_main: debug name = %s\n", name); } if (strcmp (name, GAP_FMACNAME_PLUG_IN_NAME_FMAC_VARYING) == 0) { if (run_mode != GIMP_RUN_NONINTERACTIVE) { status = GIMP_PDB_CALLING_ERROR; l_rc = -1; } else { if(n_params == 7) { filtermacro_file1 = param[3].data.d_string; filtermacro_file2 = param[4].data.d_string; current_step = param[5].data.d_float; total_steps = param[6].data.d_int32; if((filtermacro_file1 == NULL) || (filtermacro_file2 == NULL)) { status = GIMP_PDB_CALLING_ERROR; } } else { status = GIMP_PDB_CALLING_ERROR; } if(status == GIMP_PDB_SUCCESS) { l_rc = gap_fmac_execute(run_mode, image_id, drawable_id , filtermacro_file1 , filtermacro_file2 , current_step , total_steps ); } } } else { status = GIMP_PDB_CALLING_ERROR; } if(l_rc < 0) { status = GIMP_PDB_EXECUTION_ERROR; } if (run_mode != GIMP_RUN_NONINTERACTIVE) { gimp_displays_flush(); } values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; } /* end run */ gimp-gap-2.6.0+dfsg.orig/gap/gap_story_vthumb.h0000644000175000017500000001114711212030253021265 0ustar thibautthibaut/* gap_story_vthumb.h * * This module handles GAP storyboard dialog video thumbnail (vthumb) * processing. * video thumbnails are thumbnails of relevant frames (typically * the first referenced framenumber in a video, section or anim image) */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.26a; 2007/10/06 hof: created */ #ifndef _GAP_STORY_VTHUMB_H #define _GAP_STORY_VTHUMB_H #include "libgimp/gimp.h" #include "gap_story_main.h" void gap_story_vthumb_debug_print_videolist(GapStoryVTResurceElem *video_list, GapVThumbElem *vthumb_list); void gap_story_vthumb_close_videofile(GapStbMainGlobalParams *sgpp); void gap_story_vthumb_open_videofile(GapStbMainGlobalParams *sgpp , const char *filename , gint32 seltrack , const char *preferred_decoder ); GapStoryVTResurceElem * gap_story_vthumb_get_velem_movie(GapStbMainGlobalParams *sgpp ,const char *video_filename ,gint32 seltrack ,const char *preferred_decoder ); GapStoryVTResurceElem * gap_story_vthumb_get_velem_no_movie(GapStbMainGlobalParams *sgpp ,GapStoryBoard *stb ,GapStoryElem *stb_elem ); guchar * gap_story_vthumb_create_generic_vthumb(GapStbMainGlobalParams *sgpp , GapStoryBoard *stb , GapStorySection *section , GapStoryElem *stb_elem , gint32 framenumber , gint32 *th_bpp , gint32 *th_width , gint32 *th_height , gboolean do_scale ); GapVThumbElem * gap_story_vthumb_add_vthumb(GapStbMainGlobalParams *sgpp ,gint32 framenr ,guchar *th_data ,gint32 th_width ,gint32 th_height ,gint32 th_bpp ,gint32 video_id ); GapVThumbElem * gap_story_vthumb_elem_fetch(GapStbMainGlobalParams *sgpp ,GapStoryBoard *stb ,GapStoryElem *stb_elem ,gint32 framenr ,gint32 seltrack ,const char *preferred_decoder ); guchar * gap_story_vthumb_fetch_thdata(GapStbMainGlobalParams *sgpp ,GapStoryBoard *stb ,GapStoryElem *stb_elem ,gint32 framenr ,gint32 seltrack ,const char *preferred_decoder , gint32 *th_bpp , gint32 *th_width , gint32 *th_height ); guchar * gap_story_vthumb_fetch_thdata_no_store(GapStbMainGlobalParams *sgpp ,GapStoryBoard *stb ,GapStoryElem *stb_elem ,gint32 framenr ,gint32 seltrack ,const char *preferred_decoder , gint32 *th_bpp , gint32 *th_width , gint32 *th_height , gboolean *file_read_flag , gint32 *video_id ); void gap_story_vthumb_g_main_context_iteration(GapStbMainGlobalParams *sgpp); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_onion_main.c0000644000175000017500000004266511212030253020652 0ustar thibautthibaut/* gap_onion_main.c * 2001.11.20 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module handles ONION Skin Layers in the GIMP Video Menu. * Onion Layer(s) usually do show previous (or next) frame(s) * of the video in the current frame. * * Video/OnionSkin/Configuration ... GUI to configure, create abd delete onionskin Layer(s) for framerange * Video/OnionSkin/Create or Replace ... create or replace onionskin Layer(s) and set visible. * Video/OnionSkin/Delete ... delete onionskin Layer(s) * Video/OnionSkin/Toggle Visibility ... show/hide onionskin layer(s) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 2.1.0a; 2004/06/03 hof: added onionskin ref_mode parameter * version 1.3.17a; 2003.07.29 hof: param types GimpPlugInInfo.run procedure * version 1.3.16c; 2003.07.12 hof: Onionsettings scope changes from gimp-session * to permanent per animation (stored in video_info file=. * version 1.3.16b; 2003.07.06 hof: new parameter asc_opacity (for cross-fading support) * version 1.3.14a; 2003.05.24 hof: integration into gimp-gap-1.3.14 * version 1.3.12a; 2003.05.03 hof: started port to gimp-1.3 / gtk+2.2 * version 1.2.2a; 2001.11.20 hof: created */ #include #include #include #include /* ------------------------ * global gap DEBUG switch * ------------------------ */ /* int gap_debug = 1; */ /* print debug infos */ /* int gap_debug = 0; */ /* 0: dont print debug infos */ int gap_debug = 0; GapOnionMainGlobalParams global_params; static void query(void); static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; static GimpParamDef args_onion_cfg[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (the current videoframe)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "num_olayers", "Number of Onion Layers"}, {GIMP_PDB_INT32, "ref_delta", "Reference Frame Delta: +- 1 ... n Default: -1 "}, {GIMP_PDB_INT32, "ref_cycle", "Reference is Cycle : TRUE/FALSE (TRUE .. last frame has frame 0 as next frame)"}, {GIMP_PDB_INT32, "stack_pos", "Place OnionLayer(s) on Stackposition 0..n Default: 1"}, {GIMP_PDB_INT32, "stack_top", "TRUE Stack Position is relative from TOP, FALSE relative to Bottom"}, {GIMP_PDB_FLOAT, "opacity", "OnionOpacity: 0.0..100.0%"}, {GIMP_PDB_FLOAT, "opacity_delta", "OnionOpacityDelta: 0..100% Default: 80"}, {GIMP_PDB_INT32, "ignore_botlayers", "Ignore N Bottom Sourcelayers (0 .. use full picture, 1 ignor bg layer) "}, {GIMP_PDB_INT32, "select_mode", "Mode how to identify a layer: 0-3 by layername 0=equal, 1=prefix, 2=suffix, 3=contains, 6=all visible (ignore select_string)"}, {GIMP_PDB_INT32, "select_case", "0: ignore case 1: select_string is case sensitive"}, {GIMP_PDB_INT32, "select_invert", "0: select normal 1: invert (select all unselected layers)"}, {GIMP_PDB_STRING, "select_string", "string to match with layername (how to match is defined by select_mode)"}, {GIMP_PDB_INT32, "range_from", "first affected frame (ignored if run is not 2 or 3)"}, {GIMP_PDB_INT32, "range_to", "last affected frame (ignored if run is not 2 or 3)"}, {GIMP_PDB_INT32, "run", "0 .. do nothing, 1..set params for this session, 2..set and create or replace onionlayers for selected framerange 3..delete onionlayers from selected famerange "}, {GIMP_PDB_INT32, "asc_opacity", "TRUE..farest neighbour frame has highest opacity, FALSE: nearest has highest opacity"}, {GIMP_PDB_INT32, "auto_create", "TRUE..automatic creation/replacing of onionskinlayers after GAP controlled load"}, {GIMP_PDB_INT32, "auto_delete", "TRUE..automatic delete of onionskinlayers before GAP controlled save"}, {GIMP_PDB_INT32, "ref_mode", "Reference Mode: 0:NORMAL, 1:BIDIRECTIONAL_SINGLE, 2:BIDIRECTIONAL_DOUBLE "}, }; static int nargs_onion_cfg = G_N_ELEMENTS(args_onion_cfg); static GimpParamDef args_onion_visi[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (the current videoframe)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, {GIMP_PDB_INT32, "visible_mode", "0: set invisible 1: set visible 2: toggle visibility"}, }; static int nargs_onion_visi = G_N_ELEMENTS(args_onion_visi); static GimpParamDef args_onion_std[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_IMAGE, "image", "Input image (the current videoframe)"}, {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"}, }; static int nargs_onion_std = G_N_ELEMENTS(args_onion_std); static GimpParamDef *return_vals = NULL; static int nreturn_vals = 0; /* ------------------------ * MAIN query and run * ------------------------ */ MAIN () static void query () { gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR); gimp_install_procedure(GAP_PLUGIN_NAME_ONION_CFG, "This plugin sets Configuration for Onion Layers in Videofames", "This plugin is the configuration GUI for Onion layers." " Onion Layer(s) usually do show previous and/ or next frame(s)" " of the video in the current frame, depending on ref_mode parameter" " Onion Layers are not created automatically. You have to create or delete them manually" " using the menu Video/OnionSkin/make or Video/OnionSkin/delete or call the Procedures " GAP_PLUGIN_NAME_ONION_APPLY " " GAP_PLUGIN_NAME_ONION_DEL " " " The configuration can be saved in the gimprc parameter file.", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Configuration..."), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_onion_cfg, nreturn_vals, args_onion_cfg, return_vals); gimp_install_procedure(GAP_PLUGIN_NAME_ONION_APPLY, "This plugin creates or replaces Onionskin Layer(s)", "This plugin creates or updates Onionskin Layers in the current Videoframe." " Onion Layer(s) usually do show previous (or next) frame(s)" " of the video. At 1.st call in the current frame." " This Plugin runs NONINTERACTIVE only. It depends on the configuration settings" " made by Video/Onionskin/Config or call of the plugin: " GAP_PLUGIN_NAME_ONION_CFG " " " if no configuration is found, default settings are used", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Create or Replace"), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_onion_std, nreturn_vals, args_onion_std, return_vals); gimp_install_procedure(GAP_PLUGIN_NAME_ONION_DEL, "This plugin removes OnionSkin Layer(s)", "This plugin removes Onion Skin Layers from the current Videoframe." " Onion Layer(s) usually do show previous (or next) frame(s)" " of the video.", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Delete"), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_onion_std, nreturn_vals, args_onion_std, return_vals); gimp_install_procedure(GAP_PLUGIN_NAME_ONION_VISI, "This plugin toggles visibility of OnionSkin Layer(s)", "This plugin sets visibility for all onionskin Layers in the current Videoframe.", "Wolfgang Hofer (hof@gimp.org)", "Wolfgang Hofer", GAP_VERSION_WITH_DATE, N_("Toggle Visibility"), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs_onion_visi, nreturn_vals, args_onion_visi, return_vals); { /* Menu names */ const char *menupath_image_video = N_("/Video/"); const char *menupath_image_video_onionskin = N_("/Video/Onionskin/"); //gimp_plugin_menu_branch_register("", "Video"); //gimp_plugin_menu_branch_register("/Video", "Onionskin"); gimp_plugin_menu_register (GAP_PLUGIN_NAME_ONION_CFG, menupath_image_video_onionskin); gimp_plugin_menu_register (GAP_PLUGIN_NAME_ONION_APPLY, menupath_image_video_onionskin); gimp_plugin_menu_register (GAP_PLUGIN_NAME_ONION_DEL, menupath_image_video_onionskin); gimp_plugin_menu_register (GAP_PLUGIN_NAME_ONION_VISI, menupath_image_video_onionskin); } } /* end query */ /* optional: include files with GUI and some worker procedures here * (so we can compile and install using gimptool without any makefile) */ #ifdef INCLUDE_ALL_C_FILES #include "gap_match.c" #include "gap_lib.c" #include "gap_onion_gui.c" #include "gap_onion_worker.c" #endif static void run(const gchar *name , gint n_params , const GimpParam *param , gint *nreturn_vals , GimpParam **return_vals) { GapOnionMainGlobalParams *gpp; static GimpParam values[1]; gint32 l_rc; gint32 l_lock_image_id; char *l_env; gpp = &global_params; *nreturn_vals = 1; *return_vals = values; l_rc = 0; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = GIMP_PDB_SUCCESS; l_env = (char*) g_getenv("GAP_DEBUG"); if(l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1; } if(gap_debug) fprintf(stderr, "\n\ngap_onion_main: debug name = %s\n", name); gpp->run_mode = param[0].data.d_int32; INIT_I18N(); gap_onion_dlg_init_default_values(gpp); /* init with default values */ /* get image_ID */ gpp->image_ID = param[1].data.d_image; l_lock_image_id = gpp->image_ID; /* --------------------------- * check for LOCKS * --------------------------- */ if(gap_lock_check_for_lock(l_lock_image_id, gpp->run_mode)) { values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; return ; } /* set LOCK on current image (for all gap_plugins) */ gap_lock_set_lock(l_lock_image_id); /* get animinfo */ gap_onion_worker_plug_in_gap_get_animinfo(gpp->image_ID, &gpp->ainfo); gap_onion_worker_get_data_onion_cfg(gpp); /* get current params (if there are any) */ gpp->vin.onionskin_auto_enable = TRUE; gpp->cache.count = 0; /* start with empty image cache */ gpp->image_ID = param[1].data.d_image; gpp->range_from = gpp->ainfo.curr_frame_nr; gpp->range_to = gpp->ainfo.last_frame_nr; if (strcmp (name, GAP_PLUGIN_NAME_ONION_CFG) == 0) { /* ----------------------- * CONFIG * ----------------------- */ if (gpp->run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_onion_cfg) { values[0].data.d_status = GIMP_PDB_CALLING_ERROR; } else { gpp->vin.num_olayers = param[3].data.d_int32; gpp->vin.ref_delta = param[4].data.d_int32; gpp->vin.ref_cycle = param[5].data.d_int32; gpp->vin.stack_pos = param[6].data.d_int32; gpp->vin.stack_top = param[7].data.d_int32; gpp->vin.opacity = param[8].data.d_float; gpp->vin.opacity_delta = param[9].data.d_float; gpp->vin.ignore_botlayers = param[10].data.d_int32; gpp->vin.select_mode = param[11].data.d_int32; gpp->vin.select_case = param[12].data.d_int32; gpp->vin.select_invert = param[13].data.d_int32; if (param[14].data.d_string != NULL) { g_snprintf(&gpp->vin.select_string[0] , sizeof(gpp->vin.select_string) , "%s", param[14].data.d_string ); } gpp->range_from = param[15].data.d_int32; gpp->range_to = param[16].data.d_int32; gpp->run = param[17].data.d_int32; gpp->vin.asc_opacity = param[18].data.d_int32; gpp->vin.auto_replace_after_load = param[19].data.d_int32; gpp->vin.auto_delete_before_save = param[20].data.d_int32; gpp->vin.onionskin_auto_enable = TRUE; gpp->vin.ref_mode = param[21].data.d_int32; } } else if(gpp->run_mode != GIMP_RUN_INTERACTIVE) { values[0].data.d_status = GIMP_PDB_CALLING_ERROR; } if (values[0].data.d_status == GIMP_PDB_SUCCESS) { if(gpp->run_mode == GIMP_RUN_INTERACTIVE) { l_rc = gap_onion_dlg_onion_cfg_dialog (gpp); if(gap_debug) printf("MAIN after gap_onion_dlg_onion_cfg_dialog ------------------\n"); } if (l_rc >= 0) { if(gpp->run != GAP_ONION_RUN_CANCEL) { /* disable both automatic onionskin triggers by disabling * the master switch * while applying onionskin to a range of frames. * (this prevents from creating onionskins twice per image. * automatic delete is also not done in that case because it makes no * sense when the user explicitly wants to create onionskin layers * in the processed range) */ gpp->vin.onionskin_auto_enable = FALSE; l_rc = gap_onion_worker_set_data_onion_cfg(gpp, GAP_PLUGIN_NAME_ONION_CFG); } if((gpp->run == GAP_ONION_RUN_APPLY) || (gpp->run == GAP_ONION_RUN_DELETE)) { /* do ONIONSKIN processing for all the frames in selected Range */ l_rc = gap_onion_worker_onion_range(gpp); gpp->vin.onionskin_auto_enable = TRUE; l_rc = gap_onion_worker_set_data_onion_cfg(gpp, GAP_PLUGIN_NAME_ONION_CFG); } } } } else if (strcmp (name, GAP_PLUGIN_NAME_ONION_APPLY) == 0) { /* ----------------------- * MAKE * ----------------------- * store params also with name GAP_PLUGIN_NAME_ONION_APPLY * This makes it possible, to call this plugin as filter * for a selected range of frames. * (using plug_in_gap_modify and selecting plug_in_onionskin_make as filter) */ gap_onion_worker_set_data_onion_cfg(gpp, GAP_PLUGIN_NAME_ONION_APPLY); l_rc = gap_onion_worker_onion_apply(gpp, FALSE /* do not use_cache */ ); } else if (strcmp (name, GAP_PLUGIN_NAME_ONION_DEL) == 0) { /* ----------------------- * DEL * ----------------------- */ gap_onion_worker_set_data_onion_cfg(gpp, GAP_PLUGIN_NAME_ONION_DEL); l_rc = gap_onion_worker_onion_delete(gpp); } else if (strcmp (name, GAP_PLUGIN_NAME_ONION_VISI) == 0) { /* ----------------------- * VISI * ----------------------- */ gint32 l_visi_mode; l_visi_mode = GAP_ONION_VISI_TOGGLE; /* interactive mode always uses toggle */ if (gpp->run_mode == GIMP_RUN_NONINTERACTIVE) { if (n_params != nargs_onion_visi) { values[0].data.d_status = GIMP_PDB_CALLING_ERROR; } else { l_visi_mode = param[3].data.d_int32; } } if (values[0].data.d_status == GIMP_PDB_SUCCESS) { gap_onion_worker_set_data_onion_cfg(gpp, GAP_PLUGIN_NAME_ONION_VISI); l_rc = gap_onion_worker_onion_visibility(gpp, l_visi_mode); } } else { values[0].data.d_status = GIMP_PDB_CALLING_ERROR; } if(l_rc < 0) { values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; } if (gpp->run_mode != GIMP_RUN_NONINTERACTIVE) { gimp_displays_flush(); } /* remove LOCK on this image for all gap_plugins */ gap_lock_remove_lock(l_lock_image_id); } /* end run */ gimp-gap-2.6.0+dfsg.orig/gap/gap_onion_base.c0000644000175000017500000005352111212030253020631 0ustar thibautthibaut/* gap_onion_base.c procedures * 2003.05.22 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains GAP Onionskin Worker Procedures */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 2.1.0a; 2004/06/03 hof: added onionskin ref_mode * version 1.3.16c; 2003.07.08 hof: created (as extract of the gap_onion_worker.c module) */ #include "config.h" /* SYTEM (UNIX) includes */ #include #include #include #include #include #include #include #include #include #include "gap_libgapbase.h" #include #include #include #include #include extern int gap_debug; /* ============================================================================ * gap_onion_base_mark_as_onionlayer * set onion layer parasite (store timestamp and tattoo) * tattoos are unique identifiers within an image * and remain unique over sessions -- if saved in xcf format. * ============================================================================ */ void gap_onion_base_mark_as_onionlayer(gint32 layer_id) { GapOnionBaseParasite_data *l_parasite_data; GimpParasite *l_parasite; if(gap_debug) printf("gap_onion_base_mark_as_onionlayer: START\n"); l_parasite_data = g_malloc(sizeof(GapOnionBaseParasite_data)); l_parasite_data->timestamp = gap_base_get_current_time(); l_parasite_data->tattoo = gimp_drawable_get_tattoo(layer_id); if(gap_debug) printf("gap_onion_base_mark_as_onionlayer: tattoo is: %d\n", (int)l_parasite_data->tattoo); l_parasite = gimp_parasite_new(GAP_ONION_PARASITE_NAME, GIMP_PARASITE_PERSISTENT, sizeof(GapOnionBaseParasite_data), l_parasite_data); if(l_parasite) { gimp_drawable_parasite_attach(layer_id, l_parasite); gimp_parasite_free(l_parasite); } } /* end gap_onion_base_mark_as_onionlayer */ /* ============================================================================ * gap_onion_base_check_is_onion_layer * check for onion layer parasite and tattoo. * (if the user made a copy of an onion layer, the copy has an onionparasite * but the originals parasitedata.tattoo will not match with the layers tattoo. * therefore the copy is not identified as onion layer.) * returns TRUE if layer is an original onion layer. * ============================================================================ */ gint32 gap_onion_base_check_is_onion_layer(gint32 layer_id) { gint l_found; GapOnionBaseParasite_data *l_parasite_data; GimpParasite *l_parasite; if(gap_debug) printf("gap_onion_base_check_is_onion_layer: START layer_id %d\n", (int)layer_id); l_found = FALSE; l_parasite = gimp_drawable_parasite_find(layer_id, GAP_ONION_PARASITE_NAME); if (l_parasite) { l_parasite_data = (GapOnionBaseParasite_data *)l_parasite->data; if(gap_debug) printf("gap_onion_base_check_is_onion_layer: tattoo is: %d\n", (int)l_parasite_data->tattoo); if (l_parasite_data->tattoo == gimp_drawable_get_tattoo(layer_id)) { l_found = TRUE; if(gap_debug) printf("gap_onion_base_check_is_onion_layer: ONION_LAYER_FOUND layer_id %d\n", (int)layer_id); } gimp_parasite_free(l_parasite); } return l_found; } /* end gap_onion_base_check_is_onion_layer */ /* ============================================================================ * gap_onion_base_onionskin_visibility * set visibility of all onion layer(s) in the current image. * ============================================================================ */ gint gap_onion_base_onionskin_visibility(gint32 image_id, gint visi_mode) { #define VISIBILTY_UNSET -4444 gint32 *l_layers_list; gint l_nlayers; gint l_idx; gint l_is_onion; gint l_visible; gint32 l_layer_id; if(gap_debug) { printf("gap_onion_base_onionskin_visibility: START visi_mode: %d\n", (int)visi_mode); printf(" image_ID: %d\n", (int)image_id); } l_visible = VISIBILTY_UNSET; if(visi_mode == GAP_ONION_VISI_TRUE) { l_visible = TRUE; } if(visi_mode == GAP_ONION_VISI_FALSE) { l_visible = TRUE; } l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list) { for(l_idx=0;l_idx < l_nlayers;l_idx++) { l_layer_id = l_layers_list[l_idx]; l_is_onion = gap_onion_base_check_is_onion_layer(l_layer_id); if(l_is_onion) { if (l_visible == VISIBILTY_UNSET) { l_visible = !gimp_drawable_get_visible(l_layer_id); } /* set visibility */ if(gap_debug) printf("layer_id %d visibility: %d\n", (int)l_layer_id ,(int)l_visible); gimp_drawable_set_visible(l_layer_id, l_visible); } } g_free(l_layers_list); } return 0; } /* end gap_onion_base_onionskin_visibility */ /* ============================================================================ * gap_onion_base_onionskin_delete * remove onion layer(s) from the current image. * ============================================================================ */ gint gap_onion_base_onionskin_delete(gint32 image_id) { gint32 *l_layers_list; gint l_nlayers; gint l_idx; gint l_is_onion; if(gap_debug) { printf("gap_onion_base_onionskin_delete: START\n"); printf(" image_ID: %d\n", (int)image_id); } l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(gap_debug) printf("gap_onion_base_onionskin_delete: l_nlayers = %d\n", (int)l_nlayers); if(l_layers_list) { for(l_idx=0;l_idx < l_nlayers;l_idx++) { if(gap_debug) printf("gap_onion_base_onionskin_delete: l_idx = %d\n", (int)l_idx); l_is_onion = gap_onion_base_check_is_onion_layer(l_layers_list[l_idx]); if(l_is_onion) { /* remove onion layer from source */ gimp_image_remove_layer(image_id, l_layers_list[l_idx]); } } g_free(l_layers_list); } if(gap_debug) printf("gap_onion_base_onionskin_delete: END\n"); return 0; } /* end gap_onion_base_onionskin_delete */ /* ============================================================================ * gap_onion_base_onionskin_apply * create or replace onion layer(s) in the current image. * Onion layers do show one (or more) merged copies of previos (or next) * videoframe(s). * This procedure first removes onion layers (if there are any) * then reads the other videoframes, merges them (according to config params) * and imports the merged layer(s) as onion layer(s). * Onion Layers are marked by tattoo and parasite * use_chache TRUE: * check if desired frame is already in the image cache we can skip loading * if the cached image is already merged we can simply copy the layer. * Further we update the cache with merged layer. * use_cache is for processing multiple frames (speeds up remarkable) * use_cache FALSE: * always load frames and perform merge, * but we can steal layer from the tmp_image. * (faster than copy when processing a single frame only) * * The functionpointers * fptr_add_img_to_cache * fptr_find_frame_in_img_cache * * are used for caching the handled images. * this is useful when onionskin layers are created for more than one frame * at once. for processing single frames it is OK to pass NULL pointers. * * returns value >= 0 if all is ok * (or -1 on error) * ============================================================================ */ gint gap_onion_base_onionskin_apply(gpointer gpp , gint32 image_id , GapVinVideoInfo *vin_ptr , long ainfo_curr_frame_nr , long ainfo_first_frame_nr , long ainfo_last_frame_nr , char *ainfo_basename , char *ainfo_extension , GapOnionBaseFptrAddImageToCache fptr_add_img_to_cache , GapOnionBaseFptrFindFrameInImageCache fptr_find_frame_in_img_cache , gboolean use_cache) { gint32 l_nr; gint32 l_sign; gint32 l_onr; gint32 l_ign; gint32 l_idx; gint32 l_frame_nr; gint32 l_tmp_image_id; gint32 l_is_onion; gint32 l_layerstack; char *l_new_filename; char *l_name; gint32 l_layer_id; gint32 l_new_layer_id; gint32 *l_layers_list; gint l_nlayers; gdouble l_opacity; char *l_layername; gint32 l_active_layer; if(gap_debug) { printf("gap_onion_base_onionskin_apply: START\n"); printf(" num_olayers: %d\n", (int)vin_ptr->num_olayers); printf(" ref_mode: %d\n", (int)vin_ptr->ref_mode); printf(" ref_delta: %d\n", (int)vin_ptr->ref_delta); printf(" ref_cycle: %d\n", (int)vin_ptr->ref_cycle); printf(" stack_pos: %d\n", (int)vin_ptr->stack_pos); printf(" stack_top: %d\n", (int)vin_ptr->stack_top); printf(" opacity: %f\n", (float)vin_ptr->opacity); printf(" opacity_delta: %f\n", (float)vin_ptr->opacity_delta); printf(" ignore_botlayers: %d\n", (int)vin_ptr->ignore_botlayers); printf(" image_ID: %d\n", (int)image_id); printf(" use_cache: %d\n", (int)use_cache); printf(" asc_opacity: %d\n", (int)vin_ptr->asc_opacity); printf(" ainfo_curr_frame_nr: %d\n", (int)ainfo_curr_frame_nr); printf(" ainfo_first_frame_nr: %d\n", (int)ainfo_first_frame_nr); printf(" ainfo_last_frame_nr: %d\n", (int)ainfo_last_frame_nr); printf(" ainfo_basename: %s\n", ainfo_basename); printf(" ainfo_extension: %s\n", ainfo_extension); } /* keep information about the active_layer * (needed for restore after onionskin layers were recreated) */ l_active_layer = gimp_image_get_active_layer(image_id); if(l_active_layer >= 0) { if(gap_onion_base_check_is_onion_layer(l_active_layer)) { /* no need to remember the active layer, because * it is an onionskin layer that will be deleted * before recreation */ l_active_layer = -1; } } /* delete onion layers (if there are old ones) */ gap_onion_base_onionskin_delete(image_id); l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(vin_ptr->stack_top) { l_layerstack = CLAMP(vin_ptr->stack_pos, 0, l_nlayers); } else { l_layerstack = CLAMP((l_nlayers - vin_ptr->stack_pos),0 ,l_nlayers); } if(l_layers_list) { g_free(l_layers_list); l_layers_list = NULL;} /* create new onion layer(s) */ l_opacity = vin_ptr->opacity; l_new_filename = NULL; l_frame_nr = ainfo_curr_frame_nr; l_sign = -1; for(l_onr=1; l_onr <= vin_ptr->num_olayers; l_onr++) { /* find out reference frame number */ if(vin_ptr->asc_opacity) { /* process far neigbours first to give them the highest configured opacity value */ l_nr = (1+ vin_ptr->num_olayers) - l_onr; } else { /* process near neigbours first to give them the highest configured opacity value */ l_nr = l_onr; } /* find out reference frame number */ switch(vin_ptr->ref_mode) { case GAP_ONION_REFMODE_BIDRIECTIONAL_SINGLE: l_sign *= -1; /* toggle sign between -1 and +1 */ break; case GAP_ONION_REFMODE_BIDRIECTIONAL_DOUBLE: l_sign *= -1; /* toggle sign between -1 and +1 */ l_nr = 1 + ((l_nr -1) / 2); break; case GAP_ONION_REFMODE_NORMAL: l_sign = 1; /* normal mode: always force sign of +1 */ default: break; } l_frame_nr = ainfo_curr_frame_nr + (l_sign * (vin_ptr->ref_delta * l_nr)); if(!vin_ptr->ref_cycle) { if((l_frame_nr < ainfo_first_frame_nr) || (l_frame_nr > ainfo_last_frame_nr)) { break; /* fold back cycle turned off */ } } if (l_frame_nr < ainfo_first_frame_nr) { l_frame_nr = ainfo_last_frame_nr +1 - (ainfo_first_frame_nr - l_frame_nr); if (l_frame_nr < ainfo_first_frame_nr) { break; /* stop on multiple fold back cycle */ } } if (l_frame_nr > ainfo_last_frame_nr) { l_frame_nr = ainfo_first_frame_nr -1 + (l_frame_nr - ainfo_last_frame_nr); if (l_frame_nr > ainfo_last_frame_nr) { break; /* stop on multiple fold back cycle */ } } l_tmp_image_id = -1; l_layer_id = -1; if(use_cache) { if(fptr_find_frame_in_img_cache != NULL) { (*fptr_find_frame_in_img_cache)(gpp, l_frame_nr, &l_tmp_image_id, &l_layer_id); } if (l_tmp_image_id == image_id) { /* never use the same image as source and destination, * if references point to same image, always force * loading a 2.nd copy for the merge */ l_tmp_image_id = -1; } } if(l_tmp_image_id < 0) { /* frame is not available in the cache */ if(gap_debug) printf("gap_onion_base_onionskin_apply: frame is NOT available in the CACHE\n"); /* build the frame name */ if(l_new_filename != NULL) g_free(l_new_filename); l_new_filename = gap_lib_alloc_fname(ainfo_basename, l_frame_nr, ainfo_extension); /* load referenced frame */ l_tmp_image_id = gap_lib_load_image(l_new_filename); if(l_tmp_image_id < 0) return -1; /* dont waste time and memory for undo in noninteracive processing * of the src frames */ /*gimp_image_undo_enable(l_tmp_image_id);*/ /* clear undo stack */ /* no more gimp_image_undo_enable, causes warnings since gimp-2.1.6 */ /* Gimp-Core-CRITICAL **: file gimpimage.c: line 1708 (gimp_image_undo_thaw): assertion `gimage->undo_freeze_count > 0' failed */ gimp_image_undo_disable(l_tmp_image_id); /* NO Undo */ } else { if(gap_debug) printf("gap_onion_base_onionskin_apply: frame is AVAILABLE in the CACHE l_tmp_image_id: %d\n", (int)l_tmp_image_id); } if(l_layer_id < 0) { /* there was no merged layer in the cache, so we must * merge layers now */ if(gap_debug) printf("gap_onion_base_onionskin_apply: layer is NOT available in the CACHE\n"); /* set some layers invisible * a) ignored bottomlayer(s) * b) select_mode dependent: layers where layername does not match select-string * c) all onion layers */ l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers); for(l_ign=0, l_idx=l_nlayers -1; l_idx >= 0;l_idx--) { l_layer_id = l_layers_list[l_idx]; l_layername = gimp_drawable_get_name(l_layer_id); l_is_onion = gap_onion_base_check_is_onion_layer(l_layer_id); if((l_ign < vin_ptr->ignore_botlayers) || (FALSE == gap_match_layer( l_idx , l_layername , &vin_ptr->select_string[0] , vin_ptr->select_mode , vin_ptr->select_case , vin_ptr->select_invert , l_nlayers , l_layer_id) ) || (l_is_onion)) { gimp_drawable_set_visible(l_layer_id, FALSE); } g_free (l_layername); if(!l_is_onion) { /* exclude other onion layers from counting ignored layers */ l_ign++; } } /* merge visible layers (clip at image size) */ l_layer_id = gap_image_merge_visible_layers(l_tmp_image_id, GIMP_CLIP_TO_IMAGE); } else { if(gap_debug) printf("gap_onion_base_onionskin_apply: layer is AVAILABLE in the CACHE l_layer_id: %d\n", (int)l_layer_id); } /* COPY or MOVE the resulting merged layer to current image image_id */ if(use_cache) { /* when using image cache we must copy the merged layer * but first update the cache, so we can reuse the merged layer * when processing the next frame */ if(fptr_add_img_to_cache != NULL) { (*fptr_add_img_to_cache)(gpp, l_frame_nr, l_tmp_image_id, l_layer_id); } } if(l_layer_id >= 0) { gint l_src_offset_x; /* layeroffsets as they were in src_image */ gint l_src_offset_y; /* copy the layer to dest image image_id */ l_new_layer_id = gap_layer_copy_to_dest_image (image_id ,l_layer_id ,CLAMP(l_opacity, 0.0, 100.0) ,0 /* NORMAL GimpLayerModeEffects */ ,&l_src_offset_x ,&l_src_offset_y ); if(! gimp_drawable_has_alpha(l_new_layer_id)) { /* have to add alpha channel */ gimp_layer_add_alpha(l_new_layer_id); } if(gap_debug) printf("ONL:gap_onion_base_onionskin_apply l_onr:%d, framenr:%d, layerstack:%d opacity:%f\n" , (int)l_onr , (int)l_frame_nr , (int)l_layerstack , (float)l_opacity ); /* add the layer to current frame at desired stackposition */ gimp_image_add_layer (image_id, l_new_layer_id, l_layerstack); gimp_layer_set_offsets(l_new_layer_id, l_src_offset_x, l_src_offset_y); /* set layername */ l_name = g_strdup_printf(_("onionskin_%06d"), (int) l_frame_nr); gimp_drawable_set_name(l_new_layer_id, l_name); g_free(l_name); /* Set parasite or tattoo */ gap_onion_base_mark_as_onionlayer(l_new_layer_id); /* gimp_layer_set_opacity(l_new_layer_id, l_opacity); */ } if(l_layers_list != NULL) { g_free (l_layers_list); l_layers_list = NULL;} if(!use_cache) { /* destroy the tmp image */ gap_image_delete_immediate(l_tmp_image_id); } /* opacitiy for next onion layer (reduced by delta percentage) */ l_opacity = CLAMP((l_opacity * vin_ptr->opacity_delta / 100.0), 0.0 , 100.0); /* stackposition for next onion layer */ l_layerstack++; if(l_new_filename) { g_free(l_new_filename); l_new_filename = NULL; }; } if(l_active_layer >= 0) { gimp_image_set_active_layer(image_id, l_active_layer); } if(gap_debug) printf("gap_onion_base_onionskin_apply: END\n\n"); return 0; } /* end gap_onion_base_onionskin_apply */ /* ---------------------------------- * gap_onion_image_has_oinonlayers * ---------------------------------- * check if image has onionskin layers * IN: only_visible TRUE check only for visible onionskin layers * FALSE check for all onionskin layers */ gboolean gap_onion_image_has_oinonlayers(gint32 image_id, gboolean only_visible) { gint32 *l_layers_list; gint l_nlayers; gint l_idx; gint l_is_onion; gint32 l_layer_id; gboolean l_has_onion; if(gap_debug) { printf("gap_onion_image_has_oinonlayers: START only_visible: %d image_id: %d\n" , (int)only_visible , (int)image_id ); } l_has_onion = FALSE; l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list) { for(l_idx=0;l_idx < l_nlayers;l_idx++) { l_layer_id = l_layers_list[l_idx]; l_is_onion = gap_onion_base_check_is_onion_layer(l_layer_id); if(l_is_onion) { if (only_visible) { if(gimp_drawable_get_visible(l_layer_id)) { l_has_onion = TRUE; break; } } else { l_has_onion = TRUE; break; } } } g_free(l_layers_list); } return (l_has_onion); } /* end gap_onion_image_has_oinonlayers */ /* --------------------------------- * gap_onion_base_image_duplicate * --------------------------------- * duplicate the image * and mark onionskin layers in the copy */ gint32 gap_onion_base_image_duplicate(gint32 image_id) { gint32 dup_image_id; dup_image_id = gimp_image_duplicate(image_id); if(dup_image_id >= 0) { gint32 *l_layers_list; gint32 *l_dup_layers_list; gint l_nlayers; gint l_dup_nlayers; gint l_idx; gint l_is_onion; gint32 l_layer_id; gboolean l_has_onion; l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); l_dup_layers_list = gimp_image_get_layers(dup_image_id, &l_dup_nlayers); if((l_layers_list) && (l_dup_layers_list)) { for(l_idx=0;l_idx < MIN(l_nlayers, l_dup_nlayers);l_idx++) { l_layer_id = l_layers_list[l_idx]; l_is_onion = gap_onion_base_check_is_onion_layer(l_layer_id); if(l_is_onion) { gap_onion_base_mark_as_onionlayer(l_dup_layers_list[l_idx]); } } g_free(l_layers_list); g_free(l_dup_layers_list); } } return(dup_image_id); } /* end gap_onion_base_image_duplicate */ gimp-gap-2.6.0+dfsg.orig/gap/gap_decode_xanim.h0000644000175000017500000000256711212030253021145 0ustar thibautthibaut/* gap_decode_xanim.h * 1999.11.22 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * Call xanim exporting edition (the loki version) * via shellscript gap_xanim_export.sh * To split any xanim supported video into * video frames (single images on disk) * Audio Tracks can also be extracted. * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 1.1.11b; 1999/11/22 hof: first release */ #ifndef _GAP_XANIM_H #define _GAP_XANIM_H #include "libgimp/gimp.h" int gap_xanim_decode(GimpRunMode run_mode ); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_mod_layer.c0000644000175000017500000015533611212030253020477 0ustar thibautthibaut/* gap_mod_layer.c * 1998.10.14 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * modify Layer (perform actions (like raise, set visible, apply filter) * - foreach selected layer * - in each frame of the selected framerange) * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 2.1.0b; 2004/10/17 hof: bugfix Function: Add layermask from selection * optim: direct processing for the current image * gimp 2.1.0b; 2004/08/11 hof: new action_modes "Copy layermask from layer above/below" * gimp 1.3.25a; 2004/01/21 hof: message text fixes (# 132030) * gimp 1.3.24a; 2004/01/17 hof: added Layermask Handling * gimp 1.3.20d; 2003/09/20 hof: sourcecode cleanup, * added new Actionmodes for Selction handling * gimp 1.3.20b; 2003/09/20 hof: gap_db_browser_dialog new param image_id * gimp 1.3.15a; 2003/06/21 hof: textspacing * gimp 1.3.14a; 2003/05/17 hof: placed OK button right. * gimp 1.3.12a; 2003/05/01 hof: merge into CVS-gimp-gap project * gimp 1.3.11a; 2003/01/18 hof: Conditional framesave * gimp 1.3.8a; 2002/09/21 hof: gap_lastvaldesc * gimp 1.3.4b; 2002/03/24 hof: support COMMON_ITERATOR * gimp 1.3.4a; 2002/03/12 hof: replaced private pdb-wrappers * gimp 1.1.29b; 2000/11/30 hof: use g_snprintf * gimp 1.1.28a; 2000/11/05 hof: check for GIMP_PDB_SUCCESS (not for FALSE) * gimp 1.1.6; 1999/06/21 hof: bugix: wrong iterator total_steps and direction * gimp 1.1.15.1; 1999/05/08 hof: bugix (dont mix GimpImageType with GimpImageBaseType) * version 0.98.00 1998.11.27 hof: - use new module gap_pdb_calls.h * version 0.97.00 1998.10.19 hof: - created module */ /* SYTEM (UNIX) includes */ #include #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "config.h" #include "gap-intl.h" #include "libgimp/gimp.h" /* GAP includes */ #include "gap_lastvaldesc.h" #include "gap_arr_dialog.h" #include "gap_filter.h" #include "gap_filter_pdb.h" #include "gap_dbbrowser_utils.h" #include "gap_pdb_calls.h" #include "gap_match.h" #include "gap_lib.h" #include "gap_layer_copy.h" #include "gap_image.h" #include "gap_range_ops.h" #include "gap_mod_layer.h" #include "gap_mod_layer_dialog.h" extern int gap_debug; /* ==0 ... dont print debug infos */ #define GAP_DB_BROWSER_MODFRAMES_HELP_ID "gap-modframes-db-browser" /* ============================================================================ * p_pitstop_dialog * return -1 on CANCEL * 0 on Continue (OK) * ============================================================================ */ static gint p_pitstop_dialog(gint text_flag, char *filter_procname) { const gchar *l_env; gchar *l_msg; static GapArrButtonArg l_but_argv[2]; gint l_but_argc; gint l_argc; static GapArrArg l_argv[1]; gint l_continue; l_but_argv[0].but_txt = _("Continue"); l_but_argv[0].but_val = 0; l_but_argv[1].but_txt = GTK_STOCK_CANCEL; l_but_argv[1].but_val = -1; l_but_argc = 2; l_argc = 0; /* optional dialog between both calls (to see the effect of 1.call) */ l_env = g_getenv("GAP_FILTER_PITSTOP"); if(l_env != NULL) { if((*l_env == 'N') || (*l_env == 'n')) { return 0; /* continue without question */ } } if(text_flag == 0) { l_msg = g_strdup_printf (_("2nd call of %s\n(define end-settings)"), filter_procname); } else { l_msg = g_strdup_printf ( _("Non-Interactive call of %s\n(for all selected layers)"), filter_procname); } l_continue = gap_arr_std_dialog ( _("Animated Filter Apply"), l_msg, l_argc, l_argv, l_but_argc, l_but_argv, 0); g_free (l_msg); return (l_continue); } /* end p_pitstop_dialog */ /* --------------------------------- * p_get_nb_layer_id * --------------------------------- * get layer_id of the neigbour layer /above or below) * the specified ref_layer * with the nb_ref parameter of -1 the neigbour layer one above is picked * , +1 selects the neigbour one below * return -1 if there is no such a neigbourlayer */ gint32 p_get_nb_layer_id(gint32 image_id, gint32 ref_layer_id, gint32 nb_ref) { gint l_nlayers; gint32 *l_layers_list; gint32 l_nb_layer_id; gint32 l_idx; gint32 l_nb_idx; l_nb_layer_id = -1; l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list != NULL) { for(l_idx = 0; l_idx < l_nlayers; l_idx++) { if(l_layers_list[l_idx] == ref_layer_id) { l_nb_idx = l_idx + nb_ref; if((l_nb_idx >= 0) && (l_nb_idx < l_nlayers)) { l_nb_layer_id = l_layers_list[l_nb_idx]; } break; } } g_free (l_layers_list); } return (l_nb_layer_id); } /* end p_get_nb_layer_id */ /* ============================================================================ * gap_mod_get_1st_selected * return index of the 1.st selected layer * or -1 if no selection was found * ============================================================================ */ int gap_mod_get_1st_selected (GapModLayliElem * layli_ptr, gint nlayers) { int l_idx; for(l_idx = 0; l_idx < nlayers; l_idx++) { if(layli_ptr[l_idx].selected != FALSE) { return (l_idx); } } return(-1); } /* end gap_mod_get_1st_selected */ /* ============================================================================ * gap_mod_alloc_layli * returns pointer to a new allocated image_id of the new created multilayer image * (or NULL on error) * ============================================================================ */ GapModLayliElem * gap_mod_alloc_layli(gint32 image_id, gint32 *l_sel_cnt, gint *nlayers, gint32 sel_mode, gint32 sel_case, gint32 sel_invert, char *sel_pattern ) { gint32 *l_layers_list; gint32 l_layer_id; gint32 l_idx; GapModLayliElem *l_layli_ptr; char *l_layername; *l_sel_cnt = 0; l_layers_list = gimp_image_get_layers(image_id, nlayers); if(l_layers_list == NULL) { return(NULL); } l_layli_ptr = g_new0(GapModLayliElem, (*nlayers)); if(l_layli_ptr == NULL) { g_free (l_layers_list); return(NULL); } for(l_idx = 0; l_idx < (*nlayers); l_idx++) { l_layer_id = l_layers_list[l_idx]; l_layername = gimp_drawable_get_name(l_layer_id); l_layli_ptr[l_idx].layer_id = l_layer_id; l_layli_ptr[l_idx].visible = gimp_drawable_get_visible(l_layer_id); l_layli_ptr[l_idx].selected = gap_match_layer(l_idx, l_layername, sel_pattern, sel_mode, sel_case, sel_invert, *nlayers, l_layer_id); if(l_layli_ptr[l_idx].selected != FALSE) { (*l_sel_cnt)++; /* count all selected layers */ } if(gap_debug) printf("gap: gap_mod_alloc_layli [%d] id:%d, sel:%d name:%s:\n", (int)l_idx, (int)l_layer_id, (int)l_layli_ptr[l_idx].selected, l_layername); g_free (l_layername); } g_free (l_layers_list); return( l_layli_ptr ); } /* end gap_mod_alloc_layli */ /* ============================================================================ * p_raise_layer * raise layer (check if possible before) * (without the check each failed attempt would open an inf window) * ============================================================================ */ static void p_raise_layer (gint32 image_id, gint32 layer_id, GapModLayliElem * layli_ptr, gint nlayers) { if(layli_ptr[0].layer_id == layer_id) return; /* is already on top */ if(! gimp_drawable_has_alpha (layer_id)) { /* implicite add an alpha channel before we try to raise */ gimp_layer_add_alpha(layer_id); } gimp_image_raise_layer(image_id, layer_id); } /* end p_raise_layer */ static void p_lower_layer (gint32 image_id, gint32 layer_id, GapModLayliElem * layli_ptr, gint nlayers) { if(layli_ptr[nlayers-1].layer_id == layer_id) return; /* is already on bottom */ if(! gimp_drawable_has_alpha (layer_id)) { /* implicite add an alpha channel before we try to lower */ gimp_layer_add_alpha(layer_id); } if(nlayers > 1) { if((layli_ptr[nlayers-2].layer_id == layer_id) && (! gimp_drawable_has_alpha (layli_ptr[nlayers-1].layer_id))) { /* the layer is one step above a "bottom-layer without alpha" */ /* implicite add an alpha channel before we try to lower */ gimp_layer_add_alpha(layli_ptr[nlayers-1].layer_id); } } gimp_image_lower_layer(image_id, layer_id); } /* end p_lower_layer */ /* ============================================================================ * p_selection_combine * * combine selections * ============================================================================ */ static void p_selection_combine(gint32 image_id ,gint32 master_channel_id ,GimpChannelOps operation ) { gint32 l_new_channel_id; gint32 l_sel_channel_id; l_sel_channel_id = gimp_image_get_selection(image_id); l_new_channel_id = gimp_channel_copy(l_sel_channel_id); /* copy the initial selection master_channel_id * to the newly create image */ gap_layer_copy_content( l_new_channel_id /* dst_drawable_id */ , master_channel_id /* src_drawable_id */ ); gimp_channel_combine_masks(l_sel_channel_id ,l_new_channel_id ,operation , 0 , 0 ); gimp_drawable_delete(l_new_channel_id); } /* end p_selection_combine */ /* --------------------------------- * p_apply_selection_action * --------------------------------- * check/perform action that modify the images selection channel. * NOTE: actions where the master_channel_id is required * are NOT performed if the image_id is equal to master_image_id * To perform the action on the master image pass -1 as master_image_id. * (this shall be done deferred after processing all the other frame images) * * return TRUE if action was handled * (this is also TRUE if the action was skiped due to the condition * image_id == master_image_id) * return FALSE for all other actions */ static gboolean p_apply_selection_action(gint32 image_id, gint32 action_mode , gint32 master_image_id, gint32 master_channel_id) { if(action_mode == GAP_MOD_ACM_SEL_REPLACE) { /* check if we are processing the master image * (must not replace selection by itself) */ if (image_id != master_image_id) { gint32 l_sel_channel_id; gimp_selection_all(image_id); l_sel_channel_id = gimp_image_get_selection(image_id); /* copy the initial selection master_channel_id * to the newly create image */ gap_layer_copy_content( l_sel_channel_id /* dst_drawable_id */ , master_channel_id /* src_drawable_id */ ); } return(TRUE); } if(action_mode == GAP_MOD_ACM_SEL_ADD) { /* if we are processing the master image, * no need to add selection to itself */ if (image_id != master_image_id) { p_selection_combine(image_id, master_channel_id, GIMP_CHANNEL_OP_ADD); } return(TRUE); } if(action_mode == GAP_MOD_ACM_SEL_SUBTRACT) { /* if we are processing the master image, * we must defere action until all other images are handled * to keep original master selection intact. * (subtract from itself would clear the selection) */ if (image_id != master_image_id) { p_selection_combine(image_id, master_channel_id, GIMP_CHANNEL_OP_SUBTRACT); } return(TRUE); } if(action_mode == GAP_MOD_ACM_SEL_INTERSECT) { /* if we are processing the master image, * intersect with itself can be skipped, because * the result will be the same selection as before. */ if (image_id != master_image_id) { p_selection_combine(image_id, master_channel_id, GIMP_CHANNEL_OP_INTERSECT); } return(TRUE); } if(action_mode == GAP_MOD_ACM_SEL_NONE) { gimp_selection_none(image_id); return(TRUE); } if(action_mode == GAP_MOD_ACM_SEL_ALL) { gimp_selection_all(image_id); return(TRUE); } if(action_mode == GAP_MOD_ACM_SEL_INVERT) { gimp_selection_invert(image_id); return(TRUE); } return(FALSE); } /* end p_apply_selection_action */ /* --------------------------------- * p_apply_action * --------------------------------- * perform function (defined by action_mode) * on all selcted layer(s) * * note: some functions operate on the images selection channel * and may be skiped when processing the active master_image_id * * returns 0 if all done OK * (or -1 on error) */ static int p_apply_action(gint32 image_id, gint32 action_mode, GapModLayliElem *layli_ptr, gint nlayers, gint32 sel_cnt, long from, long to, long curr, char *new_layername, char *filter_procname, gint32 master_image_id ) { int l_idx; int l_rc; gint32 l_layer_id; gint32 l_layermask_id; gint32 l_new_layer_id; gint l_merge_mode; gint l_vis_result; char l_name_buff[MAX_LAYERNAME]; if(gap_debug) printf("gap: p_apply_action START\n"); l_rc = 0; l_merge_mode = -44; /* none of the flatten modes */ if(action_mode == GAP_MOD_ACM_MERGE_EXPAND) l_merge_mode = GAP_RANGE_OPS_FLAM_MERG_EXPAND; if(action_mode == GAP_MOD_ACM_MERGE_IMG) l_merge_mode = GAP_RANGE_OPS_FLAM_MERG_CLIP_IMG; if(action_mode == GAP_MOD_ACM_MERGE_BG) l_merge_mode = GAP_RANGE_OPS_FLAM_MERG_CLIP_BG; /* check and perform selection related actions * that operate on the image (and not on selected layer(s) */ { gint32 master_channel_id; gboolean action_was_applied; master_channel_id = gimp_image_get_selection(master_image_id); action_was_applied = p_apply_selection_action(image_id , action_mode , master_image_id , master_channel_id ); if(action_was_applied) { return l_rc; } } /* merge actions require one call per image */ if(l_merge_mode != (-44)) { if(sel_cnt < 2) { return(0); /* OK, nothing to merge */ } l_vis_result = FALSE; /* set selected layers visible, all others invisible for merge */ for(l_idx = 0; l_idx < nlayers; l_idx++) { if(layli_ptr[l_idx].selected == FALSE) { gimp_drawable_set_visible(layli_ptr[l_idx].layer_id, FALSE); } else { if(gimp_drawable_get_visible(layli_ptr[l_idx].layer_id)) { /* result will we visible if at least one of the * selected layers was visible before */ l_vis_result = TRUE; } gimp_drawable_set_visible(layli_ptr[l_idx].layer_id, TRUE); } } /* merge all visible layers (i.e. all selected layers) */ l_layer_id = gimp_image_merge_visible_layers (image_id, l_merge_mode); if(l_vis_result == FALSE) { gimp_drawable_set_visible(l_layer_id, FALSE); } /* if new_layername is available use that name * for the new merged layer */ if (!gap_match_string_is_empty (new_layername)) { gap_match_substitute_framenr(&l_name_buff[0], sizeof(l_name_buff), new_layername, curr); gimp_drawable_set_name(l_layer_id, &l_name_buff[0]); } /* restore visibility flags after merge */ for(l_idx = 0; l_idx < nlayers; l_idx++) { if(layli_ptr[l_idx].selected == FALSE) { gimp_drawable_set_visible(layli_ptr[l_idx].layer_id, layli_ptr[l_idx].visible); } } return(0); } /* -----------------------------*/ /* non-merge actions require calls foreach selected layer */ for(l_idx = 0; (l_idx < nlayers) && (l_rc == 0); l_idx++) { l_layer_id = layli_ptr[l_idx].layer_id; /* apply function defined by action_mode */ if(layli_ptr[l_idx].selected != FALSE) { if(gap_debug) printf("gap: p_apply_action on selected LayerID:%d layerstack:%d\n", (int)l_layer_id, (int)l_idx); switch(action_mode) { case GAP_MOD_ACM_SET_VISIBLE: gimp_drawable_set_visible(l_layer_id, TRUE); break; case GAP_MOD_ACM_SET_INVISIBLE: gimp_drawable_set_visible(l_layer_id, FALSE); break; case GAP_MOD_ACM_SET_LINKED: gimp_drawable_set_linked(l_layer_id, TRUE); break; case GAP_MOD_ACM_SET_UNLINKED: gimp_drawable_set_linked(l_layer_id, FALSE); break; case GAP_MOD_ACM_RAISE: p_raise_layer(image_id, l_layer_id, layli_ptr, nlayers); break; case GAP_MOD_ACM_LOWER: p_lower_layer(image_id, l_layer_id, layli_ptr, nlayers); break; case GAP_MOD_ACM_APPLY_FILTER: l_rc = gap_filt_pdb_call_plugin(filter_procname, image_id, l_layer_id, GIMP_RUN_WITH_LAST_VALS); if(gap_debug) printf("gap: p_apply_action FILTER:%s rc =%d\n", filter_procname, (int)l_rc); break; case GAP_MOD_ACM_APPLY_FILTER_ON_LAYERMASK: if(gimp_layer_get_mask(l_layer_id) >= 0) { l_rc = gap_filt_pdb_call_plugin(filter_procname, image_id, gimp_layer_get_mask(l_layer_id), GIMP_RUN_WITH_LAST_VALS); } break; case GAP_MOD_ACM_DUPLICATE: l_new_layer_id = gimp_layer_copy(l_layer_id); gimp_image_add_layer (image_id, l_new_layer_id, -1); if (!gap_match_string_is_empty (new_layername)) { gap_match_substitute_framenr(&l_name_buff[0], sizeof(l_name_buff), new_layername, curr); gimp_drawable_set_name(l_new_layer_id, &l_name_buff[0]); } break; case GAP_MOD_ACM_DELETE: gimp_image_remove_layer(image_id, l_layer_id); break; case GAP_MOD_ACM_RENAME: gap_match_substitute_framenr(&l_name_buff[0], sizeof(l_name_buff), new_layername, curr); gimp_drawable_set_name(l_layer_id, &l_name_buff[0]); break; case GAP_MOD_ACM_SEL_ALPHA: if(gimp_drawable_has_alpha(l_layer_id)) { gimp_selection_layer_alpha(l_layer_id); } else { gimp_selection_none(image_id); } break; case GAP_MOD_ACM_SEL_SAVE: { gint32 l_sel_channel_id; l_sel_channel_id = gimp_selection_save(image_id); if(*new_layername != '\0') { gap_match_substitute_framenr(&l_name_buff[0], sizeof(l_name_buff), new_layername, curr); gimp_drawable_set_name(l_sel_channel_id, &l_name_buff[0]); } } break; case GAP_MOD_ACM_SEL_LOAD: { if(*new_layername != '\0') { gint *l_channels; gint n_channels; gint l_ii; gchar *l_channelname; gap_match_substitute_framenr(&l_name_buff[0], sizeof(l_name_buff), new_layername, curr); l_channels = gimp_image_get_channels(image_id, &n_channels); for(l_ii=0; l_ii < n_channels; l_ii++) { l_channelname = gimp_drawable_get_name(l_channels[l_ii]); if(l_channelname) { if(strcmp(l_channelname,&l_name_buff[0] ) == 0) { gimp_selection_load(l_channels[l_ii]); g_free(l_channelname); break; } g_free(l_channelname); } } if(l_channels) { g_free(l_channels); } } } break; case GAP_MOD_ACM_SEL_DELETE: { if(*new_layername != '\0') { gint *l_channels; gint n_channels; gint l_ii; gchar *l_channelname; gap_match_substitute_framenr(&l_name_buff[0], sizeof(l_name_buff), new_layername, curr); l_channels = gimp_image_get_channels(image_id, &n_channels); for(l_ii=0; l_ii < n_channels; l_ii++) { l_channelname = gimp_drawable_get_name(l_channels[l_ii]); if(l_channelname) { if(strcmp(l_channelname,&l_name_buff[0] ) == 0) { gimp_image_remove_channel(image_id, l_channels[l_ii]); } g_free(l_channelname); } } if(l_channels) { g_free(l_channels); } } } break; case GAP_MOD_ACM_ADD_ALPHA: if(!gimp_drawable_has_alpha(l_layer_id)) { gimp_layer_add_alpha(l_layer_id); } break; case GAP_MOD_ACM_LMASK_WHITE: if(gimp_layer_get_mask(l_layer_id) >= 0) { gimp_layer_remove_mask (l_layer_id, GIMP_MASK_APPLY); } l_layermask_id = gimp_layer_create_mask(l_layer_id, GIMP_ADD_WHITE_MASK); gimp_layer_add_mask(l_layer_id, l_layermask_id); break; case GAP_MOD_ACM_LMASK_BLACK: if(gimp_layer_get_mask(l_layer_id) >= 0) { gimp_layer_remove_mask (l_layer_id, GIMP_MASK_APPLY); } l_layermask_id = gimp_layer_create_mask(l_layer_id, GIMP_ADD_BLACK_MASK); gimp_layer_add_mask(l_layer_id, l_layermask_id); break; case GAP_MOD_ACM_LMASK_ALPHA: if(gimp_layer_get_mask(l_layer_id) >= 0) { gimp_layer_remove_mask (l_layer_id, GIMP_MASK_APPLY); } l_layermask_id = gimp_layer_create_mask(l_layer_id, GIMP_ADD_ALPHA_MASK); gimp_layer_add_mask(l_layer_id, l_layermask_id); break; case GAP_MOD_ACM_LMASK_TALPHA: if(gimp_layer_get_mask(l_layer_id) >= 0) { gimp_layer_remove_mask (l_layer_id, GIMP_MASK_APPLY); } l_layermask_id = gimp_layer_create_mask(l_layer_id, GIMP_ADD_ALPHA_TRANSFER_MASK); gimp_layer_add_mask(l_layer_id, l_layermask_id); break; case GAP_MOD_ACM_LMASK_SEL: if(gimp_layer_get_mask(l_layer_id) >= 0) { gimp_layer_remove_mask (l_layer_id, GIMP_MASK_APPLY); } l_layermask_id = gimp_layer_create_mask(l_layer_id, GIMP_ADD_SELECTION_MASK); gimp_layer_add_mask(l_layer_id, l_layermask_id); break; case GAP_MOD_ACM_LMASK_BWCOPY: if(gimp_layer_get_mask(l_layer_id) >= 0) { gimp_layer_remove_mask (l_layer_id, GIMP_MASK_APPLY); } l_layermask_id = gimp_layer_create_mask(l_layer_id, GIMP_ADD_COPY_MASK); gimp_layer_add_mask(l_layer_id, l_layermask_id); break; case GAP_MOD_ACM_LMASK_DELETE: if(gimp_layer_get_mask(l_layer_id) >= 0) { gimp_layer_remove_mask (l_layer_id, GIMP_MASK_DISCARD); } break; case GAP_MOD_ACM_LMASK_APPLY: if(gimp_layer_get_mask(l_layer_id) >= 0) { gimp_layer_remove_mask (l_layer_id, GIMP_MASK_APPLY); } break; case GAP_MOD_ACM_LMASK_COPY_FROM_UPPER_LMASK: case GAP_MOD_ACM_LMASK_COPY_FROM_LOWER_LMASK: /* create black mask per default */ if(gimp_layer_get_mask(l_layer_id) >= 0) { gimp_layer_remove_mask (l_layer_id, GIMP_MASK_APPLY); } l_layermask_id = gimp_layer_create_mask(l_layer_id, GIMP_ADD_BLACK_MASK); gimp_layer_add_mask(l_layer_id, l_layermask_id); /* get layermask_id from upper neigbour layer (if there is any) */ if(l_layermask_id >= 0) { gint32 l_nb_mask_id; gint32 l_nb_layer_id; gint32 l_nb_ref; gint32 l_fsel_layer_id; gint32 l_nb_had_layermask; l_nb_ref = 1; if(action_mode == GAP_MOD_ACM_LMASK_COPY_FROM_UPPER_LMASK) { l_nb_ref = -1; } l_nb_layer_id = p_get_nb_layer_id(image_id, l_layer_id, l_nb_ref); if(l_nb_layer_id >= 0) { l_nb_mask_id = gimp_layer_get_mask(l_nb_layer_id); l_nb_had_layermask = TRUE; if(l_nb_mask_id < 0) { /* the referenced neigbour layer had no layermask * in this case we create one as bw-copy temporary */ l_nb_had_layermask = FALSE; l_nb_mask_id = gimp_layer_create_mask(l_nb_layer_id, GIMP_ADD_COPY_MASK); gimp_layer_add_mask(l_nb_layer_id, l_nb_mask_id); } if(l_nb_mask_id >= 0) { /* the referenced neigbour layer has a layermask * we can copy from this mask now */ gimp_selection_none(image_id); gimp_edit_copy(l_nb_mask_id); l_fsel_layer_id = gimp_edit_paste(l_layermask_id, FALSE); gimp_floating_sel_anchor(l_fsel_layer_id); if(l_nb_had_layermask == FALSE) { /* remove the temporary created layermask in the neigbour layer */ gimp_layer_remove_mask (l_nb_layer_id, GIMP_MASK_DISCARD); } } } } break; case GAP_MOD_ACM_LMASK_INVERT: if(gimp_layer_get_mask(l_layer_id) >= 0) { gimp_invert(gimp_layer_get_mask(l_layer_id)); } break; case GAP_MOD_ACM_CREATE_LAYER_FROM_OPACITY: /* create a mask layer that represents current opacity * (including both the alpha channel and layermask (if exists) */ gap_layer_create_layer_from_alpha(l_layer_id , image_id , NULL /* name_prefix */ , _("_msk") /* name suffix */ , TRUE /* applyExistingLayermask */ , FALSE /* useTransferAlpha */ ); break; case GAP_MOD_ACM_CREATE_LAYER_FROM_ALPHA: /* create a mask layer that is a copy of the the alpha channel * (ignores an existing layermask) */ gap_layer_create_layer_from_alpha(l_layer_id , image_id , NULL /* name_prefix */ , _("_msk") /* name suffix */ , FALSE /* applyExistingLayermask */ , FALSE /* useTransferAlpha */ ); break; case GAP_MOD_ACM_CREATE_LAYER_FROM_LMASK: /* create a mask layer that is a copy of the layermask * (ignores the alpha channel) */ gap_layer_create_layer_from_layermask(l_layer_id , image_id , NULL /* name_prefix */ , _("_msk") /* name suffix */ ); break; case GAP_MOD_ACM_SET_MODE_NORMAL: gimp_layer_set_mode(l_layer_id, GIMP_NORMAL_MODE); break; case GAP_MOD_ACM_SET_MODE_DISSOLVE: gimp_layer_set_mode(l_layer_id, GIMP_DISSOLVE_MODE); break; case GAP_MOD_ACM_SET_MODE_MULTIPLY: gimp_layer_set_mode(l_layer_id, GIMP_MULTIPLY_MODE); break; case GAP_MOD_ACM_SET_MODE_DIVIDE: gimp_layer_set_mode(l_layer_id, GIMP_DIVIDE_MODE); break; case GAP_MOD_ACM_SET_MODE_SCREEN: gimp_layer_set_mode(l_layer_id, GIMP_SCREEN_MODE); break; case GAP_MOD_ACM_SET_MODE_OVERLAY: gimp_layer_set_mode(l_layer_id, GIMP_OVERLAY_MODE); break; case GAP_MOD_ACM_SET_MODE_DIFFERENCE: gimp_layer_set_mode(l_layer_id, GIMP_DIFFERENCE_MODE); break; case GAP_MOD_ACM_SET_MODE_ADDITION: gimp_layer_set_mode(l_layer_id, GIMP_ADDITION_MODE); break; case GAP_MOD_ACM_SET_MODE_SUBTRACT: gimp_layer_set_mode(l_layer_id, GIMP_SUBTRACT_MODE); break; case GAP_MOD_ACM_SET_MODE_DARKEN_ONLY: gimp_layer_set_mode(l_layer_id, GIMP_DARKEN_ONLY_MODE); break; case GAP_MOD_ACM_SET_MODE_LIGHTEN_ONLY: gimp_layer_set_mode(l_layer_id, GIMP_LIGHTEN_ONLY_MODE); break; case GAP_MOD_ACM_SET_MODE_DODGE: gimp_layer_set_mode(l_layer_id, GIMP_DODGE_MODE); break; case GAP_MOD_ACM_SET_MODE_BURN: gimp_layer_set_mode(l_layer_id, GIMP_BURN_MODE); break; case GAP_MOD_ACM_SET_MODE_HARDLIGHT: gimp_layer_set_mode(l_layer_id, GIMP_HARDLIGHT_MODE); break; case GAP_MOD_ACM_SET_MODE_SOFTLIGHT: gimp_layer_set_mode(l_layer_id, GIMP_SOFTLIGHT_MODE); break; case GAP_MOD_ACM_SET_MODE_COLOR_ERASE: gimp_layer_set_mode(l_layer_id, GIMP_COLOR_ERASE_MODE); break; case GAP_MOD_ACM_SET_MODE_GRAIN_EXTRACT_MODE: gimp_layer_set_mode(l_layer_id, GIMP_GRAIN_EXTRACT_MODE); break; case GAP_MOD_ACM_SET_MODE_GRAIN_MERGE_MODE: gimp_layer_set_mode(l_layer_id, GIMP_GRAIN_MERGE_MODE); break; case GAP_MOD_ACM_SET_MODE_HUE_MODE: gimp_layer_set_mode(l_layer_id, GIMP_HUE_MODE); break; case GAP_MOD_ACM_SET_MODE_SATURATION_MODE: gimp_layer_set_mode(l_layer_id, GIMP_SATURATION_MODE); break; case GAP_MOD_ACM_SET_MODE_COLOR_MODE: gimp_layer_set_mode(l_layer_id, GIMP_COLOR_MODE); break; case GAP_MOD_ACM_SET_MODE_VALUE_MODE: gimp_layer_set_mode(l_layer_id, GIMP_VALUE_MODE); break; case GAP_MOD_ACM_RESIZE_TO_IMG: gimp_layer_resize_to_image_size (l_layer_id); break; default: break; } } } return (l_rc); } /* end p_apply_action */ /* ============================================================================ * p_do_filter_dialogs * additional dialog steps * a) gap_pdb_browser (select the filter) * b) 1st interactive filtercall * c) 1st pitstop dialog * ============================================================================ */ static int p_do_filter_dialogs(GapAnimInfo *ainfo_ptr, gint32 image_id, gint32 *dpy_id, GapModLayliElem * layli_ptr, gint nlayers , char *filter_procname, int filt_len, gint *plugin_data_len, GapFiltPdbApplyMode *apply_mode, gboolean operate_on_layermask ) { GapDbBrowserResult l_browser_result; gint32 l_drawable_id; int l_rc; int l_idx; static char l_key_from[512]; static char *canonical_proc_name; /* GAP-PDB-Browser Dialog */ /* ---------------------- */ if(gap_db_browser_dialog( _("Select Filter for Animated Apply on Frames"), _("Apply Constant"), _("Apply Varying"), gap_filt_pdb_constraint_proc, gap_filt_pdb_constraint_proc_sel1, gap_filt_pdb_constraint_proc_sel2, &l_browser_result, image_id, GAP_DB_BROWSER_MODFRAMES_HELP_ID) < 0) { if(gap_debug) printf("DEBUG: gap_db_browser_dialog cancelled\n"); return -1; } canonical_proc_name = gimp_canonicalize_identifier(l_browser_result.selected_proc_name); strncpy(filter_procname, canonical_proc_name, filt_len-1); filter_procname[filt_len-1] = '\0'; g_free(canonical_proc_name); if(l_browser_result.button_nr == 1) *apply_mode = GAP_PAPP_VARYING_LINEAR; else *apply_mode = GAP_PAPP_CONSTANT; /* 1.st INTERACTIV Filtercall dialog */ /* --------------------------------- */ /* check for the Plugin */ l_rc = gap_filt_pdb_procedure_available(filter_procname, GAP_PTYP_CAN_OPERATE_ON_DRAWABLE); if(l_rc < 0) { printf("ERROR: Plugin not available or wrong type %s\n", filter_procname); return -1; } /* get 1.st selected layer (of 1.st handled frame in range ) */ l_idx = gap_mod_get_1st_selected(layli_ptr, nlayers); if(l_idx < 0) { printf("ERROR: No layer selected in 1.st handled frame\n"); return (-1); } l_drawable_id = layli_ptr[l_idx].layer_id; if(operate_on_layermask) { l_drawable_id = gimp_layer_get_mask(layli_ptr[l_idx].layer_id); if(l_drawable_id < 0) { printf("ERROR: selected layer has no layermask\n"); return -1; } } /* open a view for the 1.st handled frame */ *dpy_id = gimp_display_new (image_id); l_rc = gap_filt_pdb_call_plugin(filter_procname, image_id, l_drawable_id, GIMP_RUN_INTERACTIVE); /* OOPS: cant delete the display here, because * closing the last display seems to free up * at least parts of the image, * and causes crashes if the image_id is used * in further gimp procedures */ /* gimp_display_delete(*dpy_id); */ /* get values, then store with suffix "-ITER-FROM" */ *plugin_data_len = gap_filt_pdb_get_data(filter_procname); if(*plugin_data_len > 0) { g_snprintf(l_key_from, sizeof(l_key_from), "%s%s", filter_procname, GAP_ITER_FROM_SUFFIX); gap_filt_pdb_set_data(l_key_from, *plugin_data_len); } else { return (-1); } if(*apply_mode != GAP_PAPP_VARYING_LINEAR) { return (p_pitstop_dialog(1, filter_procname)); } return(0); } /* end p_do_filter_dialogs */ /* ============================================================================ * p_do_2nd_filter_dialogs * d) [ 2nd interactive filtercall * e) 2nd pitstop dialog ] * * (temporary) open the last frame of the range * get its 1.st selected laye * and do the Interctive Filtercall (to get the end-values) * * then close everything (without save). * (the last frame will be processed later, with all its selected layers) * ============================================================================ */ static gint p_do_2nd_filter_dialogs(char *filter_procname, GapFiltPdbApplyMode l_apply_mode, char *last_frame_filename, gint32 sel_mode, gint32 sel_case, gint32 sel_invert, char *sel_pattern, gboolean operate_on_layermask ) { gint32 l_drawable_id; gint32 l_dpy_id; int l_rc; int l_idx; static char l_key_to[512]; static char l_key_from[512]; gint32 l_last_image_id; GapModLayliElem *l_layli_ptr; gint l_nlayers; gint32 l_sel_cnt; gint l_plugin_data_len; l_layli_ptr = NULL; l_rc = -1; /* assume cancel or error */ l_last_image_id = -1; l_dpy_id = -1; /* 2.nd INTERACTIV Filtercall dialog */ /* --------------------------------- */ if(last_frame_filename == NULL) { return (-1); /* there is no 2.nd frame for 2.nd filter call */ } if(p_pitstop_dialog(0, filter_procname) < 0) goto cleanup; /* load last frame into temporary image */ l_last_image_id = gap_lib_load_image(last_frame_filename); if (l_last_image_id < 0) goto cleanup; /* get informations (id, visible, selected) about all layers */ l_layli_ptr = gap_mod_alloc_layli(l_last_image_id, &l_sel_cnt, &l_nlayers, sel_mode, sel_case, sel_invert, sel_pattern); if (l_layli_ptr == NULL) goto cleanup; /* get 1.st selected layer (of last handled frame in range ) */ l_idx = gap_mod_get_1st_selected(l_layli_ptr, l_nlayers); if(l_idx < 0) { g_message (_("Modify Layers cancelled: No layer selected in last handled frame")); goto cleanup; } l_drawable_id = l_layli_ptr[l_idx].layer_id; if(operate_on_layermask) { l_drawable_id = gimp_layer_get_mask(l_layli_ptr[l_idx].layer_id); if(l_drawable_id < 0) { g_message (_("Modify Layers cancelled: first selected layer \"%s\"\nin last frame has no layermask"), gimp_drawable_get_name(l_layli_ptr[l_idx].layer_id) ); goto cleanup; } } /* open a view for the last handled frame */ l_dpy_id = gimp_display_new (l_last_image_id); /* 2.nd INTERACTIV Filtercall dialog */ /* --------------------------------- */ l_rc = gap_filt_pdb_call_plugin(filter_procname, l_last_image_id, l_drawable_id, GIMP_RUN_INTERACTIVE); /* get values, then store with suffix "-ITER-TO" */ l_plugin_data_len = gap_filt_pdb_get_data(filter_procname); if(l_plugin_data_len <= 0) goto cleanup; g_snprintf(l_key_to, sizeof(l_key_to), "%s%s", filter_procname, GAP_ITER_TO_SUFFIX); gap_filt_pdb_set_data(l_key_to, l_plugin_data_len); /* get FROM values */ g_snprintf(l_key_from, sizeof(l_key_from), "%s%s", filter_procname, GAP_ITER_FROM_SUFFIX); l_plugin_data_len = gap_filt_pdb_get_data(l_key_from); gap_filt_pdb_set_data(filter_procname, l_plugin_data_len); l_rc = p_pitstop_dialog(1, filter_procname); cleanup: if(l_last_image_id >= 0) { gimp_image_delete(l_last_image_id); } if(l_dpy_id >= 0) { gimp_display_delete(l_dpy_id); } if(l_layli_ptr != NULL) { g_free(l_layli_ptr); } return (l_rc); } /* end p_do_2nd_filter_dialogs */ /* ============================================================================ * p_frames_modify * * foreach frame of the range (given by range_from and range_to) * perform function defined by action_mode * on all selected layer(s) described by sel_mode, sel_case * sel_invert and sel_pattern * returns 0 if all done OK * (or -1 on error or cancel) * ============================================================================ */ static gint32 p_frames_modify(GapAnimInfo *ainfo_ptr, long range_from, long range_to, gint32 action_mode, gint32 sel_mode, gint32 sel_case, gint32 sel_invert, char *sel_pattern, char *new_layername) { long l_cur_frame_nr; long l_step, l_begin, l_end; gint32 l_tmp_image_id; gint32 l_dpy_id; gint l_nlayers; gdouble l_percentage, l_percentage_step; int l_rc; int l_idx; gint32 l_sel_cnt; GapModLayliElem *l_layli_ptr; GimpParam *l_params; gint l_retvals; gint l_plugin_data_len; char l_filter_procname[256]; char *l_plugin_iterator; gdouble l_cur_step; gint l_total_steps; GapFiltPdbApplyMode l_apply_mode; char *l_last_frame_filename; gint l_count; gboolean l_operating_on_current_image; gboolean l_operate_on_layermask; if(gap_debug) printf("gap: p_frames_modify START, action_mode=%d sel_mode=%d case=%d, invert=%d patt:%s:\n", (int)action_mode, (int)sel_mode, (int)sel_case, (int)sel_invert, sel_pattern); l_operate_on_layermask = FALSE; l_percentage = 0.0; if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE) { gimp_progress_init( _("Modifying frames/layer(s)...")); } l_operating_on_current_image = TRUE; l_begin = range_from; l_end = range_to; l_tmp_image_id = -1; l_layli_ptr = NULL; l_rc = 0; l_plugin_iterator = NULL; l_plugin_data_len = 0; l_apply_mode = GAP_PAPP_CONSTANT; l_dpy_id = -1; l_last_frame_filename = NULL; /* init step direction */ if(range_from > range_to) { l_step = -1; /* operate in descending (reverse) order */ l_percentage_step = 1.0 / ((1.0 + range_from) - range_to); if(range_to < ainfo_ptr->first_frame_nr) { l_begin = ainfo_ptr->first_frame_nr; } if(range_from > ainfo_ptr->last_frame_nr) { l_end = ainfo_ptr->last_frame_nr; } l_total_steps = l_begin - l_end; } else { l_step = 1; /* operate in ascending order */ l_percentage_step = 1.0 / ((1.0 + range_to) - range_from); if(range_from < ainfo_ptr->first_frame_nr) { l_begin = ainfo_ptr->first_frame_nr; } if(range_to > ainfo_ptr->last_frame_nr) { l_end = ainfo_ptr->last_frame_nr; } l_total_steps = l_end - l_begin; } l_cur_step = l_total_steps; l_cur_frame_nr = l_begin; while(1) /* loop foreach frame in range */ { if(gap_debug) printf("p_frames_modify While l_cur_frame_nr = %d\n", (int)l_cur_frame_nr); /* build the frame name */ if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename); ainfo_ptr->new_filename = gap_lib_alloc_fname(ainfo_ptr->basename, l_cur_frame_nr, ainfo_ptr->extension); if(ainfo_ptr->new_filename == NULL) goto error; if(ainfo_ptr->curr_frame_nr == l_cur_frame_nr) { /* directly operate on the current image (where we were invoked from) */ l_operating_on_current_image = TRUE; l_tmp_image_id = ainfo_ptr->image_id; } else { /* load current frame into temporary image */ l_operating_on_current_image = FALSE; l_tmp_image_id = gap_lib_load_image(ainfo_ptr->new_filename); } if(l_tmp_image_id < 0) goto error; /* get informations (id, visible, selected) about all layers */ l_layli_ptr = gap_mod_alloc_layli(l_tmp_image_id, &l_sel_cnt, &l_nlayers, sel_mode, sel_case, sel_invert, sel_pattern); if(l_layli_ptr == NULL) { printf("gap: p_frames_modify: cant alloc layer info list\n"); goto error; } if((l_cur_frame_nr == l_begin) && ((action_mode == GAP_MOD_ACM_APPLY_FILTER) || (action_mode == GAP_MOD_ACM_APPLY_FILTER_ON_LAYERMASK))) { /* ------------- 1.st frame: extra dialogs for APPLY_FILTER ---------- */ if(l_sel_cnt < 1) { g_message(_("No selected layer in start frame")); goto error; } if(action_mode == GAP_MOD_ACM_APPLY_FILTER_ON_LAYERMASK) { gint l_ii; l_operate_on_layermask = TRUE; l_ii = gap_mod_get_1st_selected(l_layli_ptr, l_nlayers); if(gimp_layer_get_mask(l_layli_ptr[l_ii].layer_id) < 0) { g_message(_("first selected layer \"%s\"\nin start frame has no layermask"), gimp_drawable_get_name(l_layli_ptr[l_ii].layer_id) ); goto error; } } if(l_begin != l_end) { l_last_frame_filename = gap_lib_alloc_fname(ainfo_ptr->basename, l_end, ainfo_ptr->extension); } /* additional dialog steps a) gap_pdb_browser (select the filter) * b) 1st interactive filtercall * c) 1st pitstop dialog * d) [ 2nd interactive filtercall * e) 2nd pitstop dialog ] */ l_rc = p_do_filter_dialogs(ainfo_ptr, l_tmp_image_id, &l_dpy_id, l_layli_ptr, l_nlayers, &l_filter_procname[0], sizeof(l_filter_procname), &l_plugin_data_len, &l_apply_mode, l_operate_on_layermask ); if(l_last_frame_filename != NULL) { if((l_rc == 0) && (l_apply_mode == GAP_PAPP_VARYING_LINEAR)) { l_rc = p_do_2nd_filter_dialogs(&l_filter_procname[0], l_apply_mode, l_last_frame_filename, sel_mode, sel_case, sel_invert, sel_pattern, l_operate_on_layermask ); } g_free(l_last_frame_filename); l_last_frame_filename = NULL; } /* the 1st selected layer has been filtered * in the INTERACTIVE call b) * therefore we unselect this layer, to avoid * a 2nd processing */ l_idx = gap_mod_get_1st_selected(l_layli_ptr, l_nlayers); if(l_idx >= 0) { l_layli_ptr[l_idx].selected = FALSE; l_sel_cnt--; } /* check for matching Iterator PluginProcedures */ if(l_apply_mode == GAP_PAPP_VARYING_LINEAR ) { l_plugin_iterator = gap_filt_pdb_get_iterator_proc(&l_filter_procname[0], &l_count); } } if(l_rc != 0) goto error; /* perform function (defined by action_mode) on selcted layer(s) */ l_rc = p_apply_action(l_tmp_image_id, action_mode, l_layli_ptr, l_nlayers, l_sel_cnt, l_begin, l_end, l_cur_frame_nr, new_layername, &l_filter_procname[0], ainfo_ptr->image_id /* MASTER_image_id */ ); if(l_rc != 0) { if(gap_debug) printf("gap: p_frames_modify p_apply-action failed. rc=%d\n", (int)l_rc); goto error; } /* free layli info table for the current frame */ if(l_layli_ptr != NULL) { g_free(l_layli_ptr); l_layli_ptr = NULL; } /* check if the resulting image has at least one layer */ gap_image_prevent_empty_image(l_tmp_image_id); /* save current frame with same name */ l_rc = gap_lib_save_named_frame(l_tmp_image_id, ainfo_ptr->new_filename); if(l_rc < 0) { printf("gap: p_frames_modify save frame %d failed.\n", (int)l_cur_frame_nr); goto error; } else l_rc = 0; /* iterator call (for filter apply with varying values) */ if((action_mode == GAP_MOD_ACM_APPLY_FILTER) && (l_plugin_iterator != NULL) && (l_apply_mode == GAP_PAPP_VARYING_LINEAR )) { l_cur_step -= 1.0; /* call plugin-specific iterator, to modify * the plugin's last_values */ if(gap_debug) printf("DEBUG: calling iterator %s current frame:%d\n", l_plugin_iterator, (int)l_cur_frame_nr); if(strcmp(l_plugin_iterator, GIMP_PLUGIN_GAP_COMMON_ITER) == 0) { l_params = gimp_run_procedure (l_plugin_iterator, &l_retvals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_INT32, l_total_steps, /* total steps */ GIMP_PDB_FLOAT, (gdouble)l_cur_step, /* current step */ GIMP_PDB_INT32, l_plugin_data_len, /* length of stored data struct */ GIMP_PDB_STRING, &l_filter_procname[0], /* the common iterator needs the plugin name as additional param */ GIMP_PDB_END); } else { l_params = gimp_run_procedure (l_plugin_iterator, &l_retvals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_INT32, l_total_steps, /* total steps */ GIMP_PDB_FLOAT, (gdouble)l_cur_step, /* current step */ GIMP_PDB_INT32, l_plugin_data_len, /* length of stored data struct */ GIMP_PDB_END); } if (l_params[0].data.d_status != GIMP_PDB_SUCCESS) { printf("ERROR: iterator %s failed\n", l_plugin_iterator); l_rc = -1; } gimp_destroy_params(l_params, l_retvals); } if(l_operating_on_current_image == FALSE) { /* destroy the tmp image */ gimp_image_delete(l_tmp_image_id); } /* close display (if open) */ if (l_dpy_id >= 0) { gimp_display_delete(l_dpy_id); l_dpy_id = -1; } if(l_rc != 0) goto error; if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE) { l_percentage += l_percentage_step; gimp_progress_update (l_percentage); } /* advance to next frame */ if(l_cur_frame_nr == l_end) break; l_cur_frame_nr += l_step; } /* end while(1) loop foreach frame in range */ /* check if master image is included in the affected range */ if ((ainfo_ptr->curr_frame_nr >= MIN(range_from, range_to)) && (ainfo_ptr->curr_frame_nr <= MAX(range_from, range_to))) { /* apply defered action concerning modifying the selection * (this is done after processing all other frames in the range * because the changes affect the selection of the master image) */ if ((action_mode == GAP_MOD_ACM_SEL_SUBTRACT) || (action_mode == GAP_MOD_ACM_SEL_ADD) || (action_mode == GAP_MOD_ACM_SEL_INTERSECT)) { gint32 master_channel_id; /* create a temporary copy of the selection * (because add the selections to itself * behaves different when there are partly selected pixel * than using a copy) */ master_channel_id = gimp_selection_save(ainfo_ptr->image_id); p_apply_selection_action(ainfo_ptr->image_id , action_mode , -1 /* MASTER_image_id */ , master_channel_id ); gimp_image_remove_channel(ainfo_ptr->image_id, master_channel_id); } } if(gap_debug) printf("p_frames_modify End OK\n"); return 0; error: if(gap_debug) printf("gap: p_frames_modify exit with Error\n"); if((l_tmp_image_id >= 0) && (l_operating_on_current_image == FALSE)) { gimp_image_delete(l_tmp_image_id); } if (l_dpy_id >= 0) { gimp_display_delete(l_dpy_id); l_dpy_id = -1; } if(l_layli_ptr != NULL) g_free(l_layli_ptr); if(l_plugin_iterator != NULL) g_free(l_plugin_iterator); return -1; } /* end p_frames_modify */ /* ============================================================================ * gap_mod_layer * ============================================================================ */ gint gap_mod_layer(GimpRunMode run_mode, gint32 image_id, gint32 range_from, gint32 range_to, gint32 action_mode, gint32 sel_mode, gint32 sel_case, gint32 sel_invert, char *sel_pattern, char *new_layername) { int l_rc; GapAnimInfo *ainfo_ptr; gint32 l_from; gint32 l_to; gint32 l_action_mode; gint32 l_sel_mode; gint32 l_sel_case; gint32 l_sel_invert; char l_sel_pattern[MAX_LAYERNAME]; char l_new_layername[MAX_LAYERNAME]; l_rc = 0; ainfo_ptr = gap_lib_alloc_ainfo(image_id, run_mode); if(ainfo_ptr != NULL) { if (0 == gap_lib_dir_ainfo(ainfo_ptr)) { if(run_mode == GIMP_RUN_INTERACTIVE) { l_rc = gap_mod_frames_dialog (ainfo_ptr, &l_from, &l_to, &l_action_mode, &l_sel_mode, &sel_case, &sel_invert, &l_sel_pattern[0], &l_new_layername[0]); } else { l_from = range_from; l_to = range_to; l_action_mode = action_mode; l_sel_mode = sel_mode; l_sel_case = sel_case; l_sel_invert = sel_invert; strncpy(&l_sel_pattern[0], sel_pattern, sizeof(l_sel_pattern) -1); l_sel_pattern[sizeof(l_sel_pattern) -1] = '\0'; strncpy(&l_new_layername[0], new_layername, sizeof(l_new_layername) -1); l_new_layername[sizeof(l_new_layername) -1] = '\0'; } if(l_rc >= 0) { /* no need to save the current image before processing * because the p_frames_modify procedure operates directly on the current frame * and loads all other frames from disc. * futher all successful processed frames are saved back to disk * (including the current one) */ l_rc = p_frames_modify(ainfo_ptr, l_from, l_to, l_action_mode, l_sel_mode, sel_case, sel_invert, &l_sel_pattern[0], &l_new_layername[0] ); } } gap_lib_free_ainfo(&ainfo_ptr); } return(l_rc); } gimp-gap-2.6.0+dfsg.orig/gap/gap_mpege.h0000644000175000017500000000304111212030253017607 0ustar thibautthibaut/* gap_mpege.h * 1998.07.04 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * 0.96.00; 1998/07/02 hof: first release */ #ifndef _GAP_MPEGE_H #define _GAP_MPEGE_H #include "libgimp/gimp.h" /* Animation sizechange modes */ typedef enum { GAP_MPEGE_MPEG_ENCODE , GAP_MPEGE_MPEG2ENCODE } GapMpegEncoderType; int gap_mpeg_encode(GimpRunMode run_mode, gint32 image_id, GapMpegEncoderType encoder /* , char *output, gint bitrate, gdouble framerate */ ); #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_story_section_properties.c0000644000175000017500000006706011212030253023700 0ustar thibautthibaut/* gap_story_section_properties.c * * This module handles GAP storyboard dialog section properties window. */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * version 1.3.26a; 2007/10/08 hof: created */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "gap_story_main.h" #include "gap_story_undo.h" #include "gap_story_dialog.h" #include "gap_story_file.h" #include "gap_story_properties.h" #include "gap_pview_da.h" #include "gap_stock.h" #include "gap_lib.h" #include "gap_vin.h" #include "gap_timeconv.h" #include "gap_thumbnail.h" #include "gap_fmac_base.h" #include "gap_story_vthumb.h" #include "images/gap-stock-pixbufs.h" #include "gap-intl.h" #define GAP_STORY_SECTION_PROP_HELP_ID "plug-in-gap-storyboard-section-prop" #define GAP_STORY_SECTION_RESPONSE_DELETE 2 #define GAP_STORY_SECTION_RESPONSE_CREATE 3 #define SPW_ENTRY_WIDTH 300 #define SPW_ICON_TYPE_WIDTH 48 #define SPW_ICON_TYPE_HEIGHT 35 typedef enum { GAP_SPW_TYPE_MAIN_SECTION ,GAP_SPW_TYPE_MASK_SECTION ,GAP_SPW_TYPE_SUB_SECTION ,GAP_SPW_TYPE_UNKNOWN_SECTION } GapStorySpwSectionType; extern int gap_debug; /* 1 == print debug infos , 0 dont print debug infos */ static void p_spw_prop_response(GtkWidget *widget , gint response_id , GapStbSecpropWidget *spw ); static GapStorySpwSectionType p_get_section_type(GapStbSecpropWidget *spw); static void p_section_name_entry_set_text(GapStbSecpropWidget *spw, const char *text); static gboolean p_rename_section(GapStbSecpropWidget *spw); static void p_render_section_icon(GapStbSecpropWidget *pv_ptr); static void p_switch_to_section(GapStbSecpropWidget *spw, GapStorySection *section); static void p_delete_sub_section_cb(GtkWidget *w, GapStbSecpropWidget *spw); static void p_create_new_section(GapStbSecpropWidget *spw); static gboolean p_spw_icontype_preview_events_cb (GtkWidget *widget , GdkEvent *event , GapStbSecpropWidget *spw); static void p_spw_section_name_entry_update_cb(GtkWidget *widget, GapStbSecpropWidget *spw); static void p_spw_update_info_labels(GapStbSecpropWidget *spw); static void p_update_widget_sensitivity(GapStbSecpropWidget *spw); static GtkWidget * p_spw_create_icontype_pv_container(GapStbSecpropWidget *spw); /* --------------------------------- * p_spw_prop_response * --------------------------------- */ static void p_spw_prop_response(GtkWidget *widget , gint response_id , GapStbSecpropWidget *spw ) { GtkWidget *dlg; GapStbMainGlobalParams *sgpp; gboolean ok_flag; sgpp = spw->sgpp; switch (response_id) { case GAP_STORY_SECTION_RESPONSE_CREATE: p_create_new_section(spw); break; case GTK_RESPONSE_OK: ok_flag = p_rename_section(spw); if (ok_flag != TRUE) { return; } /* fall through and close the dialog on OK */ case GTK_RESPONSE_CANCEL: case GAP_STORY_SECTION_RESPONSE_DELETE: default: gap_pview_reset(spw->typ_icon_pv_ptr); dlg = spw->spw_prop_dialog; if(dlg) { spw->spw_prop_dialog = NULL; gtk_widget_destroy(dlg); } break; } } /* end p_spw_prop_response */ /* --------------------------------- * p_get_section_type * --------------------------------- * returns the section type of the current * section reference spw->section_refptr */ static GapStorySpwSectionType p_get_section_type(GapStbSecpropWidget *spw) { GapStorySpwSectionType section_type; GapStorySection *main_section; section_type = GAP_SPW_TYPE_UNKNOWN_SECTION; if (spw->section_refptr != NULL) { if (spw->stb_refptr != NULL) { if(spw->section_refptr == spw->stb_refptr->mask_section) { return (GAP_SPW_TYPE_MASK_SECTION); } main_section = gap_story_find_main_section(spw->stb_refptr); if (spw->section_refptr == main_section) { return(GAP_SPW_TYPE_MAIN_SECTION); } return(GAP_SPW_TYPE_SUB_SECTION); } } return (section_type); } /* end p_get_section_type */ /* --------------------------------- * p_section_name_entry_set_text * --------------------------------- */ static void p_section_name_entry_set_text(GapStbSecpropWidget *spw, const char *text) { if ((spw == NULL) || (text == NULL)) { return; } if(spw->spw_section_name_entry == NULL) { return; } gtk_entry_set_text(GTK_ENTRY(spw->spw_section_name_entry), text); } /* end p_section_name_entry_set_text */ /* --------------------------------- * p_rename_section * --------------------------------- */ static gboolean p_rename_section(GapStbSecpropWidget *spw) { const guchar *section_name; if (spw == NULL) { return (TRUE); } if(spw->section_refptr == NULL) { return(TRUE); } if(spw->stb_refptr == NULL) { return(TRUE); } section_name = gtk_entry_get_text(GTK_ENTRY(spw->spw_section_name_entry)); if (section_name == NULL) { return (TRUE); } if(spw->section_refptr->section_name != NULL) { if(strcmp(section_name, spw->section_refptr->section_name) == 0) { /* the name has not changed */ return (TRUE); } if(gap_story_find_section_by_name(spw->stb_refptr, section_name) != NULL) { if(spw->spw_info_text_label != NULL) { gtk_label_set_text ( GTK_LABEL(spw->spw_info_text_label) , _("please enter a unique section name")); } return (FALSE); } gap_stb_undo_push((GapStbTabWidgets *)spw->tabw, GAP_STB_FEATURE_PROPERTIES_SECTION); spw->stb_refptr->unsaved_changes = TRUE; g_free(spw->section_refptr->section_name); spw->section_refptr->section_name = g_strdup(section_name); /* refresh the section_combo box to reflect new section_name */ gap_story_dlg_spw_section_refresh(spw, spw->section_refptr); } return (TRUE); } /* end p_rename_section */ /* ---------------------------------- * p_render_section_icon * ---------------------------------- * TODO: have 3 different section type icons * MAIN section * Mask section * sub-section */ static void p_render_section_icon(GapStbSecpropWidget *spw) { GdkPixbuf *pixbuf; GapStorySpwSectionType l_section_type; pixbuf = NULL; if(spw == NULL) { return; } if((spw->typ_icon_pv_ptr == NULL) || (spw->cliptype_label == NULL) || (spw->stb_refptr == NULL) || (spw->section_refptr == NULL)) { return; } l_section_type = p_get_section_type(spw); switch(l_section_type) { case GAP_SPW_TYPE_MAIN_SECTION: // TODO create main section icon (dont use the blacksecton in this case) pixbuf = gdk_pixbuf_new_from_inline (-1, gap_story_icon_section_main, FALSE, NULL); gtk_label_set_text ( GTK_LABEL(spw->cliptype_label), _("MAIN Section")); break; case GAP_SPW_TYPE_MASK_SECTION: // TODO create mask section icon (dont use the blacksecton in this case) pixbuf = gdk_pixbuf_new_from_inline (-1, gap_story_icon_section_mask, FALSE, NULL); gtk_label_set_text ( GTK_LABEL(spw->cliptype_label), _("Mask Section")); break; case GAP_SPW_TYPE_SUB_SECTION: pixbuf = gdk_pixbuf_new_from_inline (-1, gap_story_icon_section, FALSE, NULL); gtk_label_set_text ( GTK_LABEL(spw->cliptype_label), _("Sub Section")); break; default: pixbuf = gdk_pixbuf_new_from_inline (-1, gap_story_icon_default, FALSE, NULL); gtk_label_set_text ( GTK_LABEL(spw->cliptype_label), _("Unknown Section")); break; } if(pixbuf) { gap_pview_render_from_pixbuf (spw->typ_icon_pv_ptr, pixbuf); g_object_unref(pixbuf); } } /* end p_render_section_icon */ /* --------------------------------- * gap_story_spw_switch_to_section * --------------------------------- * this procedure is typically calld * when the section combo box in the main * storyboard edit dialog has changed * and the section properties shall be updated to refect those change. */ void gap_story_spw_switch_to_section(GapStbSecpropWidget *spw, GapStoryBoard *stb_dst) { if ((spw == NULL) || (stb_dst == NULL)) { return; } if ((spw->spw_prop_dialog == NULL) || (spw->spw_section_name_entry == NULL)) { /* skip because dialog is not open or not initialised */ return; } if(stb_dst->active_section == NULL) { printf("ERRPR: the active_section is NULL!\n"); return; } spw->stb_refptr = stb_dst; spw->section_refptr = stb_dst->active_section; p_section_name_entry_set_text(spw, spw->section_refptr->section_name); p_update_widget_sensitivity(spw); p_render_section_icon(spw); p_update_widget_sensitivity(spw); p_spw_update_info_labels(spw); } /* end gap_story_spw_switch_to_section */ /* --------------------------------- * p_switch_to_section * --------------------------------- * this procedure handles the case when a change of the active_section * is requested by the section properties dialog window. * (after creating a new subsection, or after delete of the active subsection) * This requires refresh of the section Combo box in the * main storyboard edit dialog and refresh of the thumbnails (tabw). */ static void p_switch_to_section(GapStbSecpropWidget *spw, GapStorySection *target_section) { if (spw == NULL) { return; } if(spw->spw_section_name_entry == NULL) { /* skip because init phase is in progress */ return; } p_section_name_entry_set_text(spw, target_section->section_name); p_update_widget_sensitivity(spw); p_render_section_icon(spw); p_update_widget_sensitivity(spw); /* make the section the active section * make the section the active section, refresh the sections combo box * (this implicite triggers thumbnail rendering) */ gap_story_dlg_spw_section_refresh(spw, target_section); p_spw_update_info_labels(spw); } /* end p_switch_to_section */ /* --------------------------------- * p_delete_sub_section_cb * --------------------------------- * MAIN and Mask section can not be deleted. */ static void p_delete_sub_section_cb(GtkWidget *w, GapStbSecpropWidget *spw) { gboolean removeOK; if(spw == NULL) { return; } if(spw->stb_refptr == NULL) { return; } gap_stb_undo_push((GapStbTabWidgets *)spw->tabw, GAP_STB_FEATURE_DELETE_SECTION); /* remove section from the list */ removeOK = gap_story_remove_section(spw->stb_refptr, spw->section_refptr); if (removeOK) { spw->section_refptr = gap_story_find_main_section(spw->stb_refptr); p_switch_to_section(spw, spw->section_refptr); } else { if(spw->spw_info_text_label != NULL) { gtk_label_set_text ( GTK_LABEL(spw->spw_info_text_label) , _("Could not delete current subsection" " because it is still used as Clip in the MAIN section")); } } } /* end p_delete_sub_section_cb */ /* --------------------------------- * p_create_new_section * --------------------------------- */ static void p_create_new_section(GapStbSecpropWidget *spw) { GapStorySection *new_section; gchar *new_section_name; if(spw == NULL) { return; } if(spw->stb_refptr == NULL) { return; } new_section = NULL; new_section_name = gap_story_generate_new_unique_section_name(spw->stb_refptr); if(new_section_name != NULL) { gap_stb_undo_push((GapStbTabWidgets *)spw->tabw, GAP_STB_FEATURE_CREATE_SECTION); /* create the section and add it to the end of section list in the storyboard */ new_section = gap_story_create_or_find_section_by_name(spw->stb_refptr, new_section_name); if(new_section) { spw->section_refptr = new_section; p_switch_to_section(spw, new_section); } g_free(new_section_name); } } /* end p_create_new_section */ /* --------------------------------- * p_spw_icontype_preview_events_cb * --------------------------------- */ static gboolean p_spw_icontype_preview_events_cb (GtkWidget *widget , GdkEvent *event , GapStbSecpropWidget *spw) { GdkEventExpose *eevent; GapStbMainGlobalParams *sgpp; if ((spw->stb_refptr == NULL)) { /* the widget is not initialized or it is just a dummy, no action needed */ return FALSE; } sgpp = spw->sgpp; switch (event->type) { case GDK_BUTTON_PRESS: return FALSE; break; case GDK_EXPOSE: if(gap_debug) { printf("p_spw_icontype_preview_events_cb GDK_EXPOSE widget:%d da_wgt:%d\n" , (int)widget , (int)spw->typ_icon_pv_ptr->da_widget ); } eevent = (GdkEventExpose *) event; if(spw->typ_icon_pv_ptr) { if(widget == spw->typ_icon_pv_ptr->da_widget) { p_render_section_icon(spw); gdk_flush (); } } break; default: break; } return FALSE; } /* end p_spw_icontype_preview_events_cb */ /* ----------------------------------- * p_spw_section_name_entry_update_cb * ----------------------------------- */ static void p_spw_section_name_entry_update_cb(GtkWidget *widget, GapStbSecpropWidget *spw) { const guchar *section_name; gboolean unique_name_entered; GapStorySpwSectionType l_section_type; if(spw == NULL) { return; } if(spw->stb_refptr == NULL) { return; } if(spw->section_refptr == NULL) { return; } section_name = gtk_entry_get_text(GTK_ENTRY(widget)); l_section_type = p_get_section_type(spw); // if(l_section_type == GAP_SPW_TYPE_SUB_SECTION) // { // if(spw->section_refptr->section_name != NULL) // { // if(strcmp(spw->section_refptr, section_name) != 0) // { // if(gap_story_find_section_by_name(spw->stb_refptr, section_name) != NULL) // { // gtk_label_set_text ( GTK_LABEL(spw->spw_info_text_label) // , _("please enter a unique section name")); // return; // // } // } // gtk_label_set_text ( GTK_LABEL(spw->spw_info_text_label) // , _("OK")); // } // } } /* end p_spw_section_name_entry_update_cb */ /* --------------------------------- * p_spw_update_info_labels * --------------------------------- */ static void p_spw_update_info_labels(GapStbSecpropWidget *spw) { char txt_buf[100]; gdouble l_speed_fps; gint32 l_nframes; if(spw == NULL) { return; } if(spw->stb_refptr == NULL) { return; } if(spw->section_refptr == NULL) { return; } l_nframes = gap_story_count_total_frames_in_section(spw->section_refptr); g_snprintf(txt_buf, sizeof(txt_buf), _("%d (frames)") ,(int)l_nframes ); gtk_label_set_text ( GTK_LABEL(spw->dur_frames_label), txt_buf); l_speed_fps = GAP_STORY_DEFAULT_FRAMERATE; if(spw->stb_refptr) { if(spw->stb_refptr->master_framerate > 0) { l_speed_fps = spw->stb_refptr->master_framerate; } } gap_timeconv_framenr_to_timestr( l_nframes , l_speed_fps , txt_buf , sizeof(txt_buf) ); gtk_label_set_text ( GTK_LABEL(spw->dur_time_label), txt_buf); } /* end p_spw_update_info_labels */ /* --------------------------------- * p_update_widget_sensitivity * --------------------------------- */ static void p_update_widget_sensitivity(GapStbSecpropWidget *spw) { GapStorySpwSectionType l_section_type; gboolean l_sensitive; if (spw == NULL) { return; } if ((spw->section_refptr == NULL) || (spw->stb_refptr == NULL)) { return; } l_section_type = p_get_section_type(spw); l_sensitive = TRUE; if(spw->spw_info_text_label != NULL) { switch(l_section_type) { case GAP_SPW_TYPE_MAIN_SECTION: p_section_name_entry_set_text(spw, _("MAIN")); l_sensitive = FALSE; gtk_label_set_text ( GTK_LABEL(spw->spw_info_text_label) , _("Clips of the MAIN section are rendered in the output video")); break; case GAP_SPW_TYPE_MASK_SECTION: p_section_name_entry_set_text(spw, _("Mask")); l_sensitive = FALSE; gtk_label_set_text ( GTK_LABEL(spw->spw_info_text_label) , _("Clips in the Mask section have global scope in all other sections, " " and can be attached as (animated) masks to clips in all other " " sections to add transparency." " white pixels in the mask keep the full opacity" " black pixels makes the pixel fully transparent," " all other colors in the mask result in more or less transparency" " depending on their brightness.")); break; case GAP_SPW_TYPE_SUB_SECTION: l_sensitive = TRUE; gtk_label_set_text ( GTK_LABEL(spw->spw_info_text_label) , _("sub sections are some kind of repository." " Rendering of clips in sub sections depends on " " corresponding references in the MAIN section" " via clip type SECTION")); break; default: l_sensitive = TRUE; gtk_label_set_text ( GTK_LABEL(spw->spw_info_text_label), " "); break; } gtk_widget_set_sensitive(spw->spw_section_name_entry, l_sensitive); if(spw->spw_delete_button != NULL) { gtk_widget_set_sensitive(spw->spw_delete_button, l_sensitive); } } } /* end p_update_widget_sensitivity */ /* ---------------------------------- * p_spw_create_icontype_pv_container * ---------------------------------- */ static GtkWidget * p_spw_create_icontype_pv_container(GapStbSecpropWidget *spw) { GtkWidget *alignment; GtkWidget *event_box; GtkWidget *vbox_icontype; gint32 l_check_size; /* the vbox for displaying the clip */ vbox_icontype = gtk_vbox_new (FALSE, 1); /* Create an EventBox (container for the preview drawing_area) */ event_box = gtk_event_box_new (); gtk_container_add (GTK_CONTAINER (event_box), vbox_icontype); gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK); g_signal_connect (G_OBJECT (event_box), "button_press_event", G_CALLBACK (p_spw_icontype_preview_events_cb), spw); /* The thumbnail preview */ alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); gtk_box_pack_start (GTK_BOX (vbox_icontype), alignment, FALSE, FALSE, 1); gtk_widget_show (alignment); l_check_size = SPW_ICON_TYPE_WIDTH / 16; spw->typ_icon_pv_ptr = gap_pview_new( SPW_ICON_TYPE_WIDTH , SPW_ICON_TYPE_HEIGHT , l_check_size , NULL /* no aspect_frame is used */ ); gtk_widget_set_events (spw->typ_icon_pv_ptr->da_widget, GDK_EXPOSURE_MASK); gtk_container_add (GTK_CONTAINER (alignment), spw->typ_icon_pv_ptr->da_widget); gtk_widget_show (spw->typ_icon_pv_ptr->da_widget); g_signal_connect (G_OBJECT (spw->typ_icon_pv_ptr->da_widget), "event", G_CALLBACK (p_spw_icontype_preview_events_cb), spw); gtk_widget_show (vbox_icontype); gtk_widget_show (event_box); p_render_section_icon(spw); return(event_box); } /* end p_spw_create_icontype_pv_container */ /* --------------------------------------- * gap_story_section_spw_properties_dialog * --------------------------------------- */ GtkWidget * gap_story_section_spw_properties_dialog (GapStbSecpropWidget *spw) { GtkWidget *dlg; GtkWidget *main_vbox; GtkWidget *frame; GtkWidget *table; GtkWidget *label; GtkWidget *button; GtkWidget *entry; gint row; GapStbTabWidgets *tabw; GapStorySpwSectionType l_section_type; if(spw == NULL) { return (NULL); } if(spw->spw_prop_dialog != NULL) { return(NULL); } /* is already open */ tabw = (GapStbTabWidgets *)spw->tabw; if(tabw == NULL) { return (NULL); } l_section_type = p_get_section_type(spw); dlg = gimp_dialog_new (_("Section Properties"), "gap_story_section_properties" ,NULL, 0 ,gimp_standard_help_func, GAP_STORY_SECTION_PROP_HELP_ID ,GTK_STOCK_NEW, GAP_STORY_SECTION_RESPONSE_CREATE ,GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL ,GTK_STOCK_OK, GTK_RESPONSE_OK ,NULL); spw->spw_prop_dialog = dlg; g_signal_connect (G_OBJECT (dlg), "response", G_CALLBACK (p_spw_prop_response), spw); main_vbox = gtk_vbox_new (FALSE, 4); gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6); gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dlg)->vbox), main_vbox); /* the frame */ frame = gimp_frame_new (_("Properties")); gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); table = gtk_table_new (17, 4, FALSE); spw->master_table = table; gtk_container_set_border_width (GTK_CONTAINER (table), 4); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_container_add (GTK_CONTAINER (frame), table); gtk_widget_show (table); row = 0; /* the Section Type: label */ label = gtk_label_new (_("Type:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 1, row, row+1); gtk_widget_show (label); { GtkWidget *hbox_type; hbox_type = gtk_hbox_new (FALSE, 1); gtk_widget_show (hbox_type); gtk_table_attach_defaults (GTK_TABLE(table), hbox_type, 1, 2, row, row+1); /* the cliptype icon (pview widget) */ gtk_box_pack_start (GTK_BOX (hbox_type) , p_spw_create_icontype_pv_container(spw) , FALSE, FALSE, 1); /* the cliptype label content */ label = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (hbox_type), label, FALSE, FALSE, 1); gtk_widget_show (label); spw->cliptype_label = label; /* dummy spacing label */ label = gtk_label_new (" "); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (hbox_type), label, TRUE, TRUE, 1); gtk_widget_show (label); /* the duration label */ label = gtk_label_new (_("Duration:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (hbox_type), label, FALSE, FALSE, 1); gtk_widget_show (label); /* the frame duration label */ label = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (hbox_type), label, FALSE, FALSE, 1); gtk_widget_show (label); spw->dur_frames_label = label; } /* the time duration label */ label = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE(table), label, 2, 3, row, row+1); gtk_widget_show (label); spw->dur_time_label = label; row++; /* the section_name label */ label = gtk_label_new (_("Name:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 1, row, row+1); gtk_widget_show (label); /* the section_name entry */ entry = gtk_entry_new (); spw->spw_section_name_entry = entry; gtk_widget_set_size_request(entry, SPW_ENTRY_WIDTH, -1); if(spw->section_refptr) { p_section_name_entry_set_text(spw, spw->section_refptr->section_name); } gtk_table_attach_defaults (GTK_TABLE(table), entry, 1, 2, row, row+1); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(p_spw_section_name_entry_update_cb), spw); gtk_widget_show (entry); /* the delete button */ button = p_gtk_button_new_from_stock_icon (GTK_STOCK_DELETE); spw->spw_delete_button = button; gimp_help_set_help_data (button, _("Delete storyboard section"), NULL); gtk_table_attach_defaults (GTK_TABLE(table), button, 2, 3, row, row+1); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (p_delete_sub_section_cb), spw); gtk_widget_show (button); row++; /* the info label */ label = gtk_label_new (_("Info:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 1, row, row+1); gtk_widget_show (label); /* the spw_info_text_label */ label = gtk_label_new (" *** "); spw->spw_info_text_label = label; gtk_label_set_line_wrap(label, TRUE); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE(table), label, 1, 2, row, row+1); gtk_widget_show (label); row++; /* the comment label */ // label = gtk_label_new (_("Comment:")); // gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); // gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 1, row, row+1); // gtk_widget_show (label); p_update_widget_sensitivity(spw); /* Show the main containers */ gtk_widget_show (main_vbox); return(dlg); } /* end gap_story_section_spw_properties_dialog */ /* ----------------------------------- * gap_story_secprop_properties_dialog * ----------------------------------- */ void gap_story_secprop_properties_dialog (GapStoryBoard *stb_dst, GapStbTabWidgets *tabw) { GapStbSecpropWidget *spw; if(stb_dst == NULL) { return; } spw = tabw->spw; /* check if already open */ if (spw != NULL) { if(spw->spw_prop_dialog) { /* Properties for the selected element already open * bring the window to front */ gtk_window_present(GTK_WINDOW(spw->spw_prop_dialog)); return ; } /* we found a dead element (that is already closed) * reuse that element to open a new section properties dialog window */ } if(spw==NULL) { spw = g_new(GapStbSecpropWidget ,1); tabw->spw = spw; } spw->spw_prop_dialog = NULL; spw->spw_section_name_entry = NULL; spw->cliptype_label = NULL; spw->spw_info_text_label = NULL; spw->spw_delete_button = NULL; spw->sgpp = tabw->sgpp; spw->tabw = tabw; if(stb_dst->active_section == NULL) { printf("ERRPR: active_section is NULL!\n"); return; } spw->stb_refptr = stb_dst; spw->section_refptr = stb_dst->active_section; spw->spw_prop_dialog = gap_story_section_spw_properties_dialog(spw); if(spw->spw_prop_dialog) { gtk_widget_show(spw->spw_prop_dialog); p_spw_update_info_labels(spw); } } /* end gap_story_secprop_properties_dialog */ /* ------------------------------- * gap_story_spw_properties_dialog * ------------------------------- */ void gap_story_spw_properties_dialog (GapStoryBoard *stb, GapStbTabWidgets *tabw) { if((tabw == NULL) || (stb == NULL)) { return; } gap_story_secprop_properties_dialog(stb, tabw); } /* end gap_story_spw_properties_dialog */ gimp-gap-2.6.0+dfsg.orig/gap/gap_audio_util.c0000644000175000017500000000674411212030253020660 0ustar thibautthibaut/* gap_audio_util.c * * GAP common encoder audio utility procedures * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* 2002.01.05 hof removed p_get_wavparams */ /* SYTEM (UNIX) includes */ #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" /* GAP includes */ #include "gap_audio_util.h" extern int gap_debug; /* ==0 ... dont print debug infos */ /* -------------------------------- * gap_audio_util_stereo_split16to16 * -------------------------------- */ void gap_audio_util_stereo_split16to16(unsigned char *l_left_ptr, unsigned char *l_right_ptr, unsigned char *l_aud_ptr, long l_data_len) { long l_idx; /* split stereo 16 bit data from wave data (sequence is 2 bytes left channel, 2 right, 2 left, 2 right ...) * into 2 separate datablocks for left and right channel of 16 bit per sample */ l_idx = 0; while(l_idx < l_data_len) { *(l_left_ptr++) = l_aud_ptr[l_idx++]; *(l_left_ptr++) = l_aud_ptr[l_idx++]; *(l_right_ptr++) = l_aud_ptr[l_idx++]; *(l_right_ptr++) = l_aud_ptr[l_idx++]; } } /* end gap_audio_util_stereo_split16to16 */ /* -------------------------------- * gap_audio_util_dbl_sample_8_to_16 * -------------------------------- */ void gap_audio_util_dbl_sample_8_to_16(unsigned char insample8, unsigned char *lsb_out, unsigned char *msb_out) { /* 16 bit audiodata is signed, * 8 bit audiodata is unsigned */ /* this conversion uses only positive 16bit values */ *msb_out = (insample8 >> 1); *lsb_out = ((insample8 << 7) & 0x80); return; /* this conversion makes use of negative 16bit values * and the full sample range * (somehow it sounds not as good as the other one) */ *msb_out = (insample8 -64); *lsb_out = 0; } /* end gap_audio_util_dbl_sample_8_to_16 */ /* -------------------------------- * gap_audio_util_stereo_split8to16 * -------------------------------- */ void gap_audio_util_stereo_split8to16(unsigned char *l_left_ptr, unsigned char *l_right_ptr, unsigned char *l_aud_ptr, long l_data_len) { long l_idx; unsigned char l_lsb, l_msb; /* split stereo 8 bit data from wave data (sequence is 2 bytes left channel, 2 right, 2 left, 2 right ...) * into 2 separate datablocks for left and right channel of 16 bit per sample */ l_idx = 0; while(l_idx < l_data_len) { gap_audio_util_dbl_sample_8_to_16(l_aud_ptr[l_idx], &l_lsb, &l_msb); l_idx++; *(l_left_ptr++) = l_lsb; *(l_left_ptr++) = l_msb; gap_audio_util_dbl_sample_8_to_16(l_aud_ptr[l_idx], &l_lsb, &l_msb); l_idx++; *(l_left_ptr++) = l_lsb; *(l_left_ptr++) = l_msb; } } /* end gap_audio_util_stereo_split8to16 */ gimp-gap-2.6.0+dfsg.orig/gap/gap_audio_extract.c0000644000175000017500000003451111212030253021346 0ustar thibautthibaut/* gap_audio_extract.c * * GAP extract audio from videofile procedures * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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.06.24 hof created (moved audio extract parts of gap_vex_exec.c to this module) */ /* SYTEM (UNIX) includes */ #include #include #include /* GIMP includes */ #include "gtk/gtk.h" #include "libgimp/gimp.h" /* GAP includes */ #include "gap_audio_util.h" #include "gap_audio_wav.h" #include "gap_audio_extract.h" extern int gap_debug; /* ==0 ... dont print debug infos */ #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* --------------------- * p_init_progress * --------------------- */ static void p_init_progress(const char *progressText ,gboolean do_progress ,GtkWidget *progressBar ) { if (do_progress) { if (progressBar == NULL) { gimp_progress_init (progressText); } else { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progressBar), progressText); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressBar), 0); } } } /* end p_init_progress */ #endif #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* --------------------- * p_do_progress * --------------------- */ static void p_do_progress(gdouble progressValue ,gboolean do_progress ,GtkWidget *progressBar // use NULL for gimp_progress ,t_GVA_Handle *gvahand ,gpointer user_data ) { if (do_progress) { if (progressBar == NULL) { gimp_progress_update (progressValue); } else { gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressBar), progressValue); } } if(gvahand->fptr_progress_callback) { gvahand->cancel_operation = (*gvahand->fptr_progress_callback)(progressValue, user_data); } } /* end p_do_progress */ #endif #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* ---------------------------------- * p_audio_extract_rewrite_wav_header * ---------------------------------- * */ static void p_audio_extract_rewrite_wav_header(FILE *fp_wav ,gint32 samples_written_to_file ,int audio_channels ,int sample_rate ,gint32 bytes_per_sample ) { if(fp_wav == NULL) { return; } fseek(fp_wav, 0, SEEK_SET); /* re-write the header */ gap_audio_wav_write_header(fp_wav , samples_written_to_file , audio_channels /* cannels 1 or 2 */ , sample_rate , bytes_per_sample , 16 /* 16 bit sample resolution */ ); } /* end p_audio_extract_rewrite_wav_header */ #endif #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* ------------------------- * gap_audio_extract_as_wav * ------------------------- * extract specified number of samples at current * position of the specified (already opened) videohandle. * and optional save extracted audiodata as RIFF WAVE file * (set wav_save to FALSE to skip writing to wav file, * this is typical used to perform dummy read for * advancing current position in the videohandle) */ void gap_audio_extract_as_wav(const char *audiofile , t_GVA_Handle *gvahand , gdouble samples_to_read , gboolean wav_save , gboolean do_progress , GtkWidget *progressBar // use NULL for gimp_progress , t_GVA_progress_callback_fptr fptr_progress_callback , gpointer user_data ) { int l_audio_channels; int l_sample_rate; long l_audio_samples; unsigned short *left_ptr; unsigned short *right_ptr; unsigned short *l_lptr; unsigned short *l_rptr; long l_to_read; gint64 l_left_to_read; long l_block_read; gdouble l_progress; FILE *fp_wav; l_audio_channels = gvahand->audio_cannels; l_sample_rate = gvahand->samplerate; l_audio_samples = gvahand->total_aud_samples; if(gap_debug) { printf("Channels:%d samplerate:%d samples:%d samples_to_read: %.0f\n" , (int)l_audio_channels , (int)l_sample_rate , (int)l_audio_samples , (float)samples_to_read ); } fp_wav = NULL; if(wav_save) { fp_wav = g_fopen(audiofile, "wb"); } if((fp_wav) || (!wav_save)) { gint32 l_bytes_per_sample; gint32 l_ii; if(l_audio_channels == 1) { l_bytes_per_sample = 2;} /* mono */ else { l_bytes_per_sample = 4;} /* stereo */ if(wav_save) { /* write the header */ gap_audio_wav_write_header(fp_wav , (gint32)samples_to_read , l_audio_channels /* cannels 1 or 2 */ , l_sample_rate , l_bytes_per_sample , 16 /* 16 bit sample resolution */ ); } if(gap_debug) { printf("samples_to_read:%d\n", (int)samples_to_read); } /* audio block read (blocksize covers playbacktime for 250 frames */ l_left_to_read = samples_to_read; l_block_read = (double)(250.0) / (double)gvahand->framerate * (double)l_sample_rate; l_to_read = MIN(l_left_to_read, l_block_read); /* allocate audio buffers */ left_ptr = g_malloc0((sizeof(short) * l_block_read) + 16); right_ptr = g_malloc0((sizeof(short) * l_block_read) + 16); while(l_to_read > 0) { l_lptr = left_ptr; l_rptr = right_ptr; /* read the audio data of channel 0 (left or mono) */ GVA_get_audio(gvahand ,l_lptr /* Pointer to pre-allocated buffer if int16's */ ,1 /* Channel to decode */ ,(gdouble)l_to_read /* Number of samples to decode */ ,GVA_AMOD_CUR_AUDIO /* read from current audio position (and advance) */ ); if((l_audio_channels > 1) && (wav_save)) { /* read the audio data of channel 2 (right) * NOTE: GVA_get_audio has advanced the stream position, * so we have to set GVA_AMOD_REREAD to read from * the same startposition as for channel 1 (left). */ GVA_get_audio(gvahand ,l_rptr /* Pointer to pre-allocated buffer if int16's */ ,2 /* Channel to decode */ ,l_to_read /* Number of samples to decode */ ,GVA_AMOD_REREAD /* read from */ ); } l_left_to_read -= l_to_read; if(wav_save) { /* write 16 bit wave datasamples * sequence mono: (lo, hi) * sequence stereo: (lo_left, hi_left, lo_right, hi_right) */ for(l_ii=0; l_ii < l_to_read; l_ii++) { gap_audio_wav_write_gint16(fp_wav, *l_lptr); l_lptr++; if(l_audio_channels > 1) { gap_audio_wav_write_gint16(fp_wav, *l_rptr); l_rptr++; } } } l_to_read = MIN(l_left_to_read, l_block_read); /* calculate progress */ l_progress = (gdouble)(samples_to_read - l_left_to_read) / ((gdouble)samples_to_read + 1.0); if(gap_debug) { printf("l_progress:%f\n", (float)l_progress); } p_do_progress(l_progress, do_progress, progressBar, gvahand, user_data); if(gvahand->cancel_operation) { if(wav_save) { long l_samples_written_to_file; l_samples_written_to_file = samples_to_read - l_left_to_read; /* rewrite header (to produce valid wave file in case we were cancelled) */ p_audio_extract_rewrite_wav_header(fp_wav , l_samples_written_to_file , l_audio_channels , l_sample_rate , l_bytes_per_sample ); } printf("Audio extract was cancelled.\n"); break; } } if(wav_save) { /* close wavfile */ fclose(fp_wav); } /* free audio buffers */ g_free(left_ptr); g_free(right_ptr); } return; } /* end gap_audio_extract_as_wav */ #endif #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT /* --------------------------------- * gap_audio_extract_from_videofile * --------------------------------- * extract the specified audiotrack to WAVE file. (name specified via audiofile) * starting at position (specified by l_pos and l_pos_unit) * in length of extracted_frames (if number of frames is exactly known) * or in length expected_frames (is a guess if l_extracted_frames < 1) * use do_progress flag value TRUE for progress feedback on the specified * progressBar. * (if progressBar = NULL gimp progress is used * this usually refers to the progress bar in the image window) * Note: * this feature is not present if compiled without GAP_ENABLE_VIDEOAPI_SUPPORT */ void gap_audio_extract_from_videofile(const char *videoname , const char *audiofile , gint32 audiotrack , const char *preferred_decoder , gint exact_seek , t_GVA_PosUnit pos_unit , gdouble pos , gdouble extracted_frames , gdouble expected_frames , gboolean do_progress , GtkWidget *progressBar , t_GVA_progress_callback_fptr fptr_progress_callback , gpointer user_data ) { t_GVA_Handle *gvahand; /* --------- OPEN the videofile --------------- */ gvahand = GVA_open_read_pref(videoname ,1 /* videotrack (not relevant for audio) */ ,audiotrack ,preferred_decoder , FALSE /* use MMX if available (disable_mmx == FALSE) */ ); if(gvahand == NULL) { printf("Could not open videofile:%s\n", videoname); return; } gvahand->image_id = -1; /* prenvent API from deleting that image at close */ gvahand->progress_cb_user_data = user_data; gvahand->fptr_progress_callback = fptr_progress_callback; /* ------ extract Audio ---------- */ if(gvahand->atracks > 0) { if (audiotrack > 0) { gdouble l_samples_to_read; gdouble extracted_frames; if(gap_debug) { printf("EXTRACTING audio, writing to file %s\n", audiofile); } if(gvahand->audio_cannels > 0) { /* seek needed only if extract starts not at pos 1 */ if(pos > 1) { p_init_progress(_("Seek Audio Position..."), do_progress, progressBar); /* check for exact frame_seek */ if (exact_seek != 0) { gint32 l_seek_framenumber; l_seek_framenumber = pos; if(pos_unit == GVA_UPOS_PRECENTAGE) { l_seek_framenumber = gvahand->total_frames * pos; } l_samples_to_read = (gdouble)(l_seek_framenumber) / (gdouble)gvahand->framerate * (gdouble)gvahand->samplerate; /* extract just for exact positioning (without save to wav file) */ if(gap_debug) { printf("extract just for exact positioning (without save to wav file)\n"); } gap_audio_extract_as_wav(audiofile , gvahand , l_samples_to_read , FALSE /* wav_save */ , do_progress , progressBar , fptr_progress_callback , user_data ); } else { /* audio pos 1 frame before video pos * example: extract frame 1 upto 2 * results in audio range 0 upto 2 * this way we can get the audioduration of frame 1 */ GVA_seek_audio(gvahand, pos -1, pos_unit); } } if(gvahand->cancel_operation) { /* stop if we were cancelled (via request from fptr_progress_callback) */ return; } p_init_progress(_("Extracting Audio..."), do_progress, progressBar); if(extracted_frames > 1) { l_samples_to_read = (gdouble)(extracted_frames +1.0) / (gdouble)gvahand->framerate * (gdouble)gvahand->samplerate; if(gap_debug) { printf("A: l_samples_to_read %.0f extracted_frames:%d\n" , (float)l_samples_to_read ,(int)extracted_frames ); } } else { l_samples_to_read = (gdouble)(expected_frames +1.0) / (gdouble)gvahand->framerate * (gdouble)gvahand->samplerate; if(gap_debug) { printf("B: l_samples_to_read %.0f extracted_frames:%d expected_frames:%d\n" ,(float)l_samples_to_read ,(int)extracted_frames ,(int)expected_frames ); } } /* extract and save to wav file */ if(gap_debug) { printf("extract (with save to wav file)\n"); } gap_audio_extract_as_wav(audiofile , gvahand , l_samples_to_read , TRUE /* wav_save */ , do_progress , progressBar , fptr_progress_callback , user_data ); } } } return; } /* end gap_audio_extract_from_videofile */ #endif gimp-gap-2.6.0+dfsg.orig/gap/gap_match.c0000644000175000017500000002564111212030253017613 0ustar thibautthibaut/* gap_match.c * 1998.10.14 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * layername and layerstacknumber matching procedures * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history: * gimp 1.3.20a; 2003/09/14 hof: gap_match_name increased limit of 256 bytes to 2048 * gimp 1.1.29b; 2000/11/30 hof: used g_snprintf * version 0.97.00 1998.10.14 hof: - created module */ #include "config.h" /* SYSTEM (UNIX) includes */ #include #include #include /* GIMP includes */ #include "libgimp/gimp.h" /* GAP includes */ #include "gap_match.h" /* --------------------------------- * gap_match_string_is_empty * --------------------------------- */ int gap_match_string_is_empty (const char *str) { if(str == NULL) return(TRUE); if(*str == '\0') return(TRUE); if(g_utf8_validate(str, -1, NULL)) { while(*str != '\0') { gunichar uni_char; uni_char = g_utf8_get_char(str); if(!g_unichar_isspace(uni_char)) return(FALSE); str = g_utf8_find_next_char(str, NULL); } return(TRUE); } while(*str != '\0') { if(*str != ' ') return(FALSE); str++; } return(TRUE); } /* end gap_match_string_is_empty */ /* --------------------------------- * gap_match_substitute_framenr * --------------------------------- * copy new_layername to buffer * and substitute [####] by curr frame number */ void gap_match_substitute_framenr (char *buffer, int buff_len, char *new_layername, long curr) { int l_idx; int l_digits; int l_cpy; char l_fmt_str[21]; gboolean utf8_compliant; const char *src_ptr; l_fmt_str[0] = '%'; l_fmt_str[1] = '0'; l_digits = 0; l_idx = 0; if(new_layername != NULL) { utf8_compliant = g_utf8_validate(new_layername, -1, NULL); while((l_idx < (buff_len-1)) && (*new_layername != '\0') ) { l_cpy = 1; switch(*new_layername) { case '[': if((new_layername[1] == '#') && (l_digits == 0)) { l_cpy = 0; l_digits = 1; } break; case '#': if(l_digits > 0) { l_cpy = 0; l_digits++; } break; case ']': if(l_digits > 0) { l_digits--; g_snprintf(&l_fmt_str[2], sizeof(l_fmt_str) -2, "%dd", l_digits); g_snprintf(&buffer[l_idx], buff_len - l_idx, l_fmt_str, (int)curr); l_idx += l_digits; l_digits = 0; l_cpy = 0; } break; default: l_digits = 0; break; } src_ptr = new_layername; if (utf8_compliant) { new_layername = g_utf8_find_next_char(new_layername, NULL); } else { new_layername++; } if(l_cpy != 0) { while(src_ptr != new_layername) { buffer[l_idx] = (*src_ptr); src_ptr++; l_idx++; } } } } buffer[l_idx] = '\0'; } /* end gap_match_substitute_framenr */ /* --------------------------------- * p_ascii_strup * --------------------------------- */ static gchar* p_ascii_strup(const gchar *input_string) { gchar *output_str; output_str = NULL; if(input_string != NULL) { gchar *str; output_str = g_strdup(input_string); str = output_str; while(*str != '\0') { *str = g_ascii_toupper(*str); str++; } } return (output_str); } /* end p_ascii_strup */ /* --------------------------------- * gap_match_number * --------------------------------- * match layer_idx (int) with pattern * pattern contains a list like that: * "0, 3-4, 7, 10" */ int gap_match_number(gint32 layer_idx, const char *pattern) { char l_digit_buff[128]; const char *l_ptr; int l_idx; gint32 l_num, l_range_start; gboolean utf8_compliant; utf8_compliant = g_utf8_validate(pattern, -1, NULL); l_idx = 0; l_num = -1; l_range_start = -1; l_ptr = pattern; while(1 == 1) { if(g_ascii_isdigit(*l_ptr)) { l_digit_buff[l_idx] = *l_ptr; /* collect digits here */ l_idx++; } else { if(l_idx > 0) { /* now we are one character past a number */ l_digit_buff[l_idx] = '\0'; l_num = atol(l_digit_buff); /* scann the number */ if(l_num == layer_idx) { return(TRUE); /* matches number exactly */ } if((l_range_start >= 0) && (layer_idx >= l_range_start) && (layer_idx <= l_num )) { return(TRUE); /* matches given range */ } l_range_start = -1; /* disable number for opening a range */ l_idx = 0; } switch(*l_ptr) { case '\0': return (FALSE); break; case ' ': case '\t': break; case ',': l_num = -1; /* disable number for opening a range */ break; case '-': if (l_num >= 0) { l_range_start = l_num; /* prev. number opens a range */ } break; default: /* found illegal characters */ /* return (FALSE); */ l_num = -1; /* disable number for opening a range */ l_range_start = -1; /* disable number for opening a range */ break; } } if(utf8_compliant) { l_ptr = g_utf8_find_next_char(l_ptr, NULL); } else { l_ptr++; } } /* end while */ return(FALSE); } /* end gap_match_number */ /* --------------------------------- * p_match_name * --------------------------------- * simple string matching. * since this procedure checks only for equal strings * it uses strcmp and strncmp regerdless if utf8 complient or not. * if dealing with utf8 compliant strings, iterating * takes care that utf8 character can have more than one byte. * * returns FALSE for non matching string */ static int p_match_name(const char *layername, const char *pattern, gint32 mode, gboolean utf8_compliant) { int l_llen; int l_plen; const char *uni_ptr; switch (mode) { case GAP_MTCH_EQUAL: if (0 == strcmp(layername, pattern)) { return(TRUE); } break; case GAP_MTCH_START: l_plen = strlen(pattern); if (0 == strncmp(layername, pattern, l_plen)) { return(TRUE); } break; case GAP_MTCH_END: case GAP_MTCH_ANYWHERE: l_llen = strlen(layername); l_plen = strlen(pattern); uni_ptr = layername; while (l_llen >= l_plen) { /* printf("GAP_MTCH :%s: llen:%d \n", uni_ptr, (int)l_llen); */ if((l_llen == l_plen) || (mode == GAP_MTCH_ANYWHERE)) { if(0 == strncmp(uni_ptr, pattern, l_plen)) { return(TRUE); } } if(utf8_compliant) { uni_ptr = g_utf8_find_next_char(uni_ptr, NULL); } else { uni_ptr++; } l_llen = strlen(uni_ptr); } break; default: break; } return (FALSE); } /* end p_match_name */ /* --------------------------------- * gap_match_name * --------------------------------- * simple stringmatching without wildcards * return TRUE if layername matches pattern according to specified mode * NULL pointers never match (even if compared with NULL) */ int gap_match_name(const char *layername, const char *pattern, gint32 mode, gint32 case_sensitive) { int l_rc; const gchar *l_name_ptr; const gchar *l_patt_ptr; gchar *l_name_buff; gchar *l_patt_buff; gboolean utf8_compliant; if(pattern == NULL) return (FALSE); if(layername == NULL) return (FALSE); l_name_buff = NULL; l_patt_buff = NULL; /* check utf8 compliance for both layername and pattern */ utf8_compliant = FALSE; if(g_utf8_validate(layername, -1, NULL)) { utf8_compliant = g_utf8_validate(pattern, -1, NULL); } if(case_sensitive) { /* case sensitive can compare on the originals */ l_name_ptr = layername; l_patt_ptr = pattern; } else { if(utf8_compliant) { /* ignore case by converting everything to UPPER before compare */ l_name_buff = g_utf8_strup(layername, -1); l_patt_buff = g_utf8_strup(pattern, -1); } else { l_name_buff = p_ascii_strup(layername); l_patt_buff = p_ascii_strup(pattern); } l_name_ptr = l_name_buff; l_patt_ptr = l_patt_buff; } l_rc = p_match_name(l_name_ptr, l_patt_ptr, mode, utf8_compliant); if(l_name_buff) { g_free(l_name_buff); } if(l_patt_buff) { g_free(l_patt_buff); } return (l_rc); } /* end gap_match_name */ /* --------------------------------- * gap_match_layer * --------------------------------- */ int gap_match_layer(gint32 layer_idx, const char *layername, const char *pattern, gint32 mode, gint32 case_sensitive, gint32 invert, gint nlayers, gint32 layer_id) { int l_rc; switch(mode) { case GAP_MTCH_NUMBERLIST: l_rc = gap_match_number(layer_idx, pattern); break; case GAP_MTCH_INV_NUMBERLIST: l_rc = gap_match_number((nlayers -1) - layer_idx, pattern); break; case GAP_MTCH_ALL_VISIBLE: l_rc = gimp_drawable_get_visible(layer_id); break; default: l_rc = gap_match_name(layername, pattern, mode, case_sensitive); break; } if(invert == TRUE) { if(l_rc == FALSE) { return(TRUE); } return(FALSE); } return (l_rc); } /* end gap_match_layer */ gimp-gap-2.6.0+dfsg.orig/gap/gap_player_cache.c0000644000175000017500000006460011212030253021134 0ustar thibautthibaut/* gap_player_cache.c * * This module handles frame caching for GAP video playback * */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* revision history: * version 2.2.1; 2006/05/22 hof: created */ /* The player cache structure overview: * oldest frames are at end of list, most recent accessed at start. * * HashTable: * +---------------+ * | key, elem_ptr |------------------------+ * +---------------+ | * | key, elem_ptr |------------+ | * +---------------+ | | * | key, elem_ptr | | | * +---------------+ | | * | key, elem_ptr |--+ | | * +---------------+ | | | * | | | +--------- end_elem * | | | | * List: V V V V * +-----+ +-----+ +-----+ * start_elem: ---->| next|---->| next|---->| next|-->NULL * | | | | | | * NULL<---|prev |<----|prev |<----|prev | CacheElem * +-----+ +-----+ +-----+ * | | | * | cdata | cdata | cdata * | | | * V V V * +-----+ +-----+ +-----+ * | | | | | | CacheData * | | | | | | * | | | | | | * +-----+ +-----+ +-----+ * * * Example of the cache behaviour: * (The example assumes that the cache maximum size is configured * to hold a maximal 5 frames) * * * Operation List Remarks * --------------------------------------------------------------------------------- * * add(1) 1 * add(2) 2 1 * add(3) 3 2 1 * add(4) 4 3 2 1 * add(5) 5 4 3 2 1 * add(A) A 5 4 3 2 (delete (1) to free resources for adding A) * add(B) B A 5 4 3 (delete (2) to free resources for adding B) * lookup(A) A B 5 4 3 (FOUND, relink A as first element) * lookup(1) A B 5 4 3 (NOT FOUND, no change in the list) * add(5) 5 A B 4 3 (relink 5 as first element, but ignore adding 5 a 2nd time) * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "gap_libgapbase.h" #include "gap_player_main.h" #include "gap_player_dialog.h" #include "gap-intl.h" extern int gap_debug; /* 1 == print debug infos , 0 dont print debug infos */ // local debug setting //static gint gap_debug = 1; /* 1 == print debug infos , 0 dont print debug infos */ typedef struct GapPlayerCacheElem { gchar *ckey; GapPlayerCacheData *cdata; void *next; void *prev; } GapPlayerCacheElem; typedef struct GapPlayerCacheAdmin { /* nick: admin_ptr */ GapPlayerCacheElem *start_elem; /* recently accessed element */ GapPlayerCacheElem *end_elem; /* last list elem (access long ago) */ gint32 summary_bytesize; gint32 configured_max_bytesize; GHashTable *pcache_elemref_hash; } GapPlayerCacheAdmin; static GapPlayerCacheAdmin *global_pca_ptr = NULL; static GapPlayerCacheAdmin* p_get_admin_ptr(void); static void p_debug_printf_cache_list(GapPlayerCacheAdmin *admin_ptr); static void p_debug_printf_cdata(GapPlayerCacheData *cdata); static void p_player_cache_shrink(GapPlayerCacheAdmin *admin_ptr, gint32 new_bytesize); static void p_player_cache_remove_oldest_frame(GapPlayerCacheAdmin *admin_ptr); static void p_free_elem(GapPlayerCacheElem *delete_elem_ptr); static void p_player_cache_add_new_frame(GapPlayerCacheAdmin *admin_ptr , GapPlayerCacheElem *new_elem_ptr); static void p_relink_as_first_elem(GapPlayerCacheAdmin *admin_ptr , GapPlayerCacheElem *elem_ptr); static GapPlayerCacheElem* p_new_elem(const gchar *ckey , GapPlayerCacheData *cdata); /* ------------------------------ * p_get_admin_ptr * ------------------------------ */ static GapPlayerCacheAdmin* p_get_admin_ptr(void) { if (global_pca_ptr == NULL) { GapPlayerCacheAdmin *admin_ptr; global_pca_ptr = g_new(GapPlayerCacheAdmin, 1); admin_ptr = global_pca_ptr; admin_ptr->start_elem = NULL; admin_ptr->end_elem = NULL; admin_ptr->summary_bytesize = 0; admin_ptr->configured_max_bytesize = GAP_PLAYER_CACHE_DEFAULT_MAX_BYTESIZE; /* use NULL to skip destructor for the ckey * because the ckey is also part of the value * (and therefore freed via the value destuctor procedure p_free_elem) */ admin_ptr->pcache_elemref_hash = g_hash_table_new_full(g_str_hash , g_str_equal , NULL , (GDestroyNotify) p_free_elem ); if(gap_debug) { printf("p_get_admin_ptr: %d\n", (int)global_pca_ptr); } } return (global_pca_ptr); } /* end p_init_admin */ /* ------------------------------ * p_debug_printf_cdata * ------------------------------ */ static void p_debug_printf_cdata(GapPlayerCacheData *cdata) { printf(" cdata compression: %d, size:%d, th_data:%d, width:%d, height:%d, bpp:%d\n" , (int)cdata->compression , (int)cdata->th_data_size , (int)cdata->th_data , (int)cdata->th_width , (int)cdata->th_height , (int)cdata->th_bpp ); } /* end p_debug_printf_cdata */ /* ------------------------------ * p_debug_printf_cache_list * ------------------------------ */ static void p_debug_printf_cache_list(GapPlayerCacheAdmin *admin_ptr) { GapPlayerCacheElem *elem_ptr; GapPlayerCacheElem *prev_elem_ptr; gint ii; printf("\np_debug_printf_cache_list: START start_elem:%d, end_elem:%d\n" ,(int)admin_ptr->start_elem ,(int)admin_ptr->end_elem ); ii = 0; prev_elem_ptr = NULL; elem_ptr = admin_ptr->start_elem; while(elem_ptr != NULL) { printf("elem_ptr[%03d]: %d ckey: <%s> prev:%d next:%d\n" , (int)ii , (int)elem_ptr , elem_ptr->ckey , (int)elem_ptr->prev , (int)elem_ptr->next ); ii++; if (elem_ptr->next == prev_elem_ptr) { printf("**** internal ERROR cache list is not properly linked !\n"); break; } prev_elem_ptr = elem_ptr; elem_ptr = (GapPlayerCacheElem *)elem_ptr->next; if(elem_ptr == admin_ptr->start_elem) { printf("** internal ERROR cache list is not properly linked !\n"); break; } } printf("p_debug_printf_cache_list: END\n"); } /* end p_debug_printf_cache_list */ /* --------------------------------- * gap_player_cache_set_max_bytesize * --------------------------------- */ void gap_player_cache_set_max_bytesize(gint32 max_bytesize) { GapPlayerCacheAdmin *admin_ptr; admin_ptr = p_get_admin_ptr(); if(admin_ptr) { admin_ptr->configured_max_bytesize = max_bytesize; p_player_cache_shrink(admin_ptr, 0); if (gap_debug) { printf("gap_player_cache_set_max_bytesize: max_player_cache: %d bytes (approximative frames: %d)\n" , (int)max_bytesize , (int)max_bytesize/ GAP_PLAYER_CACHE_FRAME_SZIE ); } } } /* end gap_player_cache_set_max_bytesize */ /* ----------------------------------------- * gap_player_cache_get_max_bytesize * ----------------------------------------- */ gint32 gap_player_cache_get_max_bytesize(void) { GapPlayerCacheAdmin *admin_ptr; gint32 bytesize; bytesize = 0; admin_ptr = p_get_admin_ptr(); if(admin_ptr) { bytesize = admin_ptr->configured_max_bytesize; } return (bytesize); } /* end gap_player_cache_get_max_bytesize */ /* ----------------------------------------- * gap_player_cache_get_current_bytes_used * ----------------------------------------- */ gint32 gap_player_cache_get_current_bytes_used(void) { GapPlayerCacheAdmin *admin_ptr; gint32 bytesize; bytesize = 0; admin_ptr = p_get_admin_ptr(); if(admin_ptr) { bytesize = admin_ptr->summary_bytesize; } return (bytesize); } /* end gap_player_cache_get_current_bytes_used */ /* ------------------------------------------ * gap_player_cache_get_current_frames_cached * ------------------------------------------ */ gint32 gap_player_cache_get_current_frames_cached(void) { GapPlayerCacheAdmin *admin_ptr; gint32 elem_counter; elem_counter = 0; admin_ptr = p_get_admin_ptr(); if(admin_ptr) { elem_counter = g_hash_table_size(admin_ptr->pcache_elemref_hash); } return (elem_counter); } /* end gap_player_cache_get_current_frames_cached */ /* ------------------------------------ * gap_player_cache_get_gimprc_bytesize * ------------------------------------ */ gint32 gap_player_cache_get_gimprc_bytesize(void) { gint32 bytesize; gchar *value_string; value_string = gimp_gimprc_query("video_playback_cache"); if(value_string) { char *ptr; bytesize = atol(value_string); for(ptr=value_string; *ptr != '\0'; ptr++) { if ((*ptr == 'M') || (*ptr == 'm')) { bytesize *= (1024 * 1024); break; } if ((*ptr == 'K') || (*ptr == 'k')) { bytesize *= 1024; break; } } if (bytesize < GAP_PLAYER_CACHE_FRAME_SZIE) { /* turns OFF the cache */ bytesize = 0; } g_free(value_string); } else { /* nothing configured in gimprc file * use cache with default size. */ bytesize = GAP_PLAYER_CACHE_DEFAULT_MAX_BYTESIZE; } return (bytesize); } /* end gap_player_cache_get_gimprc_bytesize */ /* ------------------------------------ * gap_player_cache_set_gimprc_bytesize * ------------------------------------ */ void gap_player_cache_set_gimprc_bytesize(gint32 bytesize) { gint32 kbsize; gint32 mbsize; gchar *value_string; kbsize = bytesize / 1024; mbsize = kbsize / 1024; value_string = NULL; if ((kbsize * 1024) != mbsize) { /* store as kilobytes to keep precision */ value_string = g_strdup_printf("%dK", kbsize); } else { /* store as megabytes (value was not truncated by integer division) */ value_string = g_strdup_printf("%dM", mbsize); } gimp_gimprc_set("video_playback_cache", value_string); g_free(value_string); } /* end gap_player_cache_set_gimprc_bytesize */ /* ------------------------------ * p_get_elem_size * ------------------------------ */ static gint32 p_get_elem_size(GapPlayerCacheElem *elem_ptr) { gint32 bytesize; bytesize = 0; if(elem_ptr) { if(elem_ptr->cdata) { bytesize = elem_ptr->cdata->th_data_size; } if(elem_ptr->ckey) { bytesize += strlen(elem_ptr->ckey); } bytesize += (sizeof(GapPlayerCacheElem) + sizeof(GapPlayerCacheData)); } return(bytesize); } /* end p_get_elem_size */ /* ------------------------------ * p_relink_as_first_elem * ------------------------------ * PRECONDITION: * elem_ptr MUST be already linked somewhere in the list. */ static void p_relink_as_first_elem(GapPlayerCacheAdmin *admin_ptr , GapPlayerCacheElem *elem_ptr) { if (admin_ptr->start_elem != elem_ptr) { /* relink elem_ptr as first element in the list. */ GapPlayerCacheElem *prev; GapPlayerCacheElem *next; prev = (GapPlayerCacheElem *)elem_ptr->prev; next = (GapPlayerCacheElem *)elem_ptr->next; if(prev) { prev->next = next; } if(next) { next->prev = prev; } admin_ptr->start_elem->prev = elem_ptr; elem_ptr->next = admin_ptr->start_elem; elem_ptr->prev = NULL; admin_ptr->start_elem = elem_ptr; if(elem_ptr == admin_ptr->end_elem) { admin_ptr->end_elem = prev; } } } /* end p_relink_as_first_elem */ /* ------------------------------ * p_new_elem * ------------------------------ */ static GapPlayerCacheElem* p_new_elem(const gchar *ckey , GapPlayerCacheData *cdata) { GapPlayerCacheElem *elem_ptr; elem_ptr = g_new ( GapPlayerCacheElem, 1 ); elem_ptr->ckey = g_strdup(ckey); elem_ptr->cdata = cdata; elem_ptr->next = NULL; elem_ptr->prev = NULL; return (elem_ptr); } /* end p_new_elem */ /* ------------------------------ * gap_player_cache_free_all * ------------------------------ * free up the player cache. (all cached frames and internal datastructures) * */ void gap_player_cache_free_all(void) { GapPlayerCacheAdmin *admin_ptr; admin_ptr = p_get_admin_ptr(); if(gap_debug) { printf("gap_player_cache_free_all: %d\n", (int)admin_ptr); } if(admin_ptr) { while(admin_ptr->start_elem) { p_player_cache_remove_oldest_frame(admin_ptr); } g_hash_table_destroy(admin_ptr->pcache_elemref_hash); global_pca_ptr = NULL; g_free(admin_ptr); } } /* end gap_player_cache_free_all */ /* ---------------------------------- * p_player_cache_shrink * ---------------------------------- * check if size is greater than configured maximum * and free up that much elements to shrink memory usage * until fit to configured maximum */ static void p_player_cache_shrink(GapPlayerCacheAdmin *admin_ptr, gint32 new_bytesize) { while(admin_ptr->start_elem != NULL) { // debug limit cache to 5 elements for testing // if(g_hash_table_size(admin_ptr->pcache_elemref_hash) < 5) if((admin_ptr->summary_bytesize + new_bytesize) < admin_ptr->configured_max_bytesize) { if(gap_debug) { printf("p_player_cache_shrink: SPACE OK %d\n", (int)admin_ptr->summary_bytesize); } break; /* we are below the limit, no need to delete frames */ } p_player_cache_remove_oldest_frame(admin_ptr); } } /* end p_player_cache_shrink */ /* ---------------------------------- * p_player_cache_remove_oldest_frame * ---------------------------------- */ void p_player_cache_remove_oldest_frame(GapPlayerCacheAdmin *admin_ptr) { GapPlayerCacheElem *delete_elem_ptr; delete_elem_ptr = admin_ptr->end_elem; if (delete_elem_ptr) { if(gap_debug) { printf("p_player_cache_remove_oldest_frame: delete_elem_ptr: %d ckey: <%s> \n" , (int)delete_elem_ptr ,delete_elem_ptr->ckey ); } admin_ptr->summary_bytesize -= p_get_elem_size(delete_elem_ptr); /* unlink from the list */ admin_ptr->end_elem = delete_elem_ptr->prev; if (admin_ptr->end_elem) { admin_ptr->end_elem->next = NULL; } else { /* there is no previous element any more, * have to reset start pointer */ admin_ptr->start_elem = NULL; } /* remove the reference from the hash table * (this also calls destructors to free the deleted list element too) */ g_hash_table_remove(admin_ptr->pcache_elemref_hash, delete_elem_ptr->ckey); } } /* end p_player_cache_remove_oldest_frame */ /* ------------------------------ * p_free_elem * ------------------------------ */ static void p_free_elem(GapPlayerCacheElem *delete_elem_ptr) { if(delete_elem_ptr == NULL) { return; } if(gap_debug) { printf("p_free_elem: delete_elem_ptr: %d, ckey: %d, cdata:%d" ,(int)delete_elem_ptr ,(int)delete_elem_ptr->ckey ,(int)delete_elem_ptr->cdata ); if(delete_elem_ptr->ckey) { printf(" ckey_string <%s>" ,delete_elem_ptr->ckey ); } printf("\n"); } g_free(delete_elem_ptr->ckey); gap_player_cache_free_cdata(delete_elem_ptr->cdata); g_free(delete_elem_ptr); } /* end p_free_elem */ /* ------------------------------ * p_player_cache_add_new_frame * ------------------------------ * the new element is added as 1.st element to the cache list. * a reference to its address is stored in the hash table. * and the summary_bytesize is updated (increased). */ static void p_player_cache_add_new_frame(GapPlayerCacheAdmin *admin_ptr , GapPlayerCacheElem *new_elem_ptr) { if(gap_debug) { printf("p_player_cache_add_new_frame START\n"); } if(admin_ptr->start_elem) { admin_ptr->start_elem->prev = new_elem_ptr; } new_elem_ptr->next = admin_ptr->start_elem; new_elem_ptr->prev = NULL; admin_ptr->start_elem = new_elem_ptr; if(admin_ptr->end_elem == NULL) { admin_ptr->end_elem = new_elem_ptr; } admin_ptr->summary_bytesize += p_get_elem_size(new_elem_ptr); /* the adress of the newly added list element * is stored with the same ckey in a hash table. */ g_hash_table_insert(admin_ptr->pcache_elemref_hash ,new_elem_ptr->ckey ,new_elem_ptr ); if(gap_debug) { guint elem_counter; if(1==0) { p_debug_printf_cache_list(admin_ptr); } printf("p_player_cache_add_new_frame END\n\n"); elem_counter = g_hash_table_size(admin_ptr->pcache_elemref_hash); printf("\n # frames cached: %d bytes_used:%d max_bytesize:%d percent:%03.2f\n" , (int)elem_counter , (int)admin_ptr->summary_bytesize , (int)admin_ptr->configured_max_bytesize , (float) 100.0 * ((float)admin_ptr->summary_bytesize / (float)MAX(1, admin_ptr->configured_max_bytesize)) ); printf("p_player_cache_add_new_frame END\n\n"); } } /* end p_player_cache_add_new_frame */ /* ------------------------------ * gap_player_cache_lookup * ------------------------------ * search the players frame cache for the frame with * the specified ckey. * return the corresponding frame data struct if found * or NULL if not found. * * NOTE: the returned cdata is for read only use * AND MUST NOT BE FREED ! * * Typically the caller shall use the rturned cdata as input * for the procedure gap_player_cache_decompress, to obtain * the (uncompressed) workcopy of the frame data. */ GapPlayerCacheData* gap_player_cache_lookup(const gchar *ckey) { GapPlayerCacheElem *elem_ptr; GapPlayerCacheAdmin *admin_ptr; if(ckey == NULL) { return (NULL); } admin_ptr = p_get_admin_ptr(); elem_ptr = (GapPlayerCacheElem *) g_hash_table_lookup (admin_ptr->pcache_elemref_hash, ckey); if (elem_ptr != NULL) { p_relink_as_first_elem(admin_ptr, elem_ptr); if(gap_debug) { printf("gap_player_cache_lookup FOUND in player cache ckey:<%s>\n", ckey); //p_debug_printf_cdata(elem_ptr->cdata); } return (elem_ptr->cdata); } if(gap_debug) { printf("gap_player_cache_lookup NOT FOUND in player cache ckey:<%s>\n", ckey); } return (NULL); } /* end gap_player_cache_lookup */ /* ------------------------------ * gap_player_cache_insert * ------------------------------ * insert the specified frame ckey and data into the player frame cache. * NOTE: this procedure does lookup if the ckey is already in the cache * and does not insert the same ckey more than once. * if the configured maximum chache limit is exceeded, one or more frames * in the cache are removed (to free up memory for the new frame). * * The current implementation removes (old) elements from the end of the * internal cache list, and adds new elements at the start of the list. * (read access re-links the accessed element as 1.st element) * */ void gap_player_cache_insert(const gchar *ckey , GapPlayerCacheData *cdata) { GapPlayerCacheAdmin *admin_ptr; gint32 new_bytesize; GapPlayerCacheElem *new_elem_ptr; if((ckey == NULL) || (cdata == NULL)) { return; } if(gap_debug) { printf("gap_player_cache_insert: ckey:<%s>\n", ckey); p_debug_printf_cdata(cdata); } if(gap_player_cache_lookup(ckey) != NULL) { if(gap_debug) { printf("gap_player_cache_insert: INSERT REJECTED! ckey:<%s> \n", ckey); } return; } new_elem_ptr = p_new_elem(ckey, cdata); new_bytesize = p_get_elem_size(new_elem_ptr); admin_ptr = p_get_admin_ptr(); p_player_cache_shrink(admin_ptr, new_bytesize); p_player_cache_add_new_frame(admin_ptr, new_elem_ptr); } /* end gap_player_cache_insert */ /* ------------------------------ * gap_player_cache_decompress * ------------------------------ * return the decompressed RGB buffer (th_data) * (for uncompressed frames this is just a copy of the chaced data) * The caller is responsible to g_free the returned data after use. */ guchar* gap_player_cache_decompress(GapPlayerCacheData *cdata) { guchar *th_data; th_data = NULL; if (cdata->compression == GAP_PLAYER_CACHE_COMPRESSION_NONE) { th_data = g_new ( guchar, cdata->th_data_size ); memcpy(th_data, cdata->th_data, cdata->th_data_size); if(gap_debug) { printf("gap_player_cache_decompress: th_data:%d size:%d, cdata->th_data: %d\n" , (int)th_data , (int)cdata->th_data_size , (int)cdata->th_data ); } } else { printf("** ERROR: player chache compression not implemented yet.\n"); } return (th_data); } /* end gap_player_cache_decompress */ /* ------------------------------ * gap_player_cache_new_data * ------------------------------ * create and set up a new player chache data stucture. * NOTE: The th_data is NOT copied but used as 1:1 reference * in case no compression is done. * comression (not implemented yet) will create * a compressed copy of th_data (that is put into the newly created * GapPlayerCacheData structure, and g_free th_data after the compression. */ GapPlayerCacheData* gap_player_cache_new_data(guchar *th_data , gint32 th_size , gint32 th_width , gint32 th_height , gint32 th_bpp , GapPlayerCacheCompressionType compression , gint32 flip_status ) { GapPlayerCacheData* cdata; cdata = g_new ( GapPlayerCacheData, 1 ); cdata->compression = compression; cdata->th_data_size = th_size; cdata->th_width = th_width; cdata->th_height = th_height; cdata->th_bpp = th_bpp; cdata->flip_status = flip_status; if (compression == GAP_PLAYER_CACHE_COMPRESSION_NONE) { cdata->th_data = th_data; } else { printf("** ERROR: player chache compression not implemented yet.\n"); cdata->compression = GAP_PLAYER_CACHE_COMPRESSION_NONE; cdata->th_data = th_data; } return (cdata); } /* end gap_player_cache_new_data */ /* ------------------------------ * gap_player_cache_free_cdata * ------------------------------ */ void gap_player_cache_free_cdata(GapPlayerCacheData *cdata) { if(cdata) { if(cdata->th_data) { g_free(cdata->th_data); } g_free(cdata); } } /* end gap_player_cache_free_cdata */ /* ------------------------------ * gap_player_cache_new_movie_key * ------------------------------ */ gchar * gap_player_cache_new_movie_key(const char *filename , gint32 framenr , gint32 seltrack , gdouble delace ) { char *ckey; char *abs_filename; abs_filename = gap_file_build_absolute_filename(filename); ckey = g_strdup_printf("[@MOVIE]:%d:%s:%06d:%d:%1.3f" , (int)gap_file_get_mtime(filename) , abs_filename , (int)framenr , (int)seltrack , (float)delace ); g_free(abs_filename); return (ckey); } /* end gap_player_cache_new_movie_key */ /* ------------------------------ * gap_player_cache_new_image_key * ------------------------------ */ gchar* gap_player_cache_new_image_key(const char *filename) { char *ckey; char *abs_filename; abs_filename = gap_file_build_absolute_filename(filename); ckey = g_strdup_printf("[@IMAGE]:%d:%s" , (int)gap_file_get_mtime(filename) , abs_filename ); g_free(abs_filename); return (ckey); } /* end gap_player_cache_new_image_key */ /* ------------------------------ * gap_player_cache_new_composite_video_key * ------------------------------ * type: use 0 when playback the full full storyboard, 1 for partial playback * version: internal counter (increased each time the storyboard is changed in the edit dialog) */ gchar* gap_player_cache_new_composite_video_key(const char *filename , gint32 framenr , gint32 type , gint32 version ) { char *ckey; char *abs_filename; abs_filename = gap_file_build_absolute_filename(filename); ckey = g_strdup_printf("[@COMPOSITE]:%06d:%d:%04d:%s" , (int)framenr , (int)type , (int)version , abs_filename ); g_free(abs_filename); return (ckey); } /* end gap_player_cache_new_composite_video_key */ gimp-gap-2.6.0+dfsg.orig/gap/gap_decode_mplayer.c0000644000175000017500000014142611212030253021473 0ustar thibautthibaut/* gap_decode_mplayer.c * 2004.12.06 hof (Wolfgang Hofer) * * GAP ... Gimp Animation Plugins * * This Module contains: * * GIMP/GAP-frontend interface for mplayer * Calls mplayer to split any mplayer supported video into * video frames (single images on disk) * Audio can also be extracted. * * mplayer exporting edition is available at: * Web: http://www.mplayerhq.hu/homepage/design7/news.html * * Warning: This Module needs UNIX environment to run. * It uses programs and commands that are NOT available * on other Operating Systems (Win95, NT, XP ...) * * - mplayer MPlayer 1.0pre5 or MPlayer 1.0pre7 * (the best mediaplayer for linux) * set environment GAP_MPLAYER_PROG to configure where to find mplayer * (default: search mplayer in your PATH) * - cd (UNIX command) * - rm (UNIX command is used to delete by wildcard (expanded by /bin/sh) * and to delete a directory with all files */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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. */ /* revision history * gimp-gap 2.1; 2005/05/22 hof: support MPlayer1.0pre7 (has new calling options) * gimp-gap 2.1; 2004/11/29 hof: created */ /* * Here is a list of the mplayer 1.0 extracting related options * that were used in this frontend. * Please Note: Options changed incompatible from 1.0pre5 to 1.0pre7 release, * the old MPlayer1.0pre5 options can be selected via dialog. * * -ss