home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / gap / gap_decode_xanim.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-10  |  34.2 KB  |  1,204 lines

  1. /* gap_decode_xanim.c
  2.  * 1999.11.22 hof (Wolfgang Hofer)
  3.  *
  4.  * GAP ... Gimp Animation Plugins
  5.  *
  6.  * This Module contains:
  7.  *
  8.  *        GIMP/GAP-frontend interface for XANIM exporting edition from loki entertainmaint
  9.  *         Call xanim exporting edition (the loki version)
  10.  *         To split any xanim supported video into
  11.  *         anim frames (single images on disk)
  12.  *         Audio can also be extracted.
  13.  *
  14.  *        xanim  exporting edition is available at:
  15.  *            Web:        http://heroine.linuxbox.com/toys.html
  16.  *                        http://www.lokigames.com/development/smjpeg.php3
  17.  *            download:   http://heroine.linuxbox.com/xanim_exporting_edition.tar.gz
  18.  *                        http://www.lokigames.com/development/download/smjpeg/xanim2801-loki090899.tar.gz
  19.  *            Send comments or questions to smjpeg@lokigames.com.
  20.  *
  21.  * Warning: This Module needs UNIX environment to run.
  22.  *   It uses programs and commands that are NOT available
  23.  *   on other Operating Systems (Win95, NT ...)
  24.  *
  25.  *     - xanim              2.80 exporting edition with extensions from loki entertainment.
  26.  *                          set environment GAP_XANIM_PROG to configure where to find xanim
  27.  *                          (default: search xanim in your PATH)
  28.  *     - grep               (UNIX command)
  29.  *     - rm                 (UNIX command is used to delete by wildcard (expanded by /bin/sh)
  30.  *                                and to delete a directory with all files
  31.  */
  32. /* The GIMP -- an image manipulation program
  33.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  34.  *
  35.  * This program is free software; you can redistribute it and/or modify
  36.  * it under the terms of the GNU General Public License as published by
  37.  * the Free Software Foundation; either version 2 of the License, or
  38.  * (at your option) any later version.
  39.  *
  40.  * This program is distributed in the hope that it will be useful,
  41.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  42.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  43.  * GNU General Public License for more details.
  44.  *
  45.  * You should have received a copy of the GNU General Public License
  46.  * along with this program; if not, write to the Free Software
  47.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  48.  */
  49.  
  50. /* revision history
  51.  * 1.1.29b;  2000/11/30  hof: used g_snprintf
  52.  * 1.1.17b;  2000/02/26  hof: bugfixes
  53.  * 1.1.14a;  1999/11/22  hof: fixed gcc warning (too many arguments for format)
  54.  * 1.1.13a;  1999/11/22  hof: first release
  55.  */
  56.  
  57. /* SYTEM (UNIX) includes */ 
  58. #include <stdio.h>
  59. #include <stdlib.h>
  60. #include <string.h>
  61. #include <sys/types.h>
  62. #include <signal.h>
  63. #include <sys/stat.h>
  64. #include <unistd.h>
  65.  
  66. /* GIMP includes */
  67. #include "gtk/gtk.h"
  68. #include "config.h"
  69. #include "libgimp/stdplugins-intl.h"
  70. #include "libgimp/gimp.h"
  71.  
  72. #ifdef G_OS_WIN32
  73. #include <io.h>
  74. #  ifndef S_ISDIR
  75. #    define S_ISDIR(m) ((m) & _S_IFDIR)
  76. #  endif
  77. #  ifndef S_ISREG
  78. #    define S_ISREG(m) ((m) & _S_IFREG)
  79. #  endif
  80. #endif
  81.  
  82. /* GAP includes */
  83. #include "gap_lib.h"
  84. #include "gap_arr_dialog.h"
  85. #include "gap_decode_xanim.h"
  86.  
  87. extern      int gap_debug; /* ==0  ... dont print debug infos */
  88.  
  89. static char *global_xanim_input_dir    = "input";
  90.  
  91. gchar global_xanim_prog[500];
  92. gchar *global_errlist = NULL;
  93.  
  94. gint32  global_delete_number;
  95.  
  96. #define MKDIR_MODE (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH )
  97.  
  98. /* ============================================================================
  99.  * p_xanim_info
  100.  * ============================================================================
  101.  */
  102. static int
  103. p_xanim_info(char *errlist)
  104. {
  105.   t_arr_arg  argv[20];
  106.   t_but_arg  b_argv[2];
  107.  
  108.   int        l_idx;
  109.   int        l_rc;
  110.   
  111.  
  112.   l_idx = 0;
  113.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  114.   argv[l_idx].label_txt = _("Conditions to run the xanim based video split");
  115.  
  116.   l_idx++;
  117.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  118.   argv[l_idx].label_txt = "";
  119.  
  120.   l_idx++;
  121.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  122.   argv[l_idx].label_txt = _("1.) xanim 2.80.0 exporting edition (the loki version)");
  123.  
  124.   l_idx++;
  125.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  126.   argv[l_idx].label_txt = _("    must be installed somewhere in your PATH");
  127.  
  128.   l_idx++;
  129.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  130.   argv[l_idx].label_txt = _("    you can get xanim exporting edition at");
  131.  
  132.   l_idx++;
  133.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  134.   argv[l_idx].label_txt = "    http://heroine.linuxbox.com/toys.html";
  135.  
  136.   l_idx++;
  137.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  138.   argv[l_idx].label_txt = "    http://www.lokigames.com/development/download/smjpeg/xanim2801-loki090899.tar.gz";
  139.  
  140.   l_idx++;
  141.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  142.   argv[l_idx].label_txt = "";
  143.  
  144.   l_idx++;
  145.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  146.   argv[l_idx].label_txt = _("2.) if your xanim exporting edition is not in your PATH or is not named xanim");
  147.  
  148.   l_idx++;
  149.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  150.   argv[l_idx].label_txt = _("    you have to set Environment variable GAP_XANIM_PROG ");
  151.  
  152.   l_idx++;
  153.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  154.   argv[l_idx].label_txt = _("    to your xanim exporting program and restart gimp");
  155.  
  156.   l_idx++;
  157.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  158.   argv[l_idx].label_txt = "";
  159.  
  160.   l_idx++;
  161.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  162.   argv[l_idx].label_txt = _("An ERROR occured while trying to call xanim:");  
  163.  
  164.   l_idx++;
  165.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  166.   argv[l_idx].label_txt = "--------------------------------------------";  
  167.  
  168.  
  169.   l_idx++;
  170.   p_init_arr_arg(&argv[l_idx], WGT_LABEL_LEFT);
  171.   argv[l_idx].label_txt = errlist;
  172.  
  173.   l_idx++;
  174.  
  175.   /* the  Action Button */
  176.     b_argv[0].but_txt  = _("Cancel");
  177.     b_argv[0].but_val  = -1;
  178.     b_argv[1].but_txt  = _("OK");
  179.     b_argv[1].but_val  = 0;
  180.   
  181.   l_rc = p_array_std_dialog(_("XANIM Information"),
  182.                              "",
  183.                               l_idx,   argv,      /* widget array */
  184.                               1,       b_argv,    /* button array */
  185.                               -1);
  186.  
  187.   return (l_rc); 
  188. }    /* end p_xanim_info */
  189.  
  190.  
  191. /* ============================================================================
  192.  * p_xanim_dialog
  193.  * ============================================================================
  194.  */
  195. static int
  196. p_xanim_dialog   (gint32 *first_frame,
  197.                   gint32 *last_frame,
  198.           char   *filename,
  199.           gint32 len_filename,
  200.           char   *basename,
  201.           gint32 len_basename,
  202.           t_gap_xa_formats *Format,
  203.           gint32  *extract_video,
  204.           gint32  *extract_audio,
  205.           gint32  *jpeg_quality,
  206.           gint32  *autoload,
  207.           gint32  *run_xanim_asynchron)
  208. {
  209. #define XADIALOG_NUM_ARGS 12
  210.   static t_arr_arg  argv[XADIALOG_NUM_ARGS];
  211.   static char *radio_args[3]  = { "XCF", "PPM", "JPEG" };
  212.  
  213.   p_init_arr_arg(&argv[0], WGT_FILESEL);
  214.   argv[0].label_txt = _("Video:");
  215.   argv[0].help_txt  = _("Name of a videofile to READ by xanim.\n"
  216.                         "Frames are extracted from the videofile\n"
  217.             "and written to seprate diskfiles.\n"
  218.             "xanim exporting edition is required.");
  219.   argv[0].text_buf_len = len_filename;
  220.   argv[0].text_buf_ret = filename;
  221.   argv[0].entry_width = 250;
  222.  
  223.   p_init_arr_arg(&argv[1], WGT_INT_PAIR);
  224.   argv[1].label_txt = _("From:");
  225.   argv[1].help_txt  = _("Framenumber of 1st frame to extract");
  226.   argv[1].constraint = FALSE;
  227.   argv[1].int_min    = 0;
  228.   argv[1].int_max    = 9999;
  229.   argv[1].int_ret    = 0;
  230.   argv[1].umin       = 0;
  231.   argv[1].entry_width = 80;
  232.   
  233.   p_init_arr_arg(&argv[2], WGT_INT_PAIR);
  234.   argv[2].label_txt = _("To:");
  235.   argv[2].help_txt  = _("Framenumber of last frame to extract");
  236.   argv[2].constraint = FALSE;
  237.   argv[2].int_min    = 0;
  238.   argv[2].int_max    = 9999;
  239.   argv[2].int_ret    = 9999;
  240.   argv[2].umin       = 0;
  241.   argv[2].entry_width = 80;
  242.   
  243.   p_init_arr_arg(&argv[3], WGT_FILESEL);
  244.   argv[3].label_txt = _("Framenames:");
  245.   argv[3].help_txt  = _("Basename for the AnimFrames to write on disk\n"
  246.                         "(framenumber and extension is added)");
  247.   argv[3].text_buf_len = len_basename;
  248.   argv[3].text_buf_ret = basename;
  249.   argv[3].entry_width = 250;
  250.   
  251.   p_init_arr_arg(&argv[4], WGT_OPTIONMENU);
  252.   argv[4].label_txt = _("Format");
  253.   argv[4].help_txt  = _("Fileformat for the extracted AnimFrames\n"
  254.                    "(xcf is extracted as ppm and converted to xcf)");
  255.   argv[4].radio_argc  = 3;
  256.   argv[4].radio_argv = radio_args;
  257.   argv[4].radio_ret  = 0;
  258.  
  259.   p_init_arr_arg(&argv[5], WGT_TOGGLE);
  260.   argv[5].label_txt = _("Extract Frames");
  261.   argv[5].help_txt  = _("Enable extraction of Frames");
  262.   argv[5].int_ret   = 1;
  263.  
  264.   p_init_arr_arg(&argv[6], WGT_TOGGLE);
  265.   argv[6].label_txt = _("Extract Audio");
  266.   argv[6].help_txt  = _("Enable extraction of audio to raw audiofile\n"
  267.                         "(frame range limits are ignored for audio)");
  268.   argv[6].int_ret   = 0;
  269.   
  270.   p_init_arr_arg(&argv[7], WGT_INT_PAIR);
  271.   argv[7].label_txt = _("Jpeg Quality:");
  272.   argv[7].help_txt  = _("Quality for resulting Jpeg frames\n"
  273.                         "(is ignored when other formats are used)");
  274.   argv[7].constraint = TRUE;
  275.   argv[7].int_min    = 0;
  276.   argv[7].int_max    = 100;
  277.   argv[7].int_ret    = 90;
  278.  
  279.   p_init_arr_arg(&argv[8], WGT_LABEL);
  280.   argv[8].label_txt = "";
  281.  
  282.   p_init_arr_arg(&argv[9], WGT_TOGGLE);
  283.   argv[9].label_txt = _("Open");
  284.   argv[9].help_txt  = _("Open the 1st one of the extracted frames");
  285.   argv[9].int_ret   = 1;
  286.  
  287.   p_init_arr_arg(&argv[10], WGT_TOGGLE);
  288.   argv[10].label_txt = _("Run asynchronously");
  289.   argv[10].help_txt  = _("Run xanim asynchronously and delete unwanted frames\n"
  290.                         "(out of the specified range) while xanim is still running");
  291.   argv[10].int_ret   = 1;
  292.  
  293.   p_init_arr_arg(&argv[11], WGT_LABEL_LEFT);
  294.   argv[11].label_txt = _("\nWarning: xanim 2.80 has only limited MPEG support.\n"
  295.              "Most of the frames (type P and B) will be skipped.");
  296.    
  297.   if(TRUE == p_array_dialog(_("Split any Xanim readable Video to Frames"), 
  298.                 _("Select Frame Range"), XADIALOG_NUM_ARGS, argv))
  299.   {
  300.      if(argv[1].int_ret < argv[2].int_ret )
  301.      {
  302.        *first_frame = (long)(argv[1].int_ret);
  303.        *last_frame  = (long)(argv[2].int_ret);
  304.      }
  305.      else
  306.      {
  307.        *first_frame = (long)(argv[2].int_ret);
  308.        *last_frame  = (long)(argv[1].int_ret);
  309.      }
  310.      *Format = (t_gap_xa_formats)(argv[4].int_ret);
  311.      *extract_video  = (long)(argv[5].int_ret);
  312.      *extract_audio  = (long)(argv[6].int_ret);
  313.      *jpeg_quality   = (long)(argv[7].int_ret);
  314.      *autoload       = (long)(argv[9].int_ret);
  315.      *run_xanim_asynchron   = (long)(argv[10].int_ret);
  316.      return (0);    /* OK */
  317.   }
  318.   else
  319.   {
  320.      return -1;     /* Cancel */
  321.   }
  322.    
  323.  
  324. }    /* end p_xanim_dialog */
  325.  
  326.  
  327. static gint
  328. p_overwrite_dialog(char *filename, gint overwrite_mode)
  329. {
  330.   static  t_but_arg  l_argv[3];
  331.   static  t_arr_arg  argv[1];
  332.  
  333.   if(p_file_exists(filename))
  334.   {
  335.     if (overwrite_mode < 1)
  336.     {
  337.        l_argv[0].but_txt  = _("Overwrite Frame");
  338.        l_argv[0].but_val  = 0;
  339.        l_argv[1].but_txt  = _("Overwrite All");
  340.        l_argv[1].but_val  = 1;
  341.        l_argv[2].but_txt  = _("Cancel");
  342.        l_argv[2].but_val  = -1;
  343.  
  344.        p_init_arr_arg(&argv[0], WGT_LABEL);
  345.        argv[0].label_txt = filename;
  346.     
  347.        return(p_array_std_dialog ( _("GAP Question"),
  348.                                    _("File already exists"),
  349.                    1, argv,
  350.                    3, l_argv, -1));
  351.     }
  352.   }
  353.   return (overwrite_mode);
  354. }
  355.  
  356.  
  357.  
  358.  
  359. static void
  360. p_build_xanim_framename(char *framename, gint32 sizeof_framename, gint32 frame_nr, char *ext)
  361. {
  362.    g_snprintf(framename, sizeof_framename, "%s/frame%d.%s",
  363.                 global_xanim_input_dir,
  364.                 (int)frame_nr,
  365.                 ext);
  366. }
  367.  
  368. static void
  369. p_build_gap_framename(char *framename, gint32 sizeof_framename, gint32 frame_nr, char *basename, char *ext)
  370. {
  371.    g_snprintf(framename, sizeof_framename, "%s%04d.%s", basename, (int)frame_nr, ext);
  372. }
  373.  
  374. int
  375. p_is_directory(char *fname)
  376. {
  377.   struct stat  l_stat_buf;
  378.  
  379.   /* get File status */
  380.   if (0 != stat(fname, &l_stat_buf))
  381.   {
  382.     /* stat error (file does not exist) */
  383.     return(0);
  384.   }
  385.   
  386.   if(S_ISDIR(l_stat_buf.st_mode))
  387.   {
  388.     return(1);
  389.   }
  390.     
  391.   return(0);
  392. }    /* end p_is_directory  */
  393.  
  394. void
  395. p_dirname(char *fname)
  396. {
  397.   int l_idx;
  398.   
  399.   l_idx = strlen(fname) -1;
  400.   while(l_idx > 0)
  401.   {
  402.      if(fname[l_idx] == G_DIR_SEPARATOR)
  403.      {
  404.         fname[l_idx] = '\0';
  405.     return;
  406.      }
  407.      l_idx--;
  408.   }
  409.   *fname = '\0';
  410. }
  411.  
  412. static void
  413. p_init_xanim_global_name()
  414. {
  415.   char *l_env;
  416.   
  417.   l_env = g_getenv("GAP_XANIM_PROG");
  418.   
  419.   if(l_env != NULL)
  420.   {
  421.      strcpy(global_xanim_prog, l_env);     
  422.      return;
  423.   }
  424.   strcpy(global_xanim_prog, "xanim");  /* default name */
  425. }
  426.  
  427. static int
  428. p_convert_frames(gint32 frame_from, gint32 frame_to, char *basename, char *ext, char *ext2)
  429. {
  430.    GimpParam          *return_vals;
  431.    int              nreturn_vals;
  432.    gint32           l_tmp_image_id;
  433.    char             l_first_xa_frame[200];
  434.  
  435.   /* load 1st one of those frames generated by xanim  */
  436.    p_build_xanim_framename(l_first_xa_frame, sizeof(l_first_xa_frame), frame_from, ext);
  437.    l_tmp_image_id = p_load_image(l_first_xa_frame);
  438.  
  439.    /* convert the xanim frames (from ppm) to xcf fileformat
  440.     * (the gap module for range convert is not linked to the frontends
  441.     *  main program, therefore i call the convert procedure by PDB-interface)
  442.     */   
  443.    return_vals = gimp_run_procedure ("plug_in_gap_range_convert2",
  444.                                     &nreturn_vals,
  445.                                     GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,     /* runmode  */
  446.                                     GIMP_PDB_IMAGE, l_tmp_image_id,
  447.                                     GIMP_PDB_DRAWABLE, 0,         /* (unused)  */
  448.                                     GIMP_PDB_INT32, frame_from,
  449.                                     GIMP_PDB_INT32, frame_to,
  450.                                     GIMP_PDB_INT32, 0,            /* dont flatten */
  451.                                     GIMP_PDB_INT32, 4444,         /* dest type (keep type) */
  452.                                     GIMP_PDB_INT32, 256,          /* colors (unused)  */
  453.                                     GIMP_PDB_INT32, 0,            /* no dither (unused)  */
  454.                                     GIMP_PDB_STRING, ext2,        /* extension for dest. filetype  */
  455.                                     GIMP_PDB_STRING, basename,    /* basename for dest. filetype  */
  456.                                     GIMP_PDB_INT32, 0,            /* (unused)  */
  457.                                     GIMP_PDB_INT32, 0,            /* (unused)  */
  458.                                     GIMP_PDB_INT32, 0,            /* (unused)  */
  459.                                     GIMP_PDB_STRING, "none",      /* (unused) palettename */
  460.                                     GIMP_PDB_END);
  461.  
  462.    /* destroy the tmp image */
  463.    gimp_image_delete(l_tmp_image_id);
  464.  
  465.    if (return_vals[0].data.d_status != GIMP_PDB_SUCCESS)
  466.    {
  467.       return(-1);  
  468.    }
  469.  
  470.    return(0);  /* OK */
  471. }
  472.  
  473.  
  474. static gint32
  475. p_find_max_xanim_frame(gint32 from_nr, char *ext)
  476. {
  477.   gint32 l_high;
  478.   gint32 l_max_found;
  479.   gint32 l_nr;
  480.   gint32 l_delta;
  481.   char   l_frame[500];
  482.   
  483.   l_nr = from_nr;
  484.   l_max_found = 0;
  485.   l_high = 100000;
  486.   
  487.   while(1 == 1)
  488.   {
  489.      p_build_xanim_framename(l_frame, sizeof(l_frame), l_nr, ext);
  490.  
  491.      if(gap_debug) printf("DEBUG find_MAX :%s\n", l_frame);
  492.      
  493.      if(p_file_exists(l_frame))
  494.      {
  495.         l_max_found = l_nr;
  496.         l_delta = (l_high - l_nr) / 2;
  497.         if(l_delta == 0)
  498.     { 
  499.        l_delta = 1;
  500.     }
  501.         l_nr = l_max_found + l_delta;
  502.      }
  503.      else
  504.      {    
  505.         if(l_nr == from_nr) { return (-1); }  /* no frames found */
  506.  
  507.         if(l_nr < l_high)
  508.     {
  509.            l_high = l_nr;
  510.        l_nr = l_max_found + 1;
  511.     }
  512.     else
  513.     {
  514.        return(l_max_found);
  515.     }
  516.      }
  517.   } 
  518. }    /* end p_find_max_xanim_frame */
  519.  
  520. static int
  521. p_rename_frames(gint32 frame_from, gint32 frame_to, char *basename, char *ext)
  522. {
  523.   gint32 l_use_mv;
  524.   gint32 l_frame_nr;
  525.   gint32 l_max_found;
  526.   char   l_src_frame[500];
  527.   char   l_dst_frame[500];
  528.   gint    l_overwrite_mode;
  529.  
  530.  
  531.   if(gap_debug) printf("p_rename_frames:\n");
  532.   l_use_mv = TRUE;
  533.   l_overwrite_mode = 0;
  534.  
  535.   
  536.   l_max_found = p_find_max_xanim_frame (frame_from, ext);
  537.   if(l_max_found < 0)
  538.   {
  539.        global_errlist = g_strdup_printf(
  540.            _("can't find any extracted frames,\n%s\nmaybe xanim has failed or was cancelled"),
  541.            l_src_frame);
  542.        return(-1);
  543.   }
  544.  
  545.   
  546.   l_frame_nr = frame_from;
  547.    
  548.   while (l_frame_nr <= frame_to)
  549.   {
  550.      p_build_xanim_framename(l_src_frame, sizeof(l_src_frame), l_frame_nr, ext);
  551.      p_build_gap_framename(l_dst_frame, sizeof(l_dst_frame), l_frame_nr, basename, ext);
  552.      
  553.      if(!p_file_exists(l_src_frame))
  554.      {
  555.         break;  /* srcfile not found, stop */
  556.      }
  557.      
  558.      if (strcmp(l_src_frame, l_dst_frame) != 0)
  559.      {
  560.         /* check overwrite if Destination frame already exsts */
  561.     l_overwrite_mode = p_overwrite_dialog(l_dst_frame, l_overwrite_mode);
  562.     if (l_overwrite_mode < 0)
  563.     {
  564.          global_errlist = g_strdup_printf(
  565.                  _("frames are not extracted, because overwrite of %s was cancelled"),
  566.                  l_dst_frame);
  567.          return(-1);
  568.     }
  569.     else
  570.     {
  571.        remove(l_dst_frame);
  572.        if (p_file_exists(l_dst_frame))
  573.            {
  574.          global_errlist = g_strdup_printf(
  575.                  _("failed to overwrite %s (check permissions ?)"),
  576.                  l_dst_frame);
  577.          return(-1);
  578.        }
  579.     }
  580.  
  581.         if (l_use_mv)
  582.     {    
  583.            rename(l_src_frame, l_dst_frame);
  584.     }
  585.     
  586.     if (!p_file_exists(l_dst_frame)) 
  587.     {
  588.        p_file_copy(l_src_frame, l_dst_frame);
  589.        if (p_file_exists(l_dst_frame))
  590.        {
  591.               l_use_mv = FALSE; /* if destination is on another device use copy-remove strategy */
  592.           remove(l_src_frame);
  593.        }
  594.        else
  595.        {
  596.           global_errlist = g_strdup_printf(
  597.                  _("failed to write %s (check permissions ?)"),
  598.                  l_dst_frame);
  599.           return(-1);
  600.        }
  601.     }
  602.      }
  603.      l_frame_nr++;
  604.      if(l_max_found > 0) gimp_progress_update ((gdouble)l_frame_nr / (gdouble)l_max_found);
  605.   }
  606.   return(0);
  607. }    /* end p_rename_frames */
  608.  
  609. static void
  610. p_delete_frames(gint32 max_tries, gint32 frame_from, gint32 frame_to, char *ext)
  611. {
  612.   /* this procedure is performed repeatedly while polling the xanim process
  613.    * and after xanim process has (or was) terminated to clean up unwanted frames.
  614.    */
  615.   gint32 l_tries;
  616.   gint32 l_next_number;
  617.   char   l_framename[500];
  618.   
  619.   if(gap_debug) printf("p_delete_frames: cleaning up unwanted frames (max=%d)\n", (int)max_tries);
  620.   
  621.   l_tries = 0;
  622.  
  623.   while ((global_delete_number < frame_from) && (l_tries < max_tries))
  624.   {
  625.      l_next_number = global_delete_number + 1;
  626.      p_build_xanim_framename(l_framename, sizeof(l_framename), l_next_number, ext);
  627.      
  628.      if (p_file_exists(l_framename))
  629.      {
  630.         /* if xanim has already written the next frame
  631.      * we can delete the previous (unwanted) frame now
  632.      */
  633.         p_build_xanim_framename(l_framename, sizeof(l_framename), global_delete_number, ext);
  634.     if(gap_debug) printf("delete frame: %s\n", l_framename);
  635.     remove(l_framename);
  636.  
  637.     global_delete_number = l_next_number;
  638.      }
  639.      l_tries++;
  640.   }
  641. }    /* end p_delete_frames */
  642.  
  643.  
  644. static void
  645. p_poll(pid_t xanim_pid, char *one_past_last_frame, gint32 frame_from, gint32 frame_to, char *ext)
  646. {
  647.   /* loop as long as the Xanim Process is alive */
  648.  
  649.   if(gap_debug) printf("poll started on xanim pid: %d\n", (int)xanim_pid);
  650.  
  651.  
  652.   /* kill  with signal 0 checks only if the process is alive (no signal is sent)
  653.    *       returns 0 if alive, 1 if no process with given pid found.
  654.    */
  655.   while (0 == kill(xanim_pid, 0))
  656.   {
  657.     usleep(100000);  /* sleep 1 second, and let xanim write some frames */
  658.     if (p_file_exists(one_past_last_frame))
  659.     {
  660.        /* if the last desired frame is written
  661.         * we can stop (kill with signal 9) the xanim process.
  662.         */
  663.        kill(xanim_pid, 9);
  664.        break;
  665.     }
  666.  
  667.     /* check for max unwanted frames and delete (upto 20 of them) */
  668.     p_delete_frames(20, frame_from, frame_to, ext);
  669.   }   
  670.               
  671.   if(gap_debug) printf("poll ended on xanim pid: %d\n", (int)xanim_pid);
  672. }    /* end p_poll */
  673.  
  674.  
  675. static int
  676. p_grep(char *pattern, char *file)
  677. {
  678.   gint    l_rc;
  679.   gchar  *l_cmd;
  680.  
  681.   l_cmd = g_strdup_printf("grep -c '%s' \"%s\" >/dev/null", pattern, file);
  682.   l_rc =  system(l_cmd);
  683.   g_free(l_cmd);
  684.   if (l_rc == 0)
  685.   {
  686.      return(0); /* pattern found */
  687.   }  
  688.   return(1);    /* pattern NOT found */
  689. }
  690.  
  691. static gint
  692. p_check_xanim()
  693. {
  694.   gint l_rc;
  695.   gint l_grep_counter1;
  696.   gint l_grep_counter2;
  697.   gint l_grep_counter3;
  698.   gchar *l_cmd;
  699.   static char *l_xanim_help_output = "tmp_xanim_help.output";
  700.   FILE *l_fp;
  701.  
  702.   l_fp = fopen(l_xanim_help_output, "w+");
  703.   if (l_fp == NULL)
  704.   {
  705.     global_errlist = g_strdup_printf("no write permission for current directory");
  706.     return(10);
  707.   }
  708.   fprintf(l_fp, "dummy");
  709.   fclose(l_fp);
  710.  
  711.   /* execute xanim with -h option and 
  712.    * store its output in a file.
  713.    */
  714.   l_cmd = g_strdup_printf("%s -h 2>&1 >>%s", global_xanim_prog, l_xanim_help_output);
  715.   l_rc =  system(l_cmd);
  716.  
  717.   if(gap_debug) printf("DEBUG: executed :%s\n  Retcode: %d\n", l_cmd, (int)l_rc);
  718.   g_free(l_cmd);
  719.   
  720.   if ((l_rc == 127) || (l_rc == (127 << 8)))
  721.   {
  722.         global_errlist = g_strdup_printf(
  723.                 _("could not execute %s (check if xanim is installed)"),
  724.                 global_xanim_prog  );
  725.         return(10);
  726.   }
  727.  
  728.   if(!p_file_exists(l_xanim_help_output)) 
  729.   {
  730.     global_errlist = g_strdup_printf(
  731.             _("%s does not look like xanim"),
  732.             global_xanim_prog  );
  733.     return(10);
  734.   }
  735.   
  736.   /* check the help output of xanim (using grep) */
  737.   l_grep_counter1 = 0;
  738.   /* l_grep_counter1 += p_grep("anim", l_xanim_help_output); */
  739.  
  740.   /* check for the exporting options */     
  741.   l_grep_counter2 = 0;
  742.   l_grep_counter2 += p_grep("Ea", l_xanim_help_output);
  743.   l_grep_counter2 += p_grep("Ee", l_xanim_help_output);
  744.   l_grep_counter2 += p_grep("Eq", l_xanim_help_output);
  745.  
  746.   /* check for the loki version that is able to write single frames */     
  747.   l_grep_counter3 = 0;
  748.   l_grep_counter3 += p_grep("Write video to input/frameN.EXT", l_xanim_help_output);
  749.  
  750.   remove(l_xanim_help_output);
  751.  
  752.   if(l_grep_counter2 != 0)
  753.   {
  754.      global_errlist = g_strdup_printf(
  755.              _("The xanim program on your system \"%s\"\ndoes not support the exporting options Ea, Ee, Eq"),
  756.              global_xanim_prog  );
  757.      return(10);
  758.   }
  759.   if(l_grep_counter3 != 0)
  760.   {
  761.      global_errlist = g_strdup_printf(
  762.              _("The xanim program on your system \"%s\"\ndoes not support exporting of single frames"),
  763.              global_xanim_prog  );
  764.      return(10);
  765.   }
  766.   return (0);  /* OK, xanim output looks like expected */
  767. }    /* end p_check_xanim */
  768.  
  769. static pid_t
  770. p_start_xanim_process(gint32 first_frame, gint32 last_frame,
  771.                   char   *filename,
  772.           t_gap_xa_formats Format,
  773.           gint32  extract_video,
  774.           gint32  extract_audio,
  775.           gint32  jpeg_quality , 
  776.           char *one_past_last_frame,
  777.           gint32  run_xanim_asynchron)
  778. {
  779.    gchar  l_cmd[500];
  780.    gchar  l_buf[40];
  781.    pid_t l_xanim_pid;
  782.    int   l_rc;
  783.    FILE  *l_fp;
  784.    static char *l_xanim_startscript = "tmp_xanim_startscript.sh";
  785.    static char *l_xanim_pidfile = "tmp_xanim_pidfile";
  786.    
  787.    l_xanim_pid = -1;
  788.    
  789.    /* allocate and prepare args for the xanim call */
  790.    g_snprintf(l_cmd, sizeof(l_cmd), "%s +f ", global_xanim_prog);  /* programname */
  791.    
  792.    if (extract_audio)
  793.    {
  794.      strcat(l_cmd, "+Ea ");
  795.    }
  796.  
  797.    if (extract_video)
  798.    {
  799.      strcat(l_cmd, "+v ");    /* +v is verbose mode */
  800.  
  801.      switch(Format)
  802.      { 
  803.        case XAENC_PPMRAW:
  804.           strcat(l_cmd, "+Ee ");
  805.       break;
  806.        case XAENC_JPEG:
  807.           g_snprintf(l_buf, sizeof(l_buf), "+Eq%d ", (int)jpeg_quality);
  808.       strcat(l_cmd, l_buf);
  809.       break;
  810.        default:
  811.           strcat(l_cmd, "+Ee ");
  812.       break;
  813.       }
  814.  
  815.      /* additional option "Pause after N Frames" is used,
  816.       * to stop xanim exporting frames beyond the requested limit
  817.       */
  818.      if (run_xanim_asynchron)
  819.      {
  820.        g_snprintf(l_buf, sizeof(l_buf), "+Zp%d ", (int)(last_frame +1));
  821.        strcat(l_cmd, l_buf);
  822.      }
  823.       
  824.    }
  825.    
  826.    /* add the videofilename as last parameter */
  827.    strcat(l_cmd, filename);
  828.  
  829.    if (run_xanim_asynchron)
  830.    {
  831.      /* asynchron start */
  832.      remove(l_xanim_pidfile);   
  833.      /* generate a shelscript */
  834.      l_fp = fopen(l_xanim_startscript, "w+");
  835.      if (l_fp != NULL)
  836.      {
  837.      fprintf(l_fp, "#!/bin/sh\n");
  838.      /* fprintf(l_fp, "(%s ; touch %s) &\n" */
  839.      fprintf(l_fp, "%s & # ; touch %s) &\n"
  840.                        , l_cmd                 /* start xanim as background process */
  841.                , one_past_last_frame   /* and create a dummy frame when xanim is done */
  842.          );
  843.      fprintf(l_fp, "XANIM_PID=$!\n");
  844.      fprintf(l_fp, "echo \"$XANIM_PID # XANIM_PID\"\n");
  845.      fprintf(l_fp, "echo \"$XANIM_PID # XANIM_PID\" > \"%s\"\n", l_xanim_pidfile);
  846.  
  847.      /* we pass the xanim pid in a file, 
  848.           * exitcodes are truncated to 8 bit
  849.           * by the system call
  850.           */
  851.      /* fprintf(l_fp, "exit $XANIM_PID\n"); */
  852.      fclose(l_fp);
  853.  
  854.      chmod(l_xanim_startscript, MKDIR_MODE);
  855.      }
  856.  
  857.      l_rc = system(l_xanim_startscript);
  858.  
  859.      l_fp = fopen(l_xanim_pidfile, "r");
  860.      if (l_fp != NULL)
  861.      {
  862.     fscanf(l_fp, "%d", &l_rc);
  863.     fclose(l_fp);
  864.     l_xanim_pid = (pid_t)l_rc;
  865.      }
  866.  
  867.      remove(l_xanim_startscript);
  868.      remove(l_xanim_pidfile);
  869.  
  870.  
  871.      if(gap_debug) printf("ASYNCHRON CALL: %s\nl_xanim_pid:%d\n", l_cmd, (int)l_xanim_pid);
  872.    }
  873.    else
  874.    {
  875.      /* synchron start (blocks until xanim process has finished */
  876.      l_rc = system(l_cmd);
  877.      if ((l_rc & 0xff) == 0) l_xanim_pid = 0;
  878.      else                    l_xanim_pid = -1;
  879.  
  880.      if(gap_debug) printf("ASYNCHRON CALL: %s\nretcode:%d (%d)\n", l_cmd, (int)l_rc, (int)l_xanim_pid);
  881.    }
  882.   
  883.    return(l_xanim_pid);   
  884. }    /* end p_start_xanim_process */
  885.  
  886.  
  887. #ifdef THIS_IS_A_COMMENT_EXEC_DID_NOT_WORK_AND_LEAVES_A_ZOMBIE_PROCESS
  888. static pid_t
  889. p_start_xanim_process_exec(gint32 first_frame, gint32 last_frame,
  890.                   char   *filename,
  891.           t_gap_xa_formats Format,
  892.           gint32  extract_video,
  893.           gint32  extract_audio,
  894.           gint32  jpeg_quality
  895.           )
  896. {
  897.    char *args[20];
  898.    char  l_buf[40];
  899.    int   l_idx;
  900.    pid_t l_xanim_pid;
  901.  
  902.    /* allocate and prepare args for the xanim call */
  903.    l_idx = 0;
  904.    args[l_idx] = g_strdup(global_xanim_prog);  /* programname */
  905.    
  906.    l_idx++;
  907.    args[l_idx] = g_strdup("+f");
  908.  
  909.    if (extract_audio)
  910.    {
  911.      l_idx++;
  912.      args[l_idx] = g_strdup("+Ea");
  913.    }
  914.  
  915.    if (extract_video)
  916.    {
  917.      l_idx++;
  918.      args[l_idx] = g_strdup("+v");    /* +v is verbose mode */
  919.  
  920.      l_idx++;
  921.      switch(Format)
  922.      { 
  923.        case XAENC_PPMRAW:
  924.           args[l_idx] = g_strdup("+Ee");
  925.       break;
  926.        case XAENC_JPEG:
  927.           g_snprintf(l_buf, sizeof(l_buf), "+Eq%d", (int)jpeg_quality);
  928.       args[l_idx] = g_strdup(l_buf);
  929.       break;
  930.        default:
  931.           args[l_idx] = g_strdup("+Ee");
  932.       break;
  933.       }
  934.  
  935.      /* additional option "Pause after N Frames" is used,
  936.       * to stop xanim exporting frames beyond the requested limit
  937.       */      
  938.      l_idx++;
  939.      g_snprintf(l_buf, sizeof(l_buf), "+Zp%d", (int)(last_frame +1));
  940.      args[l_idx] = g_strdup(l_buf);
  941.       
  942.    }
  943.    
  944.    /* add the videofilename as last parameter */
  945.    l_idx++;
  946.    args[l_idx] = g_strdup(filename);
  947.    
  948.    l_idx++;
  949.    args[l_idx] = NULL;  /* terminate args list with a NULL pointer */
  950.    
  951.    l_xanim_pid = fork();
  952.  
  953.    if(l_xanim_pid == 0)
  954.    {
  955.       /* here we are in the forked child process
  956.        * execute xanim
  957.        */
  958.       execvp(args[0], args);
  959.       
  960.       /* this point should never be reached */
  961.       _exit (1);
  962.    }
  963.    
  964.    return(l_xanim_pid);   
  965. }    /* end p_start_xanim_process */
  966. #endif
  967.  
  968.  
  969. /* ============================================================================
  970.  * gap_xanim_decode
  971.  * ============================================================================
  972.  */
  973.  
  974. gint32
  975. gap_xanim_decode(GimpRunModeType run_mode)
  976. {
  977.   gint32 l_rc;
  978.   gint32 first_frame;
  979.   gint32 last_frame;
  980.   char   filename[200];
  981.   char   basename[200];
  982.   char   extension[20];
  983.   char   extension2[20];
  984.   t_gap_xa_formats Format;
  985.   gint32 extract_audio;
  986.   gint32 extract_video; 
  987.   gint32 jpeg_quality;
  988.   gint32 autoload;
  989.   gint32 run_xanim_asynchron;
  990.   char   l_cmd[300];
  991.   char   l_one_past_last_frame[200];
  992.   char   l_first_to_laod[200];
  993.   char  *l_dst_dir;
  994.   pid_t  l_xanim_pid;
  995.   int    l_input_dir_created_by_myself;
  996.   
  997.   l_rc = 0;
  998.   l_input_dir_created_by_myself = FALSE;
  999.   global_errlist = NULL;
  1000.   p_init_xanim_global_name();
  1001.   
  1002.   filename[0] = '\0';
  1003.   strcpy(&basename[0], "frame_");
  1004.  
  1005.   l_rc = p_xanim_dialog (&first_frame,
  1006.                  &last_frame,
  1007.          filename, sizeof(filename),
  1008.          basename, sizeof(basename),
  1009.          &Format,
  1010.          &extract_video,
  1011.          &extract_audio,
  1012.          &jpeg_quality,
  1013.          &autoload,
  1014.          &run_xanim_asynchron);
  1015.  
  1016.  
  1017.   if(l_rc != 0)
  1018.   {
  1019.     return(l_rc);
  1020.   }
  1021.   
  1022.   if(!p_file_exists(filename))
  1023.   {
  1024.      global_errlist = g_strdup_printf(
  1025.             _("videofile %s not existent or empty\n"),
  1026.             filename);
  1027.             l_rc = 10;
  1028.   }
  1029.   else
  1030.   {
  1031.      l_rc = p_check_xanim();
  1032.   }
  1033.   
  1034.   
  1035.   if (l_rc == 0)
  1036.   {
  1037.     switch(Format)
  1038.     { 
  1039.       case XAENC_PPMRAW:
  1040.          strcpy(extension,  "ppm");
  1041.          strcpy(extension2, ".ppm");
  1042.       break;
  1043.       case XAENC_JPEG:
  1044.          strcpy(extension,  "jpg");
  1045.          strcpy(extension2, ".jpg");
  1046.      break;
  1047.       default:
  1048.          strcpy(extension,  "ppm");
  1049.          strcpy(extension2, ".xcf");
  1050.      break;
  1051.  
  1052.      }
  1053.      p_build_xanim_framename(l_one_past_last_frame, sizeof(l_one_past_last_frame), last_frame +1 , extension);
  1054.  
  1055.     if (extract_video)
  1056.     {
  1057.          /* for the frames we need a directory named "input" */
  1058.          if (p_is_directory(global_xanim_input_dir))
  1059.          {
  1060.            /* the input directory already exists,
  1061.             * remove frames
  1062.             */
  1063.            g_snprintf(l_cmd, sizeof(l_cmd), "rm -f %s/*.%s", global_xanim_input_dir, extension);
  1064.            system(l_cmd);
  1065.          }
  1066.          else
  1067.          {
  1068.             /* create input directory (needed by xanim to store the frames) */
  1069.             mkdir(global_xanim_input_dir, MKDIR_MODE);
  1070.  
  1071.             if (p_is_directory(global_xanim_input_dir))
  1072.             {
  1073.               l_input_dir_created_by_myself = TRUE;
  1074.             }
  1075.             else
  1076.             {
  1077.                global_errlist = g_strdup_printf(
  1078.                       _("could not create %s directory\n"
  1079.                        "(that is required for xanim frame export)"),
  1080.                        global_xanim_input_dir);
  1081.                l_rc = 10;
  1082.             }
  1083.          }
  1084.      }
  1085.   }
  1086.    
  1087.   if(l_rc == 0)
  1088.   {
  1089.      gimp_progress_init (_("extracting frames..."));
  1090.      gimp_progress_update (0.1);  /* fake some progress */
  1091.      /* note:
  1092.       *  we can't show realistic progress for the extracting process
  1093.       *  because we know nothing about videofileformat and how much frames
  1094.       *  are realy stored in the videofile.
  1095.       *
  1096.       *  one guess could assume, that xanim will write 0 upto last_frame
  1097.       *  to disk, and check for the frames that the xanim process creates.
  1098.       *  The periodically checking can be done in the poll procedure for asynchron
  1099.       *  startmode only.
  1100.       */
  1101.  
  1102.      l_xanim_pid = p_start_xanim_process(first_frame, last_frame,
  1103.                                     filename,
  1104.                                         Format,
  1105.                     extract_video,
  1106.                     extract_audio,
  1107.                     jpeg_quality,
  1108.                                         l_one_past_last_frame,
  1109.                     run_xanim_asynchron);
  1110.  
  1111.      if (l_xanim_pid == -1 )
  1112.      {
  1113.         global_errlist = g_strdup_printf(
  1114.            _("could not start xanim process\n(program=%s)"),
  1115.            global_xanim_prog  );
  1116.     l_rc = -1;
  1117.      }
  1118.   }
  1119.  
  1120.   if(l_rc == 0)
  1121.   {
  1122.      if(run_xanim_asynchron)
  1123.      {
  1124.        p_poll(l_xanim_pid, l_one_past_last_frame, first_frame, last_frame, extension);
  1125.      }
  1126.      
  1127.      p_delete_frames(99999, first_frame, last_frame, extension);
  1128.      remove(l_one_past_last_frame);
  1129.  
  1130.      gimp_progress_update (1.0);
  1131.      
  1132.      if (p_find_max_xanim_frame (first_frame, extension) < first_frame)
  1133.      {
  1134.         global_errlist = g_strdup_printf(
  1135.            _("can't find any extracted frames,\n"
  1136.              "xanim has failed or was cancelled"));
  1137.         l_rc = -1;
  1138.      }
  1139.      else
  1140.      {
  1141.        /* if destination directorypart does not exist, try to create it */
  1142.        l_dst_dir = g_strdup(basename);
  1143.        p_dirname(l_dst_dir);
  1144.        if (*l_dst_dir != '\0')
  1145.        {
  1146.      if ( !p_is_directory(l_dst_dir) )
  1147.      {
  1148.             mkdir (l_dst_dir, MKDIR_MODE);
  1149.      }
  1150.        }
  1151.  
  1152.        if(strcmp(extension, &extension2[1]) == 0)
  1153.        {
  1154.           gimp_progress_init (_("renaming frames..."));
  1155.           l_rc = p_rename_frames(first_frame, last_frame, basename, extension);
  1156.        }
  1157.        else
  1158.        {
  1159.           gimp_progress_init (_("converting frames..."));
  1160.           l_rc = p_convert_frames(first_frame, last_frame, basename, extension, extension2);
  1161.        }
  1162.  
  1163.        if (l_input_dir_created_by_myself)
  1164.        {
  1165.      if (strcmp(l_dst_dir, global_xanim_input_dir) != 0)
  1166.      {
  1167.             /* remove input dir with all files */
  1168.             g_snprintf(l_cmd, sizeof(l_cmd), "rm -rf \"%s\"", global_xanim_input_dir);
  1169.             system(l_cmd);         
  1170.      }
  1171.        }
  1172.        g_free(l_dst_dir);
  1173.        gimp_progress_update (1.0);
  1174.      }
  1175.      
  1176.    }
  1177.  
  1178.    if(l_rc != 0)
  1179.    {
  1180.       if(global_errlist == NULL)
  1181.       {
  1182.          p_xanim_info("ERROR: could not execute xanim");
  1183.       }
  1184.       else
  1185.       {
  1186.          p_xanim_info(global_errlist);
  1187.       }
  1188.       l_rc = -1;
  1189.    }
  1190.    else
  1191.    {
  1192.      if(autoload)
  1193.      {
  1194.         /* load first frame and add a display */
  1195.         p_build_gap_framename(l_first_to_laod, sizeof(l_first_to_laod), first_frame, basename, &extension2[1]);
  1196.         l_rc = p_load_image(l_first_to_laod);
  1197.  
  1198.     if(l_rc >= 0) gimp_display_new(l_rc);
  1199.      }
  1200.    }
  1201.  
  1202.    return(l_rc);    
  1203. }    /* end  gap_xanim_decode */
  1204.