[gimp-gap] windows specific fixes (audio resample via sox, Story attr preview rendering) create storyboard from
- From: Wolfgang Hofer <wolfgangh src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp-gap] windows specific fixes (audio resample via sox, Story attr preview rendering) create storyboard from
- Date: Wed, 16 Jan 2013 19:21:50 +0000 (UTC)
commit 038683ca82e8883b2a48fc3b8f3932bb2e6960fd
Author: Wolfgang Hofer <wolfgangh svn gnome org>
Date: Wed Jan 16 20:05:20 2013 +0100
windows specific fixes (audio resample via sox, Story attr preview rendering) create storyboard from video extract dlg.
ChangeLog | 60 ++++++++
autogen.sh | 5 +-
docs/reference/txt/gap_gimprc_params.txt | 7 +
gap/gap_story_att_trans_dlg.c | 144 ++++++++++----------
gap/gap_story_dialog.c | 164 ++++++++++++++++++++--
gap/gap_story_dialog.h | 2 +-
gap/gap_story_main.c | 135 +++++++++++++++++--
gap/gap_story_main.h | 34 +++++-
gap/gap_story_render_audio.c | 79 +++++++++---
gap/gap_story_render_processor.c | 20 +++-
gap/gap_story_render_processor.h | 2 +
gap/gap_vex_dialog.c | 214 +++++++++++++----------------
gap/gap_vex_dialog.h | 2 +-
gap/gap_vex_exec.c | 221 ++++++++++++++++++++++++++----
gap/gap_vex_exec.h | 2 +-
gap/gap_vex_main.c | 10 +-
gap/gap_vex_main.h | 39 ++++-
vid_common/gap_cme_gui.c | 8 +-
18 files changed, 871 insertions(+), 277 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index a79c45e..36ac2a0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,63 @@
+2013-01-16 Wolfgang Hofer <hof gimp org>
+
+- fixed bug in the storybard master properties that truncated framerate to integer values.
+
+- audio resample via external tool (sox) did not work in WINDOWS environment.
+ The old code was restricted to Unix only.
+ Fixed the parameter substitution and use g_spawn_sync for the external audio converter call
+ that now shall work on other operating systems than unix.
+
+ tests on windows with sox as external converter were successful,
+ but only in case when the external converter was configured with
+ the full absolute path.
+ sox is available on Linux, Windows, and MacOSX
+ see http://sox.sourceforge.net/
+
+- Support audio rendering of an audiotrack that is an extracted audiotrack from a videofile.
+ I used this as workarond in case of unsupported audio codec.
+ The workaround allows extract the audio with another external tool (that supports the codec)
+ and then refere the external audiotrack in same way as internal audiotracks.
+ (e.g. access it in the storyboard by frame numbers via AUD_PLAY_MOVIE)
+
+ ==> manually edit the Storyboard and
+ replace AUD_PLAY_MOVIE .... "my_video.mpg"
+ by AUD_PLAY_MOVIE .... "my_video_extracted_audio.wav"
+
+- Added a new feature that creates a storyboard triggered by
+ the video extract plug-in.
+ The new output mode creates the stroryboard from the videofile,
+ adds the current selected range as initial clip,
+ and opens the created storyboard in the storyboard editor dialog.
+
+- new boolean gimprc parameter video-enable-storyboard-debug-features
+ enables the debug menu in the storyboard dialog
+ and preview image extraction by click on the preview image
+ in the storyboard attributes dialog window.
+
+- fixed a bug in rendering the preview of clip type movie
+ in the storyboard attributes dialog window.
+ (This bug did occure with gimp-2.6.11 running on Windows7
+ but did not occure with gimp-2.6.11 on Linux)
+
+- automake version check support for automake-1.12
+
+ * autogen.sh
+
+ * gap/gap_story_sox.c
+ * gap/gap_story_render_audio.c
+ * gap/gap_story_main.c [.h]
+ * gap/gap_story_dialog.c [.h]
+ * gap/gap_story_att_trans_dlg.c
+ * gap/gap_story_render_processor.c [.h]
+ * gap/gap_vex_dialog.c [.h]
+ * gap/gap_vex_exec.c [.h]
+ * gap/gap_vex_main.c [.h]
+
+ * docs/reference/txt/gap_gimprc_params.txt
+
+ * vid_common/gap_cme_gui.c
+
+
2012-09-30 Wolfgang Hofer <hof gimp org>
- fixed german menuname translations. Translated message must keep the prefix "<Image>"
diff --git a/autogen.sh b/autogen.sh
index b53db5d..2a9097e 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -88,7 +88,10 @@ fi
echo -n "checking for automake >= $AUTOMAKE_REQUIRED_VERSION ... "
-if (automake-1.11 --version) < /dev/null > /dev/null 2>&1; then
+if (automake-1.12 --version) < /dev/null > /dev/null 2>&1; then
+ AUTOMAKE=automake-1.12
+ ACLOCAL=aclocal-1.12
+elif (automake-1.11 --version) < /dev/null > /dev/null 2>&1; then
AUTOMAKE=automake-1.11
ACLOCAL=aclocal-1.11
elif (automake-1.10 --version) < /dev/null > /dev/null 2>&1; then
diff --git a/docs/reference/txt/gap_gimprc_params.txt b/docs/reference/txt/gap_gimprc_params.txt
index 41d0e62..b4e73ff 100644
--- a/docs/reference/txt/gap_gimprc_params.txt
+++ b/docs/reference/txt/gap_gimprc_params.txt
@@ -386,3 +386,10 @@ If you edit gimprc files by hand, you must do this before you startup GIMP.
# rotate transformations on very small angles.
# default is 0.0125 degree
(video-move-path-rotate-threshold "0.0125")
+
+
+# enables the debug menu in the storyboard dialog
+# and preview image extraction by click on the preview image
+# in the storyboard attributes dialog window.
+# default is no
+(video-enable-storyboard-debug-features "no")
diff --git a/gap/gap_story_att_trans_dlg.c b/gap/gap_story_att_trans_dlg.c
old mode 100755
new mode 100644
index 3816484..7e8cd9c
--- a/gap/gap_story_att_trans_dlg.c
+++ b/gap/gap_story_att_trans_dlg.c
@@ -39,6 +39,7 @@
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
+#include "gap_base.h"
#include "gap_story_main.h"
#include "gap_story_undo.h"
#include "gap_story_dialog.h"
@@ -166,7 +167,7 @@ static void p_create_transformed_layer(gint32 image_id
, gint32 stackposition
, const char *layername
, GapStbAttrWidget *attw
- , gint img_idx
+ , gint img_idx
, gboolean enableMovepath
);
static gboolean p_calculate_prefetch_visibility(GapStbAttrWidget *attw, gint img_idx);
@@ -331,14 +332,14 @@ p_attw_prop_response(GtkWidget *widget
/* force close in case file selection dialog is still open */
p_attw_movepath_filesel_pw_close_cb(attw->movepath_filesel, attw);
}
-
+
if(attw->movepath_edit_dialog != NULL)
{
/* force close of the movepath edit dialog that is still open */
gtk_widget_destroy(attw->movepath_edit_dialog);
attw->movepath_edit_dialog = NULL;
}
-
+
p_delete_gfx_images(attw);
if(attw->go_timertag >= 0)
{
@@ -436,10 +437,10 @@ p_attw_prop_reset_all(GapStbAttrWidget *attw)
gtk_adjustment_set_value(GTK_ADJUSTMENT(attw->att_rows[ii].spinbutton_from_adj)
, attw->stb_elem_refptr->att_arr_value_from[ii] *
- p_getConvertFactor(ii));
+ p_getConvertFactor(ii));
gtk_adjustment_set_value(GTK_ADJUSTMENT(attw->att_rows[ii].spinbutton_to_adj)
, attw->stb_elem_refptr->att_arr_value_to[ii] *
- p_getConvertFactor(ii));
+ p_getConvertFactor(ii));
gtk_adjustment_set_value(GTK_ADJUSTMENT(attw->att_rows[ii].spinbutton_dur_adj)
, attw->stb_elem_refptr->att_arr_value_dur[ii]);
@@ -604,7 +605,7 @@ p_attw_update_sensitivity(GapStbAttrWidget *attw)
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);
-
+
sensitive = FALSE;
if(attw->stb_elem_refptr->att_movepath_file_xml != NULL)
{
@@ -956,7 +957,7 @@ p_attw_accel_adjustment_callback(GtkObject *obj, gint32 *val)
{
p_attw_push_undo_and_set_unsaved_changes(attw);
*val = l_val;
-
+
}
}
}
@@ -1039,6 +1040,8 @@ p_attw_preview_events_cb (GtkWidget *widget
GdkEventButton *bevent;
GapStbMainGlobalParams *sgpp;
gint img_idx;
+ gboolean enableStoryboardDebugFeatures;
+
if ((attw->stb_elem_refptr == NULL)
|| (attw->stb_refptr == NULL))
@@ -1063,7 +1066,9 @@ p_attw_preview_events_cb (GtkWidget *widget
// TODO: define actions when button pressed.
/* debug code to display a copy of the image */
- if(1==0)
+ enableStoryboardDebugFeatures =
+ gap_base_get_gimprc_gboolean_value(GAP_GIMPRC_ENABLE_STORYBOARD_DEBUG_FEATURES, FALSE);
+ if(enableStoryboardDebugFeatures)
{
p_debug_dup_image(attw->gfx_tab[img_idx].image_id);
}
@@ -1519,14 +1524,14 @@ p_is_width_or_height_fixed(gboolean fit_width, gboolean fit_height, gboolean kee
{
return (TRUE);
}
-
+
if ((fit_width != fit_height) && (keep_proportions == FALSE))
{
return (TRUE);
}
-
+
return (FALSE);
-
+
} /* end p_is_width_or_height_fixed */
@@ -1558,7 +1563,7 @@ p_create_transformed_layer_movepath(gint32 image_id
gint32 mov_obj_layer_id;
gdouble att_tab[GAP_STB_ATT_GFX_ARRAY_MAX][GAP_STB_ATT_TYPES_ARRAY_MAX];
gint ii;
-
+
if(attw == NULL)
{
printf("** INTERNAL ERROR p_create_transformed_layer_movepath called with attw is NULL\n");
@@ -1569,12 +1574,12 @@ p_create_transformed_layer_movepath(gint32 image_id
printf("** INTERNAL ERROR p_create_transformed_layer_movepath called with stb_refptr is NULL\n");
return (FALSE);
}
-
+
if(attw->movepath_file_xml_is_valid != TRUE)
{
return (FALSE);
}
-
+
master_width = attw->stb_refptr->master_width;
master_height = attw->stb_refptr->master_height;
keep_proportions = attw->stb_elem_refptr->att_keep_proportions;
@@ -1604,7 +1609,7 @@ p_create_transformed_layer_movepath(gint32 image_id
return (FALSE);
}
-
+
/* recreate the current layer at stackposition 2 */
/* create image with 1:1 copy of the origsize_layer_id */
@@ -1627,7 +1632,7 @@ p_create_transformed_layer_movepath(gint32 image_id
gimp_image_add_layer(mov_obj_image_id, mov_obj_layer_id, 0);
gimp_layer_set_offsets(mov_obj_layer_id, 0, 0);
}
-
+
//if(img_idx == 0)
//{
// p_debug_dup_image(mov_obj_image_id);
@@ -1641,7 +1646,7 @@ p_create_transformed_layer_movepath(gint32 image_id
{
gint scaled_width;
gint scaled_height;
-
+
scaled_width = gimp_image_width(mov_obj_image_id) * gimp_image_width(image_id) / master_width;
scaled_height = gimp_image_height(mov_obj_image_id) * gimp_image_height(image_id) / master_height;
gimp_image_scale(mov_obj_image_id, scaled_width, scaled_height);
@@ -1649,7 +1654,7 @@ p_create_transformed_layer_movepath(gint32 image_id
/* call storyboard processor that does movepath and other transformations
* (note that processing is done at size of the preview image that is 2 times larger
- * than the wanted result because
+ * than the wanted result because
*/
new_layer_id = gap_story_render_transform_with_movepath_processing(image_id
, mov_obj_image_id
@@ -1711,7 +1716,7 @@ p_create_transformed_layer_movepath(gint32 image_id
* -----------------------------------------
* create transformed copy of the specified origsize_layer_id,
* according to calculated transformation settings.
- *
+ *
*/
static void
p_create_transformed_layer(gint32 image_id
@@ -1739,8 +1744,8 @@ p_create_transformed_layer(gint32 image_id
}
}
}
-
- /* if size is not equal calculated size
+
+ /* if size is not equal calculated size
* or movepath rendering necessary then remove curr layer
* to force recreation in desired size
*/
@@ -1764,7 +1769,7 @@ p_create_transformed_layer(gint32 image_id
if(movepath_file_xml != NULL)
{
gboolean movepathOk;
-
+
movepathOk = p_create_transformed_layer_movepath(image_id
, origsize_layer_id
, layer_id_ptr
@@ -1784,7 +1789,7 @@ p_create_transformed_layer(gint32 image_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);
@@ -2191,7 +2196,7 @@ p_orig_layer_frame_fetcher(GapStbAttrWidget *attw
,stb_ret
,l_filename
);
-
+
if(is_up_to_date)
{
g_free(stb_ret);
@@ -2199,7 +2204,7 @@ p_orig_layer_frame_fetcher(GapStbAttrWidget *attw
{
g_free(l_filename);
}
-
+
return; /* orig_layer is still up to date, done */
}
@@ -2246,9 +2251,9 @@ p_orig_layer_frame_fetcher(GapStbAttrWidget *attw
, stb_ret->stb_elem->color_red
, stb_ret->stb_elem->color_green
, stb_ret->stb_elem->color_blue
- , stb_ret->stb_elem->color_alpha
+ , stb_ret->stb_elem->color_alpha
);
-
+
linfo->layer_record_type = stb_ret->stb_elem->record_type;
linfo->layer_local_framenr = 0;
linfo->layer_seltrack = 1;
@@ -2547,14 +2552,16 @@ p_fetch_video_frame_as_layer(GapStbMainGlobalParams *sgpp
, img_width
, img_height);
+
+ gimp_drawable_flush (drawable);
+ gimp_drawable_detach(drawable);
+
if(! gimp_drawable_has_alpha (l_new_layer_id))
{
/* implicitly 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);
}
@@ -2593,7 +2600,7 @@ p_fetch_imagefile_as_layer (const char *img_filename
gimp_image_undo_disable (l_tmp_image_id);
l_layer_id = gap_image_merge_visible_layers(l_tmp_image_id, GIMP_CLIP_TO_IMAGE);
-
+
if(!gimp_drawable_has_alpha(l_layer_id))
{
gimp_layer_add_alpha(l_layer_id);
@@ -2616,14 +2623,14 @@ p_fetch_imagefile_as_layer (const char *img_filename
}
return(l_new_layer_id);
-
+
} /* end p_fetch_imagefile_as_layer */
/* ---------------------------------
* p_fetch_layer_from_animimage
* ---------------------------------
- * pick layer at specified localframe_index (e.g. layerstack_position) from specified
+ * pick layer at specified localframe_index (e.g. layerstack_position) from specified
* multilayer animimage on disk (specified via filename)
* and add a copy of this layer as new layer on top of layerstack in the specified image_id.
*/
@@ -2661,7 +2668,7 @@ p_fetch_layer_from_animimage (const char *img_filename
gint32 *l_layers_list;
gimp_image_undo_disable (l_tmp_image_id);
-
+
l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers);
if(gap_debug)
@@ -2688,7 +2695,7 @@ p_fetch_layer_from_animimage (const char *img_filename
gimp_layer_remove_mask(l_layers_list[localframe_index], GIMP_MASK_APPLY);
}
gimp_layer_resize_to_image_size(l_layers_list[localframe_index]);
-
+
/* copy the picked layer from the temp image to the preview multilayer image */
l_new_layer_id = gap_layer_copy_to_dest_image(image_id,
l_layers_list[localframe_index],
@@ -2699,11 +2706,11 @@ p_fetch_layer_from_animimage (const char *img_filename
);
gimp_image_add_layer (image_id, l_new_layer_id, LAYERSTACK_TOP);
-
+
}
g_free (l_layers_list);
}
-
+
/* destroy the tmp image */
gimp_image_delete(l_tmp_image_id);
}
@@ -2834,7 +2841,7 @@ p_create_movepath_edit_resources(GapStbAttrWidget *attw)
gint32 image_id;
gint32 bg_layer_id;
gint32 origsize_layer_id;
-
+
/* create the frame image */
image_id = gimp_image_new(attw->stb_refptr->master_width
,attw->stb_refptr->master_height
@@ -2842,8 +2849,8 @@ p_create_movepath_edit_resources(GapStbAttrWidget *attw)
);
attw->movepath_frame_image_id = image_id;
gimp_image_undo_disable (image_id);
-
- /* add a transparent layer */
+
+ /* add a transparent layer */
bg_layer_id = gimp_layer_new(image_id
, "background"
, gimp_image_width(image_id)
@@ -2858,9 +2865,9 @@ p_create_movepath_edit_resources(GapStbAttrWidget *attw)
// TODO: in case the storyboard has more tracks
// the frame image should be rendered by the storyboard processor at master size
- // based on a modified storyboard that contains only tracks that render behind the current track
+ // based on a modified storyboard that contains only tracks that render behind the current track
+
-
/* create an image that holds the moving object layer */
origsize_layer_id = attw->gfx_tab[0].orig_layer_id;
attw->movepath_obj_image_id = gimp_image_new( gimp_drawable_width(origsize_layer_id)
@@ -2873,14 +2880,14 @@ p_create_movepath_edit_resources(GapStbAttrWidget *attw)
gimp_drawable_set_visible(attw->movepath_obj_layer_id, TRUE);
- /* create default values for movepath
+ /* create default values for movepath
* (will be overwritten in case xml_paramfile contains already valid settings)
*/
attw->pvals = gap_mov_exec_new_GapMovValues();
attw->pvals->dst_image_id = attw->movepath_frame_image_id;
attw->ainfo_ptr = gap_lib_alloc_ainfo_unsaved_image(attw->movepath_frame_image_id);
-
+
} /* end p_create_movepath_edit_resources */
@@ -2893,9 +2900,9 @@ static void
p_edit_movepath_closed_callback(gpointer ptr)
{
GapStbAttrWidget *attw;
-
+
attw = (GapStbAttrWidget *)ptr;
-
+
if(attw != NULL)
{
if(gap_debug)
@@ -2903,22 +2910,22 @@ p_edit_movepath_closed_callback(gpointer ptr)
printf("p_edit_movepath_closed_callback frame_image_id:%d obj_image_id:%d\n"
,(int)attw->movepath_frame_image_id
,(int)attw->movepath_obj_image_id
- );
+ );
}
attw->movepath_edit_dialog = NULL;
-
+
if(attw->pvals != NULL)
{
g_free(attw->pvals);
attw->pvals = NULL;
}
-
+
if(attw->ainfo_ptr != NULL)
{
gap_lib_free_ainfo(&attw->ainfo_ptr);
attw->ainfo_ptr = NULL;
}
-
+
if(attw->movepath_frame_image_id >= 0)
{
gimp_image_delete(attw->movepath_frame_image_id);
@@ -2932,12 +2939,12 @@ p_edit_movepath_closed_callback(gpointer ptr)
}
p_attw_movepath_file_validity_check(attw);
p_update_full_preview_gfx(attw);
-
- /* make attributes dialog sensitive again (after movepath edit dialog was closed) */
+
+ /* make attributes dialog sensitive again (after movepath edit dialog was closed) */
gtk_widget_set_sensitive(attw->attw_prop_dialog, TRUE);
}
-
+
} /* end p_edit_movepath_closed_callback */
@@ -2954,7 +2961,7 @@ p_attw_movepath_edit_button_cb ( GtkWidget *w
, GapStbAttrWidget *attw)
{
gint32 nframes;
-
+
if(attw->attw_prop_dialog == NULL)
{
return;
@@ -2993,9 +3000,9 @@ p_attw_movepath_edit_button_cb ( GtkWidget *w
printf("p_attw_movepath_edit_button_cb frame_image_id:%d obj_image_id:%d obj_layer_id:%d attw:%d\n"
,(int)attw->movepath_frame_image_id
,(int)attw->movepath_obj_image_id
- ,(int)attw->movepath_obj_layer_id
- ,(int)attw
- );
+ ,(int)attw->movepath_obj_layer_id
+ ,(int)attw
+ );
}
@@ -3028,7 +3035,7 @@ p_attw_movepath_file_validity_check(GapStbAttrWidget *attw)
{
if(attw == NULL) { return; }
attw->movepath_file_xml_is_valid = FALSE;
-
+
if(attw->stb_elem_refptr == NULL) { return; }
@@ -3456,10 +3463,10 @@ p_create_and_attach_att_arr_widgets(const char *row_title
accelerationCharacteristic = *att_arr_value_accel_ptr;
accel_wgt = gap_accel_new(ACC_WGT_WIDTH, ACC_WGT_HEIGHT, accelerationCharacteristic);
-
+
/* the Acceleration characteristic value spinbutton */
adj = accel_wgt->adj;
-
+
spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);
attw->att_rows[att_type_idx].spinbutton_accel_adj = adj;
attw->att_rows[att_type_idx].spinbutton_accel = spinbutton;
@@ -3472,17 +3479,17 @@ p_create_and_attach_att_arr_widgets(const char *row_title
gimp_help_set_help_data (spinbutton, accel_tooltip, NULL);
g_object_set_data(G_OBJECT(adj), OBJ_DATA_KEY_ATTW, attw);
-
+
gtk_table_attach( GTK_TABLE(table), accel_wgt->da_widget, col, col+1, row, row+1,
GTK_FILL, 0, 4, 0 );
gtk_widget_show (accel_wgt->da_widget);
-
-
-
+
+
+
g_signal_connect (G_OBJECT (adj), "value_changed",
G_CALLBACK (p_attw_accel_adjustment_callback),
att_arr_value_accel_ptr);
-
+
}
@@ -3955,7 +3962,7 @@ gap_story_attw_properties_dialog (GapStbAttrWidget *attw)
attw);
gtk_widget_show (entry);
attw->movepath_file_entry = entry;
-
+
/* the filesel invoker button */
button = gtk_button_new_with_label ("...");
gtk_table_attach_defaults (GTK_TABLE(table), button, 8, 10, row, row+1);
@@ -3964,7 +3971,7 @@ gap_story_attw_properties_dialog (GapStbAttrWidget *attw)
attw);
gtk_widget_show (button);
-
+
/* the movepath record/edit dialog invoker button */
button = gtk_button_new_with_label ("edit");
attw->movepath_edit_button = button;
@@ -3973,7 +3980,7 @@ gap_story_attw_properties_dialog (GapStbAttrWidget *attw)
G_CALLBACK(p_attw_movepath_edit_button_cb),
attw);
gtk_widget_show (button);
-
+
}
row++;
@@ -4129,6 +4136,3 @@ gap_story_att_fw_properties_dialog (GapStbFrameWidget *fw)
gap_story_att_stb_elem_properties_dialog(tabw, fw->stb_elem_refptr, fw->stb_refptr);
}
} /* end gap_story_att_fw_properties_dialog */
-
-
-
diff --git a/gap/gap_story_dialog.c b/gap/gap_story_dialog.c
index 7e68e0c..b4a821e 100644
--- a/gap/gap_story_dialog.c
+++ b/gap/gap_story_dialog.c
@@ -426,6 +426,11 @@ static void p_get_gimprc_render_settings(GapStbMainGlobalParams *sgpp);
static void p_reset_progress_bars(GapStbMainGlobalParams *sgpp);
+static void p_storyboard_init_from_creation_params( GapStbTabWidgets *tabw
+ , GapStbMainGlobalParams *sgpp
+ , GapStoryBoard *stb
+ , GapStbCreationParams *scrp
+ );
static void p_call_external_image_viewer(GapStbFrameWidget *fw);
@@ -452,11 +457,15 @@ static gboolean
p_is_debug_menu_enabled(void)
{
gboolean enable;
+ gboolean enableStoryboardDebugFeatures;
char *filename;
enable = FALSE;
+ enableStoryboardDebugFeatures =
+ gap_base_get_gimprc_gboolean_value(GAP_GIMPRC_ENABLE_STORYBOARD_DEBUG_FEATURES, FALSE);
if((gap_debug)
+ || (enableStoryboardDebugFeatures)
|| (g_file_test(GAP_DEBUG_STORYBOARD_CONFIG_FILE, G_FILE_TEST_EXISTS)))
{
return(TRUE);
@@ -1817,10 +1826,10 @@ p_story_call_player(GapStbMainGlobalParams *sgpp
return; /* in case of errors: NO playback possible */
sgpp->in_player_call = FALSE;
}
-
+
if(sgpp->stb_preview_render_full_size != TRUE)
{
- /* if the storboard duplicate (stb_dup) includes at least one unscalable clip
+ /* if the storboard duplicate (stb_dup) includes at least one unscalable clip
* (where either with or height is fixed to original size)
* then we must force slow internal rendering at full size.
*/
@@ -1853,12 +1862,12 @@ p_story_call_player(GapStbMainGlobalParams *sgpp
previewWidth = 320;
previewHeight = previewWidth * (stb_dup->master_height / MAX(stb_dup->master_width,1));
}
-
+
stb_dup->master_width = MIN(stb_dup->master_width, previewWidth);
stb_dup->master_height = MIN(stb_dup->master_height, previewHeight);
}
}
-
+
}
if(sgpp->plp)
@@ -5424,7 +5433,7 @@ p_menu_win_render_properties_cb (GtkWidget *widget, GapStbMainGlobalParams *sgpp
{
static GapArrArg argv[8];
gint l_ii;
-
+
gint l_stb_max_open_videofile_idx;
gint l_stb_fcache_size_per_videofile_idx;
gint l_ffetch_max_img_cache_elements_idx;
@@ -5432,7 +5441,7 @@ p_menu_win_render_properties_cb (GtkWidget *widget, GapStbMainGlobalParams *sgpp
gint l_stb_preview_render_full_size_idx;
gint l_stb_isMultithreadEnabled_idx;
gint l_stb_isMultithreadFfEncoderEnabled_idx;
-
+
gint multithreadDefaultFlag;
gboolean l_rc;
@@ -5532,7 +5541,7 @@ p_menu_win_render_properties_cb (GtkWidget *widget, GapStbMainGlobalParams *sgpp
argv[l_ii].constraint = TRUE;
argv[l_ii].label_txt = _("Multiprocessor Storyboard Support:");
argv[l_ii].help_txt = _("ON: Rendering of composite storyboard frames uses more than one processor. "
- "(reading frames from videoclips is done by parallel running prefetch processing) "
+ "(reading frames from videoclips is done by parallel running prefetch processing) "
"OFF: Rendering of composite frames uses only one processor.");
argv[l_ii].int_ret = (gint)sgpp->stb_isMultithreadEnabled;
argv[l_ii].has_default = TRUE;
@@ -5544,7 +5553,7 @@ p_menu_win_render_properties_cb (GtkWidget *widget, GapStbMainGlobalParams *sgpp
argv[l_ii].constraint = TRUE;
argv[l_ii].label_txt = _("Multiprocessor Encoder Support:");
argv[l_ii].help_txt = _("ON: Video encoders shall use more than one processor where implemented. "
- "The ffmpeg based video encoder implementation supports parallel processing. "
+ "The ffmpeg based video encoder implementation supports parallel processing. "
"OFF: Video encoders use only one processor.");
argv[l_ii].int_ret = (gint)gap_base_get_gimprc_gboolean_value(
GAP_GIMPRC_VIDEO_ENCODER_FFMPEG_MULTIPROCESSOR_ENABLE
@@ -5568,7 +5577,7 @@ p_menu_win_render_properties_cb (GtkWidget *widget, GapStbMainGlobalParams *sgpp
if(l_rc == TRUE)
{
gboolean isFFMpegEncoderMultiprocessorSupport;
-
+
sgpp->stb_max_open_videofile = argv[l_stb_max_open_videofile_idx].int_ret;
sgpp->stb_fcache_size_per_videofile = argv[l_stb_fcache_size_per_videofile_idx].int_ret;
sgpp->ffetch_max_img_cache_elements = argv[l_ffetch_max_img_cache_elements_idx].int_ret;
@@ -5581,7 +5590,7 @@ p_menu_win_render_properties_cb (GtkWidget *widget, GapStbMainGlobalParams *sgpp
p_save_gimprc_gboolean_value(GAP_GIMPRC_VIDEO_ENCODER_FFMPEG_MULTIPROCESSOR_ENABLE
, isFFMpegEncoderMultiprocessorSupport
);
-
+
}
} /* end p_menu_win_render_properties_cb */
@@ -8430,6 +8439,129 @@ p_reset_progress_bars(GapStbMainGlobalParams *sgpp)
} /* end p_reset_progress_bars */
+/* --------------------------------------
+ * p_storyboard_init_from_creation_params
+ * --------------------------------------
+ * creates an inital storyboard that includes one inital clip
+ * from the specified GapStbCreationParams.
+ */
+static void
+p_storyboard_init_from_creation_params(
+ GapStbTabWidgets *tabw
+ , GapStbMainGlobalParams *sgpp
+ , GapStoryBoard *stb
+ , GapStbCreationParams *scrp
+ )
+{
+ GapStoryRecordType record_type;
+
+ stb->master_width = scrp->vid_width;
+ stb->master_height = scrp->vid_height;
+ stb->master_framerate = scrp->framerate;
+
+ stb->master_volume = 1.0;
+ stb->master_samplerate = scrp->samplerate;
+
+ stb->master_aspect_ratio = scrp->aspect_ratio; /* 0.0 for none */
+ stb->master_aspect_width = scrp->aspect_width;
+ stb->master_aspect_height = scrp->aspect_height;
+
+ stb->stb_section = NULL;
+ stb->storyboardfile = NULL;
+ if(scrp->storyboard_filename[0] != '\0')
+ {
+ stb->storyboardfile = g_strdup(scrp->storyboard_filename);
+ }
+
+ if (scrp->preferred_decoder[0] != '\0')
+ {
+ stb->preferred_decoder = g_strdup(scrp->preferred_decoder);
+ }
+
+ /* refresh storyboard layout and thumbnail list widgets */
+ p_recreate_tab_widgets( stb
+ ,tabw
+ ,tabw->mount_col
+ ,tabw->mount_row
+ ,sgpp
+ );
+ p_render_all_frame_widgets(tabw);
+ p_widget_sensibility(sgpp);
+
+ /* creation of one inital clip */
+
+ switch (scrp->record_type_int)
+ {
+ case 0:
+ record_type = GAP_STBREC_VID_MOVIE;
+ break;
+ case 1:
+ record_type = GAP_STBREC_VID_IMAGE;
+ break;
+ case 2:
+ record_type = GAP_STBREC_VID_FRAMES;
+ break;
+ case 3:
+ record_type = GAP_STBREC_VID_ANIMIMAGE;
+ break;
+ default:
+ record_type = GAP_STBREC_VID_UNKNOWN;
+ break;
+ }
+
+ if (record_type != GAP_STBREC_VID_UNKNOWN)
+ {
+ GapStoryElem *stb_elem;
+
+ stb_elem = gap_story_new_elem(record_type);
+ if(stb_elem)
+ {
+ stb_elem->orig_filename = g_strdup(scrp->filename);
+ stb_elem->track = tabw->vtrack;
+ stb_elem->from_frame = scrp->from_frame;
+ stb_elem->to_frame = scrp->to_frame;
+ stb_elem->nloop = scrp->nloop;
+ stb_elem->nframes = (1 + abs(scrp->to_frame - scrp->from_frame) ) * scrp->nloop;
+
+ stb_elem->seltrack = scrp->vidtrack;
+ stb_elem->exact_seek = scrp->exact_seek;
+ stb_elem->delace = 0.0;
+ if (scrp->delace_mode != 0)
+ {
+ stb_elem->delace = scrp->delace_mode + CLAMP(scrp->delace_threshold, 0.0, 0.999999);
+ }
+
+ if (scrp->preferred_decoder[0] != '\0')
+ {
+ stb_elem->preferred_decoder = g_strdup(scrp->preferred_decoder);
+ }
+
+
+
+ gap_stb_undo_group_begin(tabw);
+ gap_stb_undo_push(tabw, GAP_STB_FEATURE_CREATE_CLIP);
+
+ gap_story_list_append_elem(stb, stb_elem);
+
+ /* refresh storyboard layout and thumbnail list widgets */
+ p_recreate_tab_widgets( stb
+ ,tabw
+ ,tabw->mount_col
+ ,tabw->mount_row
+ ,sgpp
+ );
+ p_render_all_frame_widgets(tabw);
+ // gap_story_stb_elem_properties_dialog(tabw, stb_elem, stb);
+ gap_stb_undo_group_end(tabw);
+ }
+
+ p_tabw_update_frame_label_and_rowpage_limits(tabw, sgpp);
+
+ }
+
+
+} /* end p_storyboard_new_from_creation_params */
+
/* -----------------------------
@@ -8437,7 +8569,7 @@ p_reset_progress_bars(GapStbMainGlobalParams *sgpp)
* -----------------------------
*/
void
-gap_storyboard_dialog(GapStbMainGlobalParams *sgpp)
+gap_storyboard_dialog(GapStbMainGlobalParams *sgpp, GapStbCreationParams *scrp)
{
GtkWidget *dialog;
GtkWidget *vbox;
@@ -8784,6 +8916,14 @@ gap_storyboard_dialog(GapStbMainGlobalParams *sgpp)
*/
ffetch_user_id = gap_frame_fetch_register_user("gap_storyboard_dialog");
+ if (scrp != NULL)
+ {
+ /* create an initial cliplist according to creation parameters */
+ sgpp->cll = gap_story_new_story_board(NULL);
+ sgpp->cll->master_type = GAP_STB_MASTER_TYPE_CLIPLIST;
+ p_storyboard_init_from_creation_params(sgpp->cll_widgets, sgpp, sgpp->cll, scrp);
+ }
+
gtk_main ();
gdk_flush ();
@@ -9338,7 +9478,7 @@ p_tabw_master_prop_dialog(GapStbTabWidgets *tabw, gboolean new_flag)
stb_dst->master_width = (gint32)(argv[l_ii_width].int_ret);
stb_dst->master_height = (gint32)(argv[l_ii_height].int_ret);
- stb_dst->master_framerate = (gint32)(argv[l_ii_framerate].flt_ret);
+ stb_dst->master_framerate = (gdouble)(argv[l_ii_framerate].flt_ret);
stb_dst->master_vtrack1_is_toplayer = (argv[l_ii_vtrack1_is_toplayer].int_ret != 0);
p_parse_aspect_width_and_height(buf_aspect_string
diff --git a/gap/gap_story_dialog.h b/gap/gap_story_dialog.h
index da63ebb..61a6ca7 100644
--- a/gap/gap_story_dialog.h
+++ b/gap/gap_story_dialog.h
@@ -32,7 +32,7 @@
#include "gap_story_main.h"
#include "gap_story_properties.h"
-void gap_storyboard_dialog(GapStbMainGlobalParams *gpp);
+void gap_storyboard_dialog(GapStbMainGlobalParams *sgpp, GapStbCreationParams *scrp);
void gap_story_dlg_attw_render_all(GapStbAttrWidget *attw);
diff --git a/gap/gap_story_main.c b/gap/gap_story_main.c
index 2fd123a..2ab5a2b 100644
--- a/gap/gap_story_main.c
+++ b/gap/gap_story_main.c
@@ -50,7 +50,7 @@ static char *plug_in_version_fmt = "%d.%d.%d; 2004/01/26";
#define PLUG_IN_COPYRIGHT "Wolfgang Hofer"
-int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */
+int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */
static GapStbMainGlobalParams global_params =
{
@@ -151,6 +151,31 @@ static GimpParamDef in_args[] = {
{ GIMP_PDB_DRAWABLE, "drawable", "UNUSED"},
};
+
+static GimpParamDef in_create_args[] = {
+ { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"},
+ { GIMP_PDB_IMAGE, "image", "Input image" },
+ { GIMP_PDB_STRING, "storyboard_filename", "name of the storyboard file (to be created)"},
+ { GIMP_PDB_STRING, "filename", "name of the video or image file (to be added as initial clip)"},
+ { GIMP_PDB_STRING, "preferred_decoder", "NULL, or one of: libmpeg3, quicktime4linux, libavformat"},
+ { GIMP_PDB_INT32, "vid_width", "storyboard master width in pixels"},
+ { GIMP_PDB_INT32, "vid_height", "storyboard master height in pixels"},
+ { GIMP_PDB_FLOAT, "framerate", "storyboard master frame rate in frames per second"},
+ { GIMP_PDB_FLOAT, "aspect_ratio", "aspect ratio (0.0 for undefined)"},
+ { GIMP_PDB_INT32, "aspect_width", "aspect width (optional 16 for 16:9)"},
+ { GIMP_PDB_INT32, "aspect_height", "aspect height (optional 9 for 16:9)"},
+ { GIMP_PDB_FLOAT, "samplerate", "audio samplerate in Hz"},
+ { GIMP_PDB_INT32, "record_type_int", "0: video, 1:image, 2:frame images, 3:anim image"},
+ { GIMP_PDB_INT32, "from_frame", "frame number for start of clip range"},
+ { GIMP_PDB_INT32, "to_frame", "frame number for end of clip range"},
+ { GIMP_PDB_INT32, "vidtrack", "selected video track (first valid track number is 1)"},
+ { GIMP_PDB_INT32, "delace_mode", "0:no deinterlacing, 1: odd rows 2: even rows 3: odd first 4: even first"},
+ { GIMP_PDB_FLOAT, "delace_threshold", "deinterlace threshold"},
+ { 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, "nloop", "number of repetitions for this clip"},
+ };
+
+
/* Functions */
MAIN ()
@@ -165,7 +190,7 @@ static void query (void)
,GAP_MINOR_VERSION
,GAP_MICRO_VERSION
);
-
+
gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR);
/* the actual installation of the plugin */
@@ -185,10 +210,30 @@ static void query (void)
in_args,
NULL /* out_args */
);
-
+
// gimp_plugin_menu_branch_register("<Image>", "Video");
gimp_plugin_menu_register (GAP_STORY_PLUG_IN_PROC, N_("<Image>/Video/"));
-
+
+
+ /* register additional create and edit plug in (API to be called from other plug-ins) */
+ gimp_install_procedure (GAP_STORY_PLUG_IN_PROC_CREATION,
+ "Storyboard create and edit",
+ "This plug-in is an interactive GUI to create and edit storyboard level1 files, "
+ "This procedure is an API intended to be called from other plug-ins"
+ "(see example call in the video extraction plug-in)",
+ PLUG_IN_AUTHOR,
+ PLUG_IN_COPYRIGHT,
+ l_plug_in_version,
+ NULL, /* do not appear in menu */
+ PLUG_IN_IMAGE_TYPES,
+ GIMP_PLUGIN,
+ G_N_ELEMENTS (in_create_args),
+ 0, /* G_N_ELEMENTS (out_args) */
+ in_create_args,
+ NULL /* out_args */
+ );
+
+
g_free(l_plug_in_version);
} /* end query */
@@ -199,15 +244,19 @@ run (const gchar *name, /* name of plugin */
gint *nreturn_vals, /* number of out-parameters */
GimpParam ** return_vals) /* out-parameters */
{
+ GapStbCreationParams creationParams;
+ GapStbCreationParams *scrp;
const gchar *l_env;
gint32 image_id = -1;
GapStbMainGlobalParams *sgpp = &global_params;
+ scrp = NULL;
+
/* 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
+ * during non-interactive calling
*/
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
@@ -236,6 +285,8 @@ run (const gchar *name, /* name of plugin */
image_id = param[1].data.d_int32;
+
+
switch (run_mode)
{
case GIMP_RUN_INTERACTIVE:
@@ -244,14 +295,18 @@ run (const gchar *name, /* name of plugin */
break;
case GIMP_RUN_NONINTERACTIVE:
- /* check to see if invoked with the correct number of parameters */
- /* if (nparams == G_N_ELEMENTS (in_args)) */
+ if (strcmp (name, GAP_STORY_PLUG_IN_PROC) == 0)
{
printf("%s: noninteractive call NOT supported.\n"
, GAP_STORY_PLUG_IN_PROC
);
status = GIMP_PDB_CALLING_ERROR;
}
+ /* Note that the API GAP_STORY_PLUG_IN_PROC_CREATION)
+ * is typically called from other plug-ins with runmode GIMP_RUN_NONINTERACTIVE
+ * (this also runs the interactive editor dialog but creates an initial storyboard
+ * from the parameters of the non-interactive call..)
+ */
break;
case GIMP_RUN_WITH_LAST_VALS:
@@ -264,17 +319,77 @@ run (const gchar *name, /* name of plugin */
break;
}
+ /* check for the additional create+edit API */
+ if (strcmp (name, GAP_STORY_PLUG_IN_PROC_CREATION) == 0)
+ {
+ /* check to see if invoked with the correct number of parameters */
+ if (nparams == G_N_ELEMENTS (in_create_args))
+ {
+ gint ii;
+
+ scrp = &creationParams;
+ ii = 2;
+ if(param[ii].data.d_string != NULL)
+ {
+ strncpy(scrp->storyboard_filename, param[ii].data.d_string, GAP_STORY_MAX_STORYFILENAME_LEN -1);
+ scrp->storyboard_filename[GAP_STORY_MAX_STORYFILENAME_LEN -1] = '\0';
+ }
+ ii++;
+
+ if(param[ii].data.d_string != NULL)
+ {
+ strncpy(scrp->filename, param[ii].data.d_string, GAP_STORY_MAX_STORYFILENAME_LEN -1);
+ scrp->filename[GAP_STORY_MAX_STORYFILENAME_LEN -1] = '\0';
+ }
+ ii++;
+
+ if(param[ii].data.d_string != NULL)
+ {
+ strncpy(scrp->preferred_decoder, param[ii].data.d_string, GAP_STORY_MAX_STORYFILENAME_LEN -1);
+ scrp->preferred_decoder[GAP_STORY_MAX_STORYFILENAME_LEN -1] = '\0';
+ }
+ ii++;
+
+ scrp->vid_width = param[ii++].data.d_int32;
+ scrp->vid_height = param[ii++].data.d_int32;
+ scrp->framerate = param[ii++].data.d_float;
+ scrp->aspect_ratio = param[ii++].data.d_float;;
+ scrp->aspect_width = param[ii++].data.d_int32;
+ scrp->aspect_height = param[ii++].data.d_int32;
+ scrp->samplerate = param[ii++].data.d_float;
+
+ /* Clip parameters */
+ scrp->record_type_int = param[ii++].data.d_int32;
+ scrp->from_frame = param[ii++].data.d_int32;
+ scrp->to_frame = param[ii++].data.d_int32;
+ scrp->vidtrack = param[ii++].data.d_int32;
+ scrp->delace_mode = param[ii++].data.d_int32;
+ scrp->delace_threshold = param[ii++].data.d_float;
+ scrp->exact_seek = param[ii++].data.d_int32;
+ scrp->nloop = param[ii++].data.d_int32;
+ }
+ else
+ {
+ printf("%s: wrong number of parameters got: %d but expected:%d.\n"
+ , name
+ , nparams
+ , G_N_ELEMENTS (in_create_args)
+ );
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+ }
+
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);
-
+ gap_storyboard_dialog(sgpp, scrp);
+
/* Store variable states for next run */
if (run_mode == GIMP_RUN_INTERACTIVE)
gimp_set_data (GAP_STORY_PLUG_IN_PROC, sgpp, sizeof (GapStbMainGlobalParams));
diff --git a/gap/gap_story_main.h b/gap/gap_story_main.h
old mode 100755
new mode 100644
index 056ec41..b25af4e
--- a/gap/gap_story_main.h
+++ b/gap/gap_story_main.h
@@ -40,6 +40,7 @@
#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_PLUG_IN_PROC_CREATION "plug_in_gap_storyboard_create_and_edit"
#define GAP_STORY_MAX_STORYFILENAME_LEN 2048
#define GAP_STORY_MAX_CLIP_WIDGETS 2000
@@ -55,6 +56,7 @@ typedef gpointer t_GVA_Handle;
#endif
#endif
+#define GAP_GIMPRC_ENABLE_STORYBOARD_DEBUG_FEATURES "video-enable-storyboard-debug-features"
#define GAP_STB_ATT_GFX_ARRAY_MAX 2
@@ -323,7 +325,7 @@ typedef struct GapStbAttrWidget /* nickname: attw */
GtkWidget *button_overlap_dur;
GtkWidget *comment_entry;
-
+
GtkWidget *movepath_edit_button;
GtkWidget *movepath_file_entry;
GtkWidget *movepath_filesel;
@@ -518,4 +520,34 @@ typedef struct GapStbMainGlobalParams /* nickname: sgpp */
} GapStbMainGlobalParams;
+typedef struct GapStbCreationParams /* nickname: scrp */
+{
+ gchar storyboard_filename[GAP_STORY_MAX_STORYFILENAME_LEN];
+ gint32 vid_width;
+ gint32 vid_height;
+ gdouble framerate;
+
+ gdouble aspect_ratio;
+ gint32 aspect_width;
+ gint32 aspect_height;
+
+ gdouble samplerate; // from audio track or default 44100 if no audio available...
+ gchar preferred_decoder[GAP_STORY_MAX_STORYFILENAME_LEN];
+
+ /* Clip parameters */
+ gint32 record_type_int;
+
+
+ gchar filename[GAP_STORY_MAX_STORYFILENAME_LEN];
+ gint32 from_frame;
+ gint32 to_frame;
+ gint32 vidtrack;
+ gdouble delace_threshold;
+ gint32 delace_mode;
+ gint32 exact_seek;
+ gint32 nloop;
+
+
+} GapStbCreationParams;
+
#endif
diff --git a/gap/gap_story_render_audio.c b/gap/gap_story_render_audio.c
index d8e380e..4e020ff 100644
--- a/gap/gap_story_render_audio.c
+++ b/gap/gap_story_render_audio.c
@@ -4,12 +4,29 @@
* GAP storyboard audio rendering.
*
*/
+/* 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.
+ */
/*
* 2006.06.25 hof - created (moved stuff from the former gap_gve_story modules to this new module)
*
*/
-
+
#include <config.h>
/* SYTEM (UNIX) includes */
@@ -201,7 +218,7 @@ gap_story_render_remove_tmp_audiofiles(GapStoryRenderVidHandle *vidhand)
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)
*/
@@ -821,7 +838,7 @@ p_extract_audioblock(t_GVA_Handle *gvahand
}
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)) ;
@@ -880,7 +897,7 @@ p_extract_audiopart(t_GVA_Handle *gvahand
{
printf("p_extract_audiopart: START\n");
}
-
+
l_audio_channels = gvahand->audio_cannels;
l_sample_rate = gvahand->samplerate;
@@ -889,7 +906,7 @@ p_extract_audiopart(t_GVA_Handle *gvahand
{
return;
}
-
+
samples_to_skip = min_play_sec * (gdouble)l_sample_rate;
GVA_seek_audio(gvahand, 0.0, GVA_UPOS_SECS);
@@ -1121,7 +1138,7 @@ gap_story_render_audio_new_audiorange_element(GapStoryRenderAudioType aud_type
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)
@@ -1169,9 +1186,37 @@ gap_story_render_audio_new_audiorange_element(GapStoryRenderAudioType aud_type
}
if(l_audscan_required)
{
-#ifdef GAP_ENABLE_VIDEOAPI_SUPPORT
+ gboolean movieIsExtractedAudio = FALSE;
+
if(aud_type == GAP_AUT_MOVIE)
{
+ 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 (l_rc == 0)
+ {
+ /* the movie filename refers to an already extracted RIFF WAVE audiofile.
+ * Assume that this external audiotrack has full videolength.
+ * in this case force audio processing without offset (e.g. set min_play_sec to 0).
+ * Note that this special case is a workarond in case of unsupported audio codec
+ * where the extraction my be done manually via other tools (that supports the codec)
+ * and allows to access the extracted (external) audiotrack
+ * in the storyboard by frame numbers just like a movie internal audiotrack.
+ */
+ movieIsExtractedAudio = TRUE;
+ min_play_sec = 0;
+ }
+ }
+#ifdef GAP_ENABLE_VIDEOAPI_SUPPORT
+ if((aud_type == GAP_AUT_MOVIE) && (movieIsExtractedAudio == FALSE))
+ {
t_GVA_Handle *gvahand;
if(preferred_decoder)
@@ -1196,7 +1241,7 @@ gap_story_render_audio_new_audiorange_element(GapStoryRenderAudioType aud_type
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);
@@ -1254,8 +1299,8 @@ gap_story_render_audio_new_audiorange_element(GapStoryRenderAudioType aud_type
, vidhand
);
GVA_close(gvahand);
-
-
+
+
if(vidhand->status_msg)
{
g_snprintf(vidhand->status_msg, vidhand->status_msg_len
@@ -1348,8 +1393,8 @@ gap_story_render_audio_new_audiorange_element(GapStoryRenderAudioType aud_type
}
}
#endif
-
- if(aud_type == GAP_AUT_AUDIOFILE)
+
+ if((aud_type == GAP_AUT_AUDIOFILE) || (movieIsExtractedAudio == TRUE))
{
if(g_file_test(aud_elem->audiofile, G_FILE_TEST_EXISTS))
{
@@ -1402,7 +1447,7 @@ gap_story_render_audio_new_audiorange_element(GapStoryRenderAudioType aud_type
{
if(create_audio_tmp_files)
{
-
+
if(vidhand->status_msg)
{
g_snprintf(vidhand->status_msg, vidhand->status_msg_len
@@ -1411,7 +1456,7 @@ gap_story_render_audio_new_audiorange_element(GapStoryRenderAudioType aud_type
}
/* 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
@@ -1427,7 +1472,7 @@ gap_story_render_audio_new_audiorange_element(GapStoryRenderAudioType aud_type
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))
@@ -1447,14 +1492,14 @@ gap_story_render_audio_new_audiorange_element(GapStoryRenderAudioType aud_type
{
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);
diff --git a/gap/gap_story_render_processor.c b/gap/gap_story_render_processor.c
index b9d7dd1..bbf6440 100644
--- a/gap/gap_story_render_processor.c
+++ b/gap/gap_story_render_processor.c
@@ -365,6 +365,8 @@ static GapStoryRenderVidHandle * p_open_video_handle_private( gboolean ignore
, gdouble delace
, gboolean compensate_framerange
, GapStoryBoard *stb_mem_ptr
+ , char *util_sox
+ , char *util_sox_options
);
static gint32 p_exec_filtermacro(gint32 image_id
, gint32 layer_id
@@ -3588,6 +3590,8 @@ p_open_mask_vidhand(GapStoryElem *stb_elem, GapStoryRenderMaskDefElem *maskdef_e
,stb_elem->delace
,FALSE /* compensate_framerange */
,NULL /* stb_mem_ptr */
+ ,NULL /* util_sox */
+ ,NULL /* util_sox_options */
);
if(maskdef_elem->mask_vidhand)
{
@@ -4086,6 +4090,8 @@ p_open_video_handle_private( gboolean ignore_audio
, gdouble delace
, gboolean compensate_framerange
, GapStoryBoard *stb_mem_ptr
+ , char *util_sox
+ , char *util_sox_options
)
{
GapStoryRenderVidHandle *vidhand;
@@ -4147,8 +4153,10 @@ p_open_video_handle_private( gboolean ignore_audio
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->util_sox = NULL;
+ vidhand->util_sox_options = NULL;
+ gap_story_render_set_audio_resampling_program(vidhand, util_sox, util_sox_options);
+
vidhand->ignore_audio = ignore_audio;
vidhand->ignore_video = ignore_video;
vidhand->create_audio_tmp_files = create_audio_tmp_files;
@@ -4509,6 +4517,8 @@ gap_story_render_open_extended_video_handle( gboolean ignore_audio
, gint32 frame_from
, gint32 frame_to
, gint32 *frame_count /* output total frame_count , or 0 on failure */
+ , char *util_sox
+ , char *util_sox_options
)
{
return(p_open_video_handle_private( ignore_audio /* ignore_audio */
@@ -4532,6 +4542,8 @@ gap_story_render_open_extended_video_handle( gboolean ignore_audio
,0.0 /* delace */
,TRUE /* compensate_framerange */
,NULL /* stb_mem_ptr */
+ ,util_sox
+ ,util_sox_options
)
);
@@ -4581,6 +4593,8 @@ gap_story_render_open_vid_handle_from_stb(GapStoryBoard *stb_mem_ptr
,0.0 /* delace */
,TRUE /* compensate_framerange */
,stb_mem_ptr /* stb_mem_ptr */
+ ,NULL /* util_sox */
+ ,NULL /* util_sox_options */
);
}
@@ -4645,6 +4659,8 @@ gap_story_render_open_vid_handle(GapLibTypeInputRange input_mode
,0.0 /* delace */
,TRUE /* compensate_framerange */
,NULL /* stb_mem_ptr */
+ ,NULL /* util_sox */
+ ,NULL /* util_sox_options */
);
if(imagename)
diff --git a/gap/gap_story_render_processor.h b/gap/gap_story_render_processor.h
index 891ca9b..0827305 100644
--- a/gap/gap_story_render_processor.h
+++ b/gap/gap_story_render_processor.h
@@ -334,6 +334,8 @@ GapStoryRenderVidHandle * gap_story_render_open_extended_video_handle(
,gint32 frame_from
,gint32 frame_to
,gint32 *frame_count /* output total frame_count , or 0 on failure */
+ ,char *util_sox
+ ,char *util_sox_options
);
void gap_story_render_close_vid_handle(GapStoryRenderVidHandle *vidhand);
diff --git a/gap/gap_vex_dialog.c b/gap/gap_vex_dialog.c
index beb30b9..e5eb972 100644
--- a/gap/gap_vex_dialog.c
+++ b/gap/gap_vex_dialog.c
@@ -87,6 +87,8 @@ 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__combo_mode_multilayer (GtkWidget *widget,
+ GapVexMainGlobalParams *gpp);
static void on_mw__checkbutton_bluebox_toggled (GtkToggleButton *togglebutton,
GapVexMainGlobalParams *gpp);
@@ -116,8 +118,6 @@ static void on_mw__entry_audiofile_changed (GtkEditable *edit
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);
@@ -392,7 +392,7 @@ p_update_wgt_sensitivity(GapVexMainGlobalParams *gpp)
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__combo_mode_multilayer, sensitive);
gtk_widget_set_sensitive(gpp->mw__checkbutton_generate_alpha_via_bluebox, sensitive);
if(gpp->val.generate_alpha_via_bluebox != TRUE)
@@ -492,11 +492,6 @@ p_init_mw__main_window_widgets (GapVexMainGlobalParams *gpp)
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 );
@@ -696,30 +691,6 @@ p_call_player_widget(GapVexMainGlobalParams *gpp
/* -------------------
- * 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
@@ -912,7 +883,7 @@ on_mw__combo_preferred_decoder (GtkWidget *widget,
break;
}
g_snprintf(gpp->val.preferred_decoder, sizeof(gpp->val.preferred_decoder)
- , "%s", preferred_decoder
+ , "%s", preferred_decoder
);
entry = GTK_ENTRY(gpp->mw__entry_preferred_decoder);
if(entry)
@@ -963,6 +934,34 @@ on_mw__combo_deinterlace (GtkWidget *widget,
} /* end on_mw__combo_deinterlace */
+/* ------------------------------
+ * on_mw__combo_mode_multilayer
+ * ------------------------------
+ */
+static void
+on_mw__combo_mode_multilayer (GtkWidget *widget,
+ GapVexMainGlobalParams *gpp)
+{
+ gint l_idx;
+ gint value;
+ gboolean sensitive;
+
+ if(gap_debug) printf("CB: on_mw__combo_mode_multilayer\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_mode_multilayer index: %d\n", (int)l_idx);
+
+ gpp->val.multilayer = l_idx;
+
+ p_update_wgt_sensitivity(gpp);
+
+} /* end on_mw__combo_mode_multilayer */
+
+
/* --------------------------------
* on_mw__checkbutton_bluebox_toggled
* --------------------------------
@@ -1368,32 +1367,6 @@ on_mw__button_audiofile_clicked (GtkButton *button,
}
}
-/* --------------------------------
- * 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
@@ -1993,7 +1966,7 @@ gap_vex_dlg_create_mw__main_window (GapVexMainGlobalParams *gpp)
GtkWidget *mw__label_audifile;
GtkWidget *mw__entry_audiofile;
GtkWidget *mw__button_audiofile;
- GtkWidget *mw__checkbutton_multilayer;
+ GtkWidget *mw__combo_mode_multilayer;
GtkWidget *mw__combo_deinterlace;
GtkObject *mw__spinbutton_delace_threshold_adj;
GtkWidget *mw__spinbutton_delace_threshold;
@@ -2337,11 +2310,7 @@ gap_vex_dlg_create_mw__main_window (GapVexMainGlobalParams *gpp)
"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);
+ gpp->mw__combo_preferred_decoder = mw__combo_preferred_decoder;
gtk_widget_show (mw__combo_preferred_decoder);
wgt_array[wgt_idx] = mw__combo_preferred_decoder;
@@ -2443,16 +2412,20 @@ gap_vex_dlg_create_mw__main_window (GapVexMainGlobalParams *gpp)
(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,
+ /* the multilayer combo box (decide if extract writes to frames on disc or to one image or storyboard) */
+ mw__combo_mode_multilayer =
+ gimp_int_combo_box_new (_("extracted frames are written to frame files on disc"), 0,
+ _("extracted frames are stored in one multilayer image"), 1,
+ _("create a storyboard from selected video clip"), 2,
+ NULL);
+ gpp->mw__combo_mode_multilayer = mw__combo_mode_multilayer;
+
+
+
+ gtk_widget_show (mw__combo_mode_multilayer);
+ gtk_table_attach (GTK_TABLE (mw__table_out), mw__combo_mode_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++;
@@ -2668,11 +2641,7 @@ gap_vex_dlg_create_mw__main_window (GapVexMainGlobalParams *gpp)
_("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);
+ gpp->mw__combo_deinterlace = mw__combo_deinterlace;
gtk_widget_show (mw__combo_deinterlace);
@@ -2726,6 +2695,41 @@ gap_vex_dlg_create_mw__main_window (GapVexMainGlobalParams *gpp)
p_align_widget_columns(wgt_array, wgt_idx);
+ /* 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__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__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;
+
+
g_signal_connect (G_OBJECT (mw__checkbutton_disable_mmx), "toggled",
G_CALLBACK (on_mw__checkbutton_disable_mmx_toggled),
gpp);
@@ -2774,9 +2778,6 @@ gap_vex_dlg_create_mw__main_window (GapVexMainGlobalParams *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);
@@ -2787,43 +2788,22 @@ gap_vex_dlg_create_mw__main_window (GapVexMainGlobalParams *gpp)
G_CALLBACK (on_mw__spinbutton_fn_digits_changed),
gpp);
+ 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);
+
+ 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);
+
+ gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (mw__combo_mode_multilayer),
+ CLAMP(gpp->val.multilayer, 0, 2), /* initial value */
+ G_CALLBACK (on_mw__combo_mode_multilayer),
+ 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) */
diff --git a/gap/gap_vex_dialog.h b/gap/gap_vex_dialog.h
index 67489d4..0623cb9 100644
--- a/gap/gap_vex_dialog.h
+++ b/gap/gap_vex_dialog.h
@@ -31,7 +31,7 @@
#include "config.h"
-/* SYTEM (UNIX) includes */
+/* SYTEM (UNIX) includes */
#include <stdio.h>
#include <stdlib.h>
diff --git a/gap/gap_vex_exec.c b/gap/gap_vex_exec.c
index b24436f..b5ebee6 100644
--- a/gap/gap_vex_exec.c
+++ b/gap/gap_vex_exec.c
@@ -36,6 +36,8 @@
#include "gap_audio_extract.h"
#include "gap_bluebox.h"
+#define GAP_STORY_PLUG_IN_PROC_CREATION "plug_in_gap_storyboard_create_and_edit"
+
/* -------------------
* p_gap_set_framerate
* -------------------
@@ -55,7 +57,7 @@ p_gap_set_framerate(gint32 image_id, gdouble framerate)
GIMP_PDB_FLOAT, framerate,
GIMP_PDB_END);
- g_free(l_params);
+ g_free(l_params);
} /* end p_gap_set_framerate */
@@ -100,7 +102,7 @@ p_frame_postprocessing(t_GVA_Handle *gvahand
{
gint32 l_bbox_layer_id;
gint32 l_layermask_id;
-
+
l_bbox_layer_id = gvahand->layer_id;
if (gpp->val.generate_alpha_via_bluebox == TRUE)
{
@@ -114,7 +116,7 @@ p_frame_postprocessing(t_GVA_Handle *gvahand
{
printf("created bb_layer_id:%d\n", l_bbox_layer_id);
}
-
+
}
if (!gimp_drawable_has_alpha(l_bbox_layer_id))
{
@@ -133,7 +135,7 @@ p_frame_postprocessing(t_GVA_Handle *gvahand
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);
@@ -156,11 +158,172 @@ p_frame_postprocessing(t_GVA_Handle *gvahand
//gimp_drawable_delete(l_bbox_layer_id);
}
}
-
+
} /* end p_frame_postprocessing */
+/* ---------------------------------------------
+ * p_vex_exe_create_storyboard_from_videorange
+ * ---------------------------------------------
+ * calls a plug-in that creates a storyboard from the selected videorange
+ * and opens it into the storyboard editor dialog.
+ */
+static void
+p_vex_exe_create_storyboard_from_videorange(GapVexMainGlobalParams *gpp)
+{
+#ifdef GAP_ENABLE_VIDEOAPI_SUPPORT
+ t_GVA_Handle *gvahand;
+ GimpParam* l_params;
+ gint l_retvals;
+ gint l_rc;
+
+ char *l_storyboard_filename;
+ gdouble l_framerate;
+ gdouble l_samplerate;
+ gdouble l_aspect_ratio;
+ gint32 l_aspect_width;
+ gint32 l_aspect_height;
+ gint32 l_vid_width;
+ gint32 l_vid_height;
+ gint32 l_image_id;
+ gint32 l_record_type_int;
+ gint32 l_nloop;
+ gint32 l_from_frame;
+ gint32 l_to_frame;
+
+ if (gpp->val.videotrack <= 0)
+ {
+ printf("No valid videotrack was selected video %s\n", gpp->val.videoname);
+ return;
+ }
+
+ /* --------- 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)
+ {
+ printf("failed to open video %s\n", gpp->val.videoname);
+ return;
+ }
+ l_framerate = gvahand->framerate;
+ l_vid_width = gvahand->width;
+ l_vid_height = gvahand->height;
+ l_samplerate = 44100;
+ if ((gvahand->atracks > 0) && (gvahand->samplerate > 0))
+ {
+ l_samplerate = gvahand->samplerate;
+ }
+ l_aspect_ratio = 0.0;
+ l_aspect_width = 0;
+ l_aspect_height = 0;
+ if (gvahand->aspect_ratio > 0)
+ {
+ l_aspect_ratio = gvahand->aspect_ratio;
+
+ if(p_check_aspect(l_aspect_ratio, 3, 2))
+ {
+ l_aspect_width = 3;
+ l_aspect_height = 2;
+ }
+ if(p_check_aspect(l_aspect_ratio, 4, 3))
+ {
+ l_aspect_width = 4;
+ l_aspect_height = 3;
+ }
+ if(p_check_aspect(l_aspect_ratio, 16, 9))
+ {
+ l_aspect_width = 16;
+ l_aspect_height = 9;
+ }
+ }
+
+
+ /* extract the 1st frame as gimp image
+ * (for passing to the storyboard plug-in as active image
+ * -- that will be displayed in the player widget of the stroyboard dialog at startup --)
+ */
+ l_image_id = -1;
+ l_rc = GVA_seek_frame(gvahand, gpp->val.begin_frame, GVA_UPOS_FRAMES);
+ l_rc = GVA_get_next_frame(gvahand);
+
+ if(l_rc == GVA_RET_OK)
+ {
+ /* convert fetched frame from buffer to gimp image gvahand->image_id */
+ l_rc = GVA_frame_to_gimp_layer(gvahand
+ ,TRUE /* delete_mode */
+ ,gpp->val.begin_frame
+ ,0 /* delace */
+ ,0.0 /* delace_threshold */
+ );
+ if(l_rc == GVA_RET_OK)
+ {
+ l_image_id = gvahand->image_id;
+ if (l_image_id >= 0)
+ {
+ gimp_display_new(l_image_id);
+ }
+ }
+ }
+
+
+ GVA_close(gvahand);
+
+ if (l_image_id < 0)
+ {
+ g_message(_("failed to extract frame from video: %s"), gpp->val.videoname);
+ return;
+ }
+
+ l_record_type_int = 0; /* 0: video, 1:image, 2:frame images, 3:anim image */
+ l_nloop = 1;
+
+ l_storyboard_filename = g_strdup_printf("STORY_%s.txt", gpp->val.basename);
+ l_from_frame = gpp->val.begin_frame;
+ l_to_frame = gpp->val.end_frame;
+
+ /* call the stroryboard plug-in */
+ l_params = gimp_run_procedure (GAP_STORY_PLUG_IN_PROC_CREATION,
+ &l_retvals,
+ GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
+ GIMP_PDB_IMAGE, l_image_id,
+ GIMP_PDB_STRING, l_storyboard_filename,
+ GIMP_PDB_STRING, gpp->val.videoname,
+ GIMP_PDB_STRING, gpp->val.preferred_decoder,
+ GIMP_PDB_INT32, l_vid_width,
+ GIMP_PDB_INT32, l_vid_height,
+ GIMP_PDB_FLOAT, l_framerate,
+ GIMP_PDB_FLOAT, l_aspect_ratio,
+ GIMP_PDB_INT32, l_aspect_width,
+ GIMP_PDB_INT32, l_aspect_height,
+ GIMP_PDB_FLOAT, l_samplerate,
+ GIMP_PDB_INT32, l_record_type_int,
+ GIMP_PDB_INT32, l_from_frame,
+ GIMP_PDB_INT32, l_to_frame,
+ GIMP_PDB_INT32, gpp->val.videotrack,
+ GIMP_PDB_INT32, gpp->val.deinterlace,
+ GIMP_PDB_FLOAT, gpp->val.delace_threshold,
+ GIMP_PDB_INT32, gpp->val.exact_seek,
+ GIMP_PDB_INT32, l_nloop,
+ GIMP_PDB_END);
+
+ g_free(l_storyboard_filename);
+
+ l_rc = -1;
+ if (l_params[0].data.d_status == GIMP_PDB_SUCCESS)
+ {
+ l_rc = 0; /* OK */
+ }
+ gimp_destroy_params (l_params, l_retvals);
+
+#endif
+} /* end p_vex_exe_create_storyboard_from_videorange */
+
+
/* ------------------------------
* gap_vex_exe_extract_videorange
* ------------------------------
@@ -219,11 +382,17 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
printf("extract_with_layermask: %d\n", (int)gpp->val.extract_with_layermask);
}
+ if (gpp->val.multilayer >= 2)
+ {
+ p_vex_exe_create_storyboard_from_videorange(gpp);
+ return;
+ }
+
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
@@ -297,7 +466,7 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
iid_max = 2;
framenumber_fil = (framenumber * 2) -1;
- if(gpp->val.deinterlace == GAP_VEX_DELACE_ODD_X2)
+ if(gpp->val.deinterlace == GAP_VEX_DELACE_ODD_X2)
{
delace[0] = GAP_VEX_DELACE_ODD;
delace[1] = GAP_VEX_DELACE_EVEN;
@@ -334,7 +503,7 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
l_empty_layer_id = gimp_layer_new(l_dummy_image_id, "background",
32, 32,
GIMP_RGB_IMAGE,
- 100.0, /* Opacity full opaque */
+ 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);
@@ -343,7 +512,7 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
/* 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.
+ * depend on a key that includes the same basename and extension.
*/
l_dummyname = gap_lib_alloc_fname6(&gpp->val.basename[0]
,99999999
@@ -357,8 +526,8 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
);
gap_image_delete_immediate(l_dummy_image_id);
- g_remove(l_dummyname);
- g_free(l_dummyname);
+ g_remove(l_dummyname);
+ g_free(l_dummyname);
l_save_run_mode = GIMP_RUN_WITH_LAST_VALS; /* for all further calls */
}
@@ -376,7 +545,7 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
{
gint32 l_seekstep;
gint32 l_seek_framenumber;
-
+
if(1==1)
{
@@ -386,7 +555,7 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
else
{
/* dead code (older and slower seek emulation
- * implementation outside the API)
+ * implementation outside the API)
*/
l_seek_framenumber = l_pos;
if(l_pos_unit == GVA_UPOS_PRECENTAGE)
@@ -397,7 +566,7 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
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)
+ * (and proceed position to next frame)
*/
l_rc = GVA_get_next_frame(gvahand);
if(l_rc != GVA_RET_OK)
@@ -424,7 +593,7 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
while(1)
{
/* fetch one frame to buffer gvahand->frame_data
- * (and proceed position to next frame)
+ * (and proceed position to next frame)
*/
l_rc = GVA_get_next_frame(gvahand);
if(l_rc != GVA_RET_OK)
@@ -433,7 +602,7 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
}
if(gpp->val.multilayer == 0)
{
- if((gpp->val.deinterlace == GAP_VEX_DELACE_ODD_X2)
+ if((gpp->val.deinterlace == GAP_VEX_DELACE_ODD_X2)
|| (gpp->val.deinterlace == GAP_VEX_DELACE_EVEN_X2))
{
framenumber_fil = (framenumber * 2) -1;
@@ -472,16 +641,16 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
);
if (l_overwrite_mode < 0)
{
- g_free(framename);
+ 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)
{
@@ -493,7 +662,7 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
, framename
, l_save_run_mode
);
-
+
if (l_sav_image_id != gvahand->image_id)
{
/* delete temporary grayscale image */
@@ -505,7 +674,7 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
break;
}
}
- g_free(framename);
+ g_free(framename);
}
}
else
@@ -523,7 +692,7 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
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))
{
@@ -539,7 +708,7 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
break;
}
}
-
+
}
framenumber++;
@@ -571,9 +740,9 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
{
gdouble l_extracted_frames;
gboolean do_progress;
-
+
l_extracted_frames = framenumber - framenumber1;
-
+
do_progress = TRUE;
if(gpp->val.run_mode != GIMP_RUN_NONINTERACTIVE)
{
@@ -612,7 +781,7 @@ gap_vex_exe_extract_videorange(GapVexMainGlobalParams *gpp)
gimp_progress_update (l_progress);
}
-
+
if(gpp->val.image_ID >= 0)
{
gimp_image_undo_enable(gpp->val.image_ID);
diff --git a/gap/gap_vex_exec.h b/gap/gap_vex_exec.h
index 33a5ecb..ae6bf66 100644
--- a/gap/gap_vex_exec.h
+++ b/gap/gap_vex_exec.h
@@ -32,7 +32,7 @@
#include "config.h"
-/* SYTEM (UNIX) includes */
+/* SYTEM (UNIX) includes */
#include <stdio.h>
#include <stdlib.h>
diff --git a/gap/gap_vex_main.c b/gap/gap_vex_main.c
index 667ac00..7c59b12 100644
--- a/gap/gap_vex_main.c
+++ b/gap/gap_vex_main.c
@@ -63,7 +63,7 @@
#include "gap_vex_exec.h"
-int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */
+int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */
static void query (void);
@@ -104,7 +104,7 @@ query ()
{ GIMP_PDB_STRING, "basename", "The name for extracted ouput frames _0001.<extension> 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, "multilayer", "0: save each frame to one file, 1: load all frames into one multilayer image, 2: create storyboard with selected clip" },
{ 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" },
@@ -281,7 +281,7 @@ run (const gchar *name, /* name of plugin */
/* init return status
- * (if this plug-in is compiled without GAP_ENABLE_VIDEOAPI_SUPPORT
+ * (if this plug-in is compiled without GAP_ENABLE_VIDEOAPI_SUPPORT
* it will always fail)
*/
values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
@@ -390,9 +390,9 @@ run (const gchar *name, /* name of plugin */
values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
}
}
-
+
return;
-
+
/* endif GAP_ENABLE_VIDEOAPI_SUPPORT */
#endif
g_message(_("Videoextract is not available because "
diff --git a/gap/gap_vex_main.h b/gap/gap_vex_main.h
index 21b454f..8e3a15c 100644
--- a/gap/gap_vex_main.h
+++ b/gap/gap_vex_main.h
@@ -81,7 +81,7 @@ typedef struct {
gdouble begin_frame;
gdouble end_frame;
gint pos_unit; /* 0 .. frames, 2 percent */
- gint multilayer; /* 0 .. extract to single frames */
+ gint multilayer; /* 0 .. extract to single frames, 1 ..extract to multilayer image, 2.. create Stroyboard, 3 create + edit Storyboard */
gint disable_mmx; /* 0 .. use MMX if available, 1 disable MMX */
gint exact_seek; /* 0 .. NO, 1 .. YES */
gint deinterlace; /* 0 .. NO, 1 .. odd rows only, 2 even rows only, 3 .. odd first, 4 .. even first */
@@ -97,7 +97,7 @@ typedef struct {
gchar preferred_decoder[100];
- /* last checked videoname */
+ /* last checked videoname */
gboolean chk_is_compatible_videofile;
gint32 chk_total_frames;
gint32 chk_vtracks;
@@ -110,7 +110,7 @@ typedef struct {
/* current states of actual loaded (frame)image */
gint32 image_ID; /* -1 if there is no valid current image */
GimpRunMode run_mode;
-
+
gboolean generate_alpha_via_bluebox;
gboolean extract_alpha_as_gray_frames;
gboolean extract_with_layermask;
@@ -119,18 +119,18 @@ typedef struct {
typedef struct { /* nick: gpp */
GapVexMainVal val;
-
+
GapPlayerMainGlobalParams *plp; /* player widget parameters */
gboolean in_player_call;
gint32 video_width;
gint32 video_height;
gdouble video_speed; /* original playback speed in frames per sec */
-
+
GtkWidget *mw__main_window;
GtkWidget *fsv__fileselection;
GtkWidget *fsb__fileselection;
GtkWidget *fsa__fileselection;
-
+
GtkWidget *mw__player_frame;
GtkWidget *mw__checkbutton_disable_mmx;
GtkWidget *mw__entry_video;
@@ -157,7 +157,7 @@ typedef struct { /* nick: gpp */
GtkWidget *mw__spinbutton_basenum;
GtkWidget *mw__entry_audiofile;
GtkWidget *mw__button_audiofile;
- GtkWidget *mw__checkbutton_multilayer;
+ GtkWidget *mw__combo_mode_multilayer;
GtkWidget *mw__combo_deinterlace;
GtkObject *mw__spinbutton_delace_threshold_adj;
GtkWidget *mw__spinbutton_delace_threshold;
@@ -170,9 +170,32 @@ typedef struct { /* nick: gpp */
GtkWidget *mw__checkbutton_generate_alpha_via_bluebox;
GtkWidget *mw__checkbutton_extract_alpha_as_gray_frames;
GtkWidget *mw__checkbutton_extract_with_layermask;
-
+
} GapVexMainGlobalParams;
extern int gap_debug;
+/* -------------------
+ * p_check_aspect
+ * -------------------
+ */
+static 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 */
+
#endif
diff --git a/vid_common/gap_cme_gui.c b/vid_common/gap_cme_gui.c
index 23636c5..da9f9cb 100644
--- a/vid_common/gap_cme_gui.c
+++ b/vid_common/gap_cme_gui.c
@@ -1734,7 +1734,7 @@ p_thread_storyboard_file(gpointer data)
l_create_audio_tmp_files = TRUE;
}
- vidhand = gap_gve_story_open_extended_video_handle
+ vidhand = gap_story_render_open_extended_video_handle
( FALSE /* dont ignore video */
, FALSE /* dont ignore audio */
, l_create_audio_tmp_files
@@ -1749,15 +1749,13 @@ p_thread_storyboard_file(gpointer data)
, -1 /* frame_from */
, 999999 /* frame_to */
, &gpp->val.storyboard_total_frames
+ , gpp->val.util_sox
+ , gpp->val.util_sox_options
);
if(vidhand)
{
gstb->vidhand_open_ok = TRUE;
- gap_gve_story_set_audio_resampling_program(vidhand
- , gpp->val.util_sox
- , gpp->val.util_sox_options
- );
if(vidhand->master_framerate != 0.0)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]