Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

page_magick.cc

Go to the documentation of this file.
00001 /*
00002 * page_magick.cc -- FX Page definition
00003 * Copyright (C) 2002 Charles Yates <charles.yates@pandora.be>
00004 * Copyright (C) 2002-2007 Dan Dennedy <dan@dennedy.org>
00005 *
00006 * This program is free software; you can redistribute it and/or modify
00007 * it under the terms of the GNU General Public License as published by
00008 * the Free Software Foundation; either version 2 of the License, or
00009 * (at your option) any later version.
00010 *
00011 * This program is distributed in the hope that it will be useful,
00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 * GNU General Public License for more details.
00015 *
00016 * You should have received a copy of the GNU General Public License
00017 * along with this program; if not, write to the Free Software Foundation,
00018 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019 */
00020 
00021 
00022 #ifdef HAVE_CONFIG_H
00023 #include <config.h>
00024 #endif
00025 
00026 #include <iostream>
00027 #include <vector>
00028 using std::cerr;
00029 using std::endl;
00030 using std::vector;
00031 
00032 #include <string>
00033 #include <iostream>
00034 using std::cerr;
00035 using std::endl;
00036 
00037 #include <glade/glade.h>
00038 
00039 #include "kino_extra.h"
00040 #include "page_magick.h"
00041 #include "kino_common.h"
00042 #include "page.h"
00043 #include "storyboard.h"
00044 #include "page_editor.h"
00045 #include "displayer.h"
00046 #include "message.h"
00047 #include "error.h"
00048 #include "commands.h"
00049 #include "gtkenhancedscale.h"
00050 #include "export.h"
00051 
00055 PlayList &GetCurrentPlayList( )
00056 {
00057     return * common->getPlayList( );
00058 }
00059 
00060 extern "C"
00061 {
00062 #include "support.h"
00063 
00064 #include <fcntl.h>
00065 #include <sys/types.h>
00066 #include <sys/stat.h>
00067 #include <unistd.h>
00068 #include <dlfcn.h>
00069 #include <dirent.h>
00070 
00071     extern GladeXML* magick_glade;
00072     extern struct navigate_control g_nav_ctl;
00073 
00074     static bool buttonMutex = false;
00075 
00076     void
00077     on_togglebutton_magick_start_toggled ( GtkToggleButton * togglebutton,
00078                                            gpointer user_data )
00079     {
00080         if ( !buttonMutex )
00081         {
00082             buttonMutex = true;
00083             common->getPageMagick() ->StartRender();
00084             buttonMutex = false;
00085         }
00086     }
00087 
00088     void
00089     on_notebook_magick_switch_video_page ( GtkNotebook * notebook,
00090                                      GtkNotebookPage * page,
00091                                      gint page_num,
00092                                      gpointer user_data )
00093     {
00094         PageMagick* magick = common->getPageMagick();
00095         magick->SetKeyFrameControllerClient( 0 );
00096         magick->ShowCurrentStatus( magick->GetCurrentPosition(), LOCKED_KEY, false, false );
00097         videoStop();
00098         magick->OnTimeRangeChanged();
00099     }
00100 
00101     void
00102     on_notebook_magick_switch_page ( GtkNotebook * notebook,
00103                                      GtkNotebookPage * page,
00104                                      gint page_num,
00105                                      gpointer user_data )
00106     {
00107         PageMagick* magick = common->getPageMagick();
00108         videoStop();
00109         magick->OnTimeRangeChanged();
00110     }
00111 
00112     gboolean
00113     on_hscale_transition_start_button_press_event
00114     ( GtkWidget * widget,
00115       GdkEventButton * event,
00116       gpointer user_data )
00117     {
00118         GtkWidget * lower = lookup_widget ( common->getPageMagick() ->window, "hscale_transition_start" );
00119         GtkWidget *upper = lookup_widget ( common->getPageMagick() ->window, "hscale_transition_end" );
00120         GtkAdjustment *adjust_lower = GTK_RANGE( lower ) ->adjustment;
00121         GtkAdjustment *adjust_upper = GTK_RANGE( upper ) ->adjustment;
00122         adjust_upper->lower = adjust_lower->value;
00123         g_signal_emit_by_name( adjust_upper, "changed" );
00124         return FALSE;
00125     }
00126 
00127 
00128     gboolean
00129     on_hscale_transition_start_button_release_event
00130     ( GtkWidget * widget,
00131       GdkEventButton * event,
00132       gpointer user_data )
00133     {
00134         GtkWidget * lower = lookup_widget ( common->getPageMagick() ->window, "hscale_transition_start" );
00135         GtkWidget *upper = lookup_widget ( common->getPageMagick() ->window, "hscale_transition_end" );
00136         GtkAdjustment *adjust_lower = GTK_RANGE( lower ) ->adjustment;
00137         GtkAdjustment *adjust_upper = GTK_RANGE( upper ) ->adjustment;
00138         adjust_upper->lower = adjust_lower->value;
00139         g_signal_emit_by_name( adjust_upper, "changed" );
00140         common->getPageMagick() ->RefreshStatus( true );
00141         return FALSE;
00142     }
00143 
00144 
00145     gboolean
00146     on_hscale_transition_end_button_press_event
00147     ( GtkWidget * widget,
00148       GdkEventButton * event,
00149       gpointer user_data )
00150     {
00151         GtkWidget * lower = lookup_widget ( common->getPageMagick() ->window, "hscale_transition_start" );
00152         GtkWidget *upper = lookup_widget ( common->getPageMagick() ->window, "hscale_transition_end" );
00153         GtkAdjustment *adjust_lower = GTK_RANGE( lower ) ->adjustment;
00154         GtkAdjustment *adjust_upper = GTK_RANGE( upper ) ->adjustment;
00155         adjust_lower->upper = adjust_upper->value;
00156         g_signal_emit_by_name( adjust_lower, "changed" );
00157         return FALSE;
00158     }
00159 
00160 
00161     gboolean
00162     on_hscale_transition_end_button_release_event
00163     ( GtkWidget * widget,
00164       GdkEventButton * event,
00165       gpointer user_data )
00166     {
00167 
00168         GtkWidget * lower = lookup_widget ( common->getPageMagick() ->window, "hscale_transition_start" );
00169         GtkWidget *upper = lookup_widget ( common->getPageMagick() ->window, "hscale_transition_end" );
00170         GtkAdjustment *adjust_lower = GTK_RANGE( lower ) ->adjustment;
00171         GtkAdjustment *adjust_upper = GTK_RANGE( upper ) ->adjustment;
00172         adjust_lower->upper = adjust_upper->value;
00173         g_signal_emit_by_name( adjust_lower, "changed" );
00174         common->getPageMagick() ->RefreshStatus( true );
00175         return FALSE;
00176     }
00177 
00178     void
00179     on_button_magick_file_clicked    (GtkButton       *button,
00180                                             gpointer         user_data)
00181     {
00182         const char *filename = common->getFileToSave( _("Enter a File Name to Save As") );
00183         gtk_widget_grab_focus( lookup_widget( GTK_WIDGET( button ), "entry_magick_file" ) );
00184         if ( strcmp( filename, "" ) )
00185             gtk_entry_set_text( GTK_ENTRY( lookup_widget( GTK_WIDGET( button ), "entry_magick_file" ) ), filename );
00186     }
00187 
00188     void
00189     on_spinbutton_magick_start_value_changed(GtkSpinButton   *spinbutton,
00190                                              gpointer         user_data)
00191     {
00192         GtkSpinButton *endSpin = GTK_SPIN_BUTTON( lookup_widget( GTK_WIDGET( spinbutton ), "spinbutton_magick_end" ) );
00193         gtk_spin_button_set_range( endSpin, gtk_spin_button_get_value( spinbutton ),
00194             common->getPlayList() ->GetNumFrames() - 1 );
00195         gtk_entry_set_text( GTK_ENTRY( lookup_widget( GTK_WIDGET( spinbutton ), "entry_magick_start" ) ),
00196             common->getTime().parseFramesToString( ( int )gtk_spin_button_get_value( spinbutton ),
00197             common->getTimeFormat() ).c_str() );
00198         common->getPageMagick()->OnTimeRangeChanged();
00199     }
00200     
00201     void
00202     on_entry_magick_start_activate         (GtkEntry        *entry,
00203                                             gpointer         user_data)
00204     {
00205         common->getTime().parseValueToString( gtk_entry_get_text( entry ), common->getTimeFormat() );
00206         GtkSpinButton *spinbutton = GTK_SPIN_BUTTON( lookup_widget( GTK_WIDGET( entry ), "spinbutton_magick_start" ) );
00207         gtk_spin_button_set_value( spinbutton, common->getTime().getFrames() );
00208         on_spinbutton_magick_start_value_changed( spinbutton, NULL );
00209     }
00210     
00211     gboolean
00212     on_entry_magick_start_focus_out_event  (GtkWidget       *widget,
00213                                             GdkEventFocus   *event,
00214                                             gpointer         user_data)
00215     {
00216         on_entry_magick_start_activate( GTK_ENTRY( widget ), NULL );
00217         g_nav_ctl.escaped = FALSE;
00218         return FALSE;
00219     }
00220     
00221     void
00222     on_spinbutton_magick_end_value_changed (GtkSpinButton   *spinbutton,
00223                                             gpointer         user_data)
00224     {
00225         GtkSpinButton *startSpin = GTK_SPIN_BUTTON( lookup_widget( GTK_WIDGET( spinbutton ), "spinbutton_magick_start" ) );
00226         gtk_spin_button_set_range( startSpin, 0, gtk_spin_button_get_value( spinbutton ) );
00227         gtk_entry_set_text( GTK_ENTRY( lookup_widget( GTK_WIDGET( spinbutton ), "entry_magick_end" ) ),
00228             common->getTime().parseFramesToString( ( int )gtk_spin_button_get_value( spinbutton ),
00229             common->getTimeFormat() ).c_str() );
00230         common->getPageMagick()->OnTimeRangeChanged();
00231     }
00232 
00233     void
00234     on_entry_magick_end_activate           (GtkEntry        *entry,
00235                                             gpointer         user_data)
00236     {
00237         common->getTime().parseValueToString( gtk_entry_get_text( entry ), common->getTimeFormat() );
00238         GtkSpinButton *spinbutton = GTK_SPIN_BUTTON( lookup_widget( GTK_WIDGET( entry ), "spinbutton_magick_end" ) );
00239         gtk_spin_button_set_value( spinbutton, common->getTime().getFrames() );
00240         on_spinbutton_magick_end_value_changed( spinbutton, NULL );
00241     }
00242     
00243     gboolean
00244     on_entry_magick_end_focus_out_event    (GtkWidget       *widget,
00245                                             GdkEventFocus   *event,
00246                                             gpointer         user_data)
00247     {
00248         on_entry_magick_end_activate( GTK_ENTRY( widget ), NULL );
00249         g_nav_ctl.escaped = FALSE;
00250         return FALSE;
00251     }
00252     
00253     void
00254     on_spinbutton_magick_limit_value_changed (GtkSpinButton   *spinbutton,
00255                                             gpointer         user_data)
00256     {
00257         gtk_entry_set_text( GTK_ENTRY( lookup_widget( GTK_WIDGET( spinbutton ), "entry_magick_limit" ) ),
00258             common->getTime().parseFramesToString( ( int )gtk_spin_button_get_value( spinbutton ),
00259             common->getTimeFormat() ).c_str() );
00260         common->getPageMagick()->OnTimeRangeChanged();
00261     }
00262 
00263     void
00264     on_entry_magick_limit_activate           (GtkEntry        *entry,
00265                                             gpointer         user_data)
00266     {
00267         common->getTime().parseValueToString( gtk_entry_get_text( entry ), common->getTimeFormat() );
00268         GtkSpinButton *spinbutton = GTK_SPIN_BUTTON( lookup_widget( GTK_WIDGET( entry ), "spinbutton_magick_limit" ) );
00269         gtk_spin_button_set_value( spinbutton, common->getTime().getFrames() );
00270         on_spinbutton_magick_limit_value_changed( spinbutton, NULL );
00271     }
00272     
00273     gboolean
00274     on_entry_magick_limit_focus_out_event    (GtkWidget       *widget,
00275                                             GdkEventFocus   *event,
00276                                             gpointer         user_data)
00277     {
00278         on_entry_magick_limit_activate( GTK_ENTRY( widget ), NULL );
00279         g_nav_ctl.escaped = FALSE;
00280         return FALSE;
00281     }
00282     
00283     static gboolean doScrub = FALSE;
00284     gboolean
00285     on_scrubbar_magick_button_press_event ( GtkWidget * widget,
00286                                       GdkEventButton * event,
00287                                       gpointer user_data )
00288     {
00289         doScrub = TRUE;
00290         videoStop();
00291         return FALSE;
00292     }
00293 
00294 
00295     gboolean
00296     on_scrubbar_magick_button_release_event ( GtkWidget * widget,
00297                                         GdkEventButton * event,
00298                                         gpointer user_data )
00299     {
00300         doScrub = FALSE;
00301         return FALSE;
00302     }
00303 
00304     gboolean
00305     on_scrubbar_magick_value_changed_event ( GtkWidget * widget,
00306                                        GdkEventButton * event,
00307                                        gpointer user_data )
00308     {
00309         if ( doScrub )
00310         {
00311             videoStop();
00312             moveToFrame( int( gtk_adjustment_get_value( GTK_ADJUSTMENT( widget ) ) ) );
00313         }
00314         return FALSE;
00315     }
00316 
00317     void
00318     on_time_range_changed(GtkWidget   *widget,
00319                           gpointer       user_data)
00320     {
00321         common->getPageMagick()->OnTimeRangeChanged();
00322     }
00323 
00324     void
00325     on_togglebutton_key_frame_toggled ( GtkToggleButton * togglebutton,
00326                                         gpointer user_data )
00327     {
00328         if ( !buttonMutex )
00329         {
00330             buttonMutex = true;
00331             PageMagick* magick = static_cast< PageMagick* >( user_data );
00332             magick->OnKeyFrameControllerKeyChanged( togglebutton );
00333             buttonMutex = false;
00334         }
00335     }
00336 
00337     static int _getOneSecond( void )
00338     {
00339         Frame & frame = *( GetFramePool() ->GetFrame( ) );
00340         common->getPlayList() ->GetFrame( common->g_currentFrame, frame );
00341         int value = ( frame.IsPAL() ? 25 : 30 );
00342         GetFramePool( ) ->DoneWithFrame( &frame );
00343         return value;
00344     }
00345 }
00346 
00350 bool Plugin::Open( char *file )
00351 {
00352     ptr = dlopen( file, RTLD_NOW );
00353     return ptr != NULL;
00354 }
00355 
00356 void Plugin::Close( )
00357 {
00358     if ( ptr != NULL )
00359         dlclose( ptr );
00360 }
00361 
00362 void *Plugin::Find( char *symbol )
00363 {
00364     return dlsym( ptr, symbol );
00365 }
00366 
00367 const char *Plugin::GetError( )
00368 {
00369     return dlerror();
00370 }
00371 
00375 PluginCollection::PluginCollection( )
00376 {}
00377 
00378 PluginCollection::~PluginCollection( )
00379 {
00380     for ( unsigned int index = 0; index < collection.size(); index ++ )
00381     {
00382         collection[ index ] ->Close();
00383         delete collection[ index ];
00384     }
00385 }
00386 
00387 void PluginCollection::Initialise( char *directory )
00388 {
00389     char * filename;
00390     char *extension;
00391     DIR *dir;
00392     struct dirent *entry;
00393     struct stat statbuf;
00394 
00395     dir = opendir( directory );
00396 
00397     if ( dir )
00398     {
00399         while ( ( entry = readdir( dir ) ) != NULL )
00400         {
00401             filename = g_strdup_printf( "%s/%s", directory, entry->d_name );
00402             extension = strrchr( entry->d_name, '.' );
00403             if ( extension != NULL && !stat( filename, &statbuf ) && S_ISREG( statbuf.st_mode ) )
00404             {
00405                 if ( !strcmp( extension, ".so" ) )
00406                 {
00407                     RegisterPlugin( filename );
00408                 }
00409             }
00410             g_free( filename );
00411         }
00412         closedir( dir );
00413     }
00414 }
00415 
00416 void PluginCollection::RegisterPlugin( char *filename )
00417 {
00418     Plugin * plugin = new Plugin;
00419     if ( plugin->Open( filename ) )
00420     {
00421         cerr << ">>> Registering plugin " << filename << endl;
00422         collection.push_back( plugin );
00423     }
00424     else
00425     {
00426         cerr << ">>> Rejecting plugin " << filename << " : " << plugin->GetError() << endl;
00427         delete plugin;
00428     }
00429 }
00430 
00431 unsigned int PluginCollection::Count()
00432 {
00433     return collection.size();
00434 }
00435 
00436 Plugin *PluginCollection::Get( unsigned int index )
00437 {
00438     return collection[ index ];
00439 }
00440 
00441 void PluginImageCreateRepository::InstallPlugins( Plugin *plugin )
00442 {
00443     GDKImageCreate * ( *func ) ( int ) = ( GDKImageCreate * ( * ) ( int ) ) plugin->Find( "GetImageCreate" );
00444     if ( func != NULL )
00445     {
00446         int index = 0;
00447         GDKImageCreate *entry = func( index ++ );
00448         while ( entry != NULL )
00449         {
00450             if ( entry->IsUsable( ) )
00451                 Register( entry );
00452             entry = func( index ++ );
00453         }
00454     }
00455 }
00456 
00457 void PluginImageFilterRepository::InstallPlugins( Plugin *plugin )
00458 {
00459     GDKImageFilter * ( *func ) ( int ) = ( GDKImageFilter * ( * ) ( int ) ) plugin->Find( "GetImageFilter" );
00460     if ( func != NULL )
00461     {
00462         int index = 0;
00463         GDKImageFilter *entry = func( index ++ );
00464         while ( entry != NULL )
00465         {
00466             if ( entry->IsUsable( ) )
00467                 Register( entry );
00468             entry = func( index ++ );
00469         }
00470     }
00471 }
00472 
00473 void PluginImageTransitionRepository::InstallPlugins( Plugin *plugin )
00474 {
00475     GDKImageTransition * ( *func ) ( int ) = ( GDKImageTransition * ( * ) ( int ) ) plugin->Find( "GetImageTransition" );
00476     if ( func != NULL )
00477     {
00478         int index = 0;
00479         GDKImageTransition *entry = func( index ++ );
00480         while ( entry != NULL )
00481         {
00482             if ( entry->IsUsable( ) )
00483                 Register( entry );
00484             entry = func( index ++ );
00485         }
00486     }
00487 }
00488 
00489 void PluginAudioFilterRepository::InstallPlugins( Plugin *plugin )
00490 {
00491     GDKAudioFilter * ( *func ) ( int ) = ( GDKAudioFilter * ( * ) ( int ) ) plugin->Find( "GetAudioFilter" );
00492     if ( func != NULL )
00493     {
00494         int index = 0;
00495         GDKAudioFilter *entry = func( index ++ );
00496         while ( entry != NULL )
00497         {
00498             if ( entry->IsUsable( ) )
00499                 Register( entry );
00500             entry = func( index ++ );
00501         }
00502     }
00503 }
00504 
00505 void PluginAudioTransitionRepository::InstallPlugins( Plugin *plugin )
00506 {
00507     GDKAudioTransition * ( *func ) ( int ) = ( GDKAudioTransition * ( * ) ( int ) ) plugin->Find( "GetAudioTransition" );
00508     if ( func != NULL )
00509     {
00510         int index = 0;
00511         GDKAudioTransition *entry = func( index ++ );
00512         while ( entry != NULL )
00513         {
00514             if ( entry->IsUsable( ) )
00515                 Register( entry );
00516             entry = func( index ++ );
00517         }
00518     }
00519 }
00520 
00524 class PageMagickFrames;
00525 class PageMagickImage;
00526 class PageMagickAudio;
00527 
00528 class PageMagickInfo
00529 {
00530 private:
00531     PageMagickFrames *frameSource;
00532     PageMagickImage *imageManipulator;
00533     PageMagickAudio *audioManipulator;
00534 public:
00535     KinoCommon *common;
00536     int begin;
00537     int end;
00538     double increment;
00539     bool reverse;
00540     int anteFrame;
00541     int postFrame;
00542     int width;
00543     int height;
00544     int isPAL;
00545     int isWide;
00546     int frequency;
00547     short channels;
00548     int samples_this_frame;
00549     bool preview;
00550     PageMagickInfo( KinoCommon *common );
00551     ~PageMagickInfo();
00552     void SetLowQuality( bool quality );
00553     KinoCommon *GetCommon( )
00554     {
00555         return this->common;
00556     }
00557     void Initialise();
00558     PageMagickFrames *GetFrameSource();
00559     PageMagickImage *GetImageManipulator();
00560     PageMagickAudio *GetAudioManipulator();
00561     void SetBegin( int begin )
00562     {
00563         this->begin = begin > 0 ? begin : 0;
00564     }
00565     void SetEnd( int end )
00566     {
00567         this->end = end > 0 ? end : 0;
00568     }
00569     void SetPostFrame( int postFrame )
00570     {
00571         this->postFrame = postFrame;
00572     }
00573     void SetAnteFrame( int anteFrame )
00574     {
00575         this->anteFrame = anteFrame;
00576     }
00577     void GetAnteFrame( uint8_t *pixels );
00578     void GetPostFrame( uint8_t *pixels );
00579     int GetPostFrame( )
00580     {
00581         return this->postFrame;
00582     }
00583     int GetAnteFrame( )
00584     {
00585         return this->anteFrame;
00586     }
00587 };
00588 
00589 namespace
00590 {
00591 
00593 class time_info
00594 {
00595 public:
00596     time_info( const PageMagickInfo& Info, const int FrameIndex, const double StartPosition = 0.0, const double EndPosition = 1.0 ) :
00597             info( Info ),
00598             frame_index( FrameIndex ),
00599             start_position( StartPosition ),
00600             end_position( EndPosition )
00601     {
00602         // Sanity checks ...
00603         if ( start_position > end_position )
00604             throw _( "Invalid position range" );
00605     }
00606 
00608     unsigned int frame_count() const
00609     {
00610         return info.end - info.begin + 1;
00611     }
00612 
00614     double duration() const
00615     {
00616         return end_position - start_position;
00617     }
00618 
00620     double position() const
00621     {
00622         double position = static_cast<double>( frame_index - info.begin ) / static_cast<double>( frame_count() ) * duration() + start_position;
00623         if ( info.reverse )
00624             position = 1 - position;
00625         return position;
00626     }
00627 
00629     double frame_delta() const
00630     {
00631         return duration() / static_cast<double>( frame_count() );
00632     }
00633 
00635     friend std::ostream& operator<<( std::ostream& Stream, const time_info& RHS )
00636     {
00637         Stream << RHS.frame_count() << " " << RHS.duration() << " " << RHS.frame_index << " " << RHS.position() << " " << RHS.frame_delta();
00638         return Stream;
00639     }
00640 
00641 private:
00642     const PageMagickInfo& info;
00643     const int frame_index;
00644     const double start_position;
00645     const double end_position;
00646 };
00647 
00648 } // namespace
00649 
00653 class PageMagickFrames
00654 {
00655 public:
00656     virtual ~PageMagickFrames() {}
00657     virtual void Initialise( PageMagickInfo * )
00658     { }
00659     virtual void GetFrame( uint8_t *pixels, int16_t **audio, int i )
00660     { }
00661     virtual void GetFrame( uint8_t *pixels, int width, int height, int16_t **audio, int i )
00662     { }
00663     virtual void Close()
00664     { }
00665     virtual bool IsSynth( )
00666     {
00667         return false;
00668     }
00669 };
00670 
00674 class PageMagickImage
00675 {
00676 public:
00677     virtual ~PageMagickImage() {}
00678     virtual void Initialise( PageMagickInfo *info )
00679     { }
00680     ;
00681     virtual void PreGetFrame( int keyPosition = -1 ) // -1 = automatic
00682     { }
00683     ;
00684     virtual void GetFrame( uint8_t *pixels, int i )
00685     { }
00686     ;
00687     virtual void Close()
00688     { }
00689     ;
00690     virtual bool ChangesImage( )
00691     {
00692         return true;
00693     }
00694 };
00695 
00699 class PageMagickAudio
00700 {
00701 public:
00702     virtual ~PageMagickAudio() {}
00703     virtual void Initialise( PageMagickInfo * )
00704     { }
00705     ;
00706     virtual void GetFrame( int16_t **audio, int i, int& samples, int locked_samples )
00707     { }
00708     ;
00709     virtual void Close()
00710     { }
00711     ;
00712 };
00713 
00717 class PageMagickOverwrite : public PageMagickFrames
00718 {
00719 private:
00720     PageMagickInfo *info;
00721 public:
00722     void Initialise( PageMagickInfo * );
00723     void GetFrame( uint8_t *pixels, int16_t **audio, int i );
00724     void GetFrame( uint8_t *pixels, int width, int height, int16_t **audio, int i );
00725     void Close();
00726 };
00727 
00728 void PageMagickOverwrite::Initialise( PageMagickInfo *info )
00729 {
00730     this->info = info;
00731     // Obtain begining and ending of sequence
00732     info->SetBegin( 0 );
00733     info->SetEnd( info->GetCommon() ->getPlayList() ->GetNumFrames() - 1 );
00734     info->increment = 1;
00735     info->reverse = false;
00736 
00737     GtkEntry *startSpin = GTK_ENTRY( lookup_widget( info->GetCommon() ->getPageMagick() ->window, "spinbutton_magick_start" ) );
00738     GtkEntry *endSpin = GTK_ENTRY( lookup_widget( info->GetCommon() ->getPageMagick() ->window, "spinbutton_magick_end" ) );
00739 
00740     if ( info->GetCommon() ->getPlayList() ->GetNumFrames() != 0 )
00741     {
00742         info->SetBegin( atoi( gtk_entry_get_text( startSpin ) ) );
00743         info->SetEnd( atoi( gtk_entry_get_text( endSpin ) ) );
00744         GtkToggleButton *limit = GTK_TOGGLE_BUTTON( lookup_widget( info->GetCommon() ->getPageMagick() ->window, "checkbutton_magick_frame_limit" ) );
00745         if ( gtk_toggle_button_get_active( limit ) )
00746         {
00747             GtkEntry * spin = GTK_ENTRY( lookup_widget( info->GetCommon() ->getPageMagick() ->window, "spinbutton_magick_limit" ) );
00748             GtkMenu *menu = GTK_MENU( gtk_option_menu_get_menu( GTK_OPTION_MENU( lookup_widget( info->GetCommon() ->getPageMagick() ->window, "optionmenu_magick_frame_offset" ) ) ) );
00749             GtkWidget *active_item = gtk_menu_get_active( menu );
00750             if ( g_list_index ( GTK_MENU_SHELL ( menu ) ->children, active_item ) == 1 )
00751             {
00752                 int end = info->begin + atoi( gtk_entry_get_text( spin ) ) - 1;
00753                 if ( end < info->end )
00754                     info->SetEnd( end );
00755             }
00756             else
00757             {
00758                 info->SetBegin( info->end - atoi( gtk_entry_get_text( spin ) ) + 1 );
00759             }
00760         }
00761         info->SetAnteFrame( info->begin - 1 );
00762         info->SetPostFrame( info->end + 1 );
00763     }
00764     else
00765     {
00766         throw _( "No frames available for rewriting." );
00767     }
00768 
00769     // Determine speed
00770     GtkToggleButton *speed = GTK_TOGGLE_BUTTON( lookup_widget( info->GetCommon() ->getPageMagick() ->window, "checkbutton_speed" ) );
00771     if ( gtk_toggle_button_get_active( speed ) )
00772     {
00773         GtkRange * range = GTK_RANGE( lookup_widget( info->GetCommon() ->getPageMagick() ->window, "hscale_speed" ) );
00774         info->increment = range->adjustment->value;
00775     }
00776 
00777     // Determine direction
00778     GtkToggleButton *reverse = GTK_TOGGLE_BUTTON( lookup_widget( info->GetCommon() ->getPageMagick() ->window, "checkbutton_reverse" ) );
00779     info->reverse = gtk_toggle_button_get_active( reverse );
00780 }
00781 
00782 void PageMagickOverwrite::GetFrame( uint8_t *pixels, int16_t **audio, int i )
00783 {
00784     Frame* infoFrame = GetFramePool()->GetFrame();
00785     common->getPlayList() ->GetFrame( i, *( infoFrame ) );
00786 
00787     if ( pixels )
00788     {
00789         infoFrame->decoder->quality = DV_QUALITY_BEST;
00790         infoFrame->ExtractRGB( pixels );
00791     }
00792 
00793     if ( audio )
00794     {
00795         AudioInfo ainfo;
00796         infoFrame->GetAudioInfo( ainfo );
00797         if ( ainfo.channels )
00798         {
00799             AudioResample<int16_ne_t,int16_ne_t> * resampler = AudioResampleFactory<int16_ne_t,int16_ne_t>::createAudioResample(
00800                                             AUDIO_RESAMPLE_SRC_SINC_BEST_QUALITY, info->frequency, false );
00801             resampler->Resample( *infoFrame );
00802             info->samples_this_frame = resampler->size / ( 2 * ainfo.channels );
00803             int16_t *p = resampler->output;
00804             for ( int s = 0; s < info->samples_this_frame; s++ )
00805                 for ( int c = 0; c < ainfo.channels; c++ )
00806                     audio[ c ][ s ] = *p++;
00807             delete resampler;
00808         }
00809     }
00810     GetFramePool()->DoneWithFrame( infoFrame );
00811 }
00812 
00813 void PageMagickOverwrite::GetFrame( uint8_t *pixels, int width, int height, int16_t **audio, int i )
00814 {
00815     Frame* infoFrame = GetFramePool()->GetFrame();
00816     common->getPlayList() ->GetFrame( i, *( infoFrame ) );
00817 
00818     if ( audio )
00819     {
00820         AudioInfo ainfo;
00821         infoFrame->GetAudioInfo( ainfo );
00822         if ( ainfo.channels )
00823         {
00824             AudioResample<int16_ne_t,int16_ne_t> *resampler = AudioResampleFactory<int16_ne_t,int16_ne_t>::createAudioResample(
00825                                     AUDIO_RESAMPLE_SRC_SINC_BEST_QUALITY, info->frequency, false );
00826             resampler->Resample( *infoFrame );
00827             info->samples_this_frame = resampler->size / ( 2 * ainfo.channels );
00828             int16_t *p = resampler->output;
00829             for ( int s = 0; s < info->samples_this_frame; s++ )
00830                 for ( int c = 0; c < ainfo.channels; c++ )
00831                     audio[ c ][ s ] = *p++;
00832             delete resampler;
00833         }
00834     }
00835     if ( pixels )
00836     {
00837         infoFrame->decoder->quality = DV_QUALITY_BEST;
00838         infoFrame->ExtractRGB( pixels );
00839         if ( ( infoFrame->GetWidth() != width || infoFrame->GetHeight() != height ) )
00840         {
00841             GdkPixbuf * i1 = gdk_pixbuf_new_from_data( pixels, GDK_COLORSPACE_RGB, FALSE, 8,
00842                             infoFrame->GetWidth(), infoFrame->GetHeight(), infoFrame->GetWidth() * 3, NULL, NULL );
00843             GdkPixbuf *i2 = gdk_pixbuf_scale_simple( i1, width, height, GDK_INTERP_HYPER );
00844             memcpy( pixels, gdk_pixbuf_get_pixels( i2 ), width * height * 3 );
00845             g_object_unref( i2 );
00846             g_object_unref( i1 );
00847         }
00848     }
00849     GetFramePool()->DoneWithFrame( infoFrame );
00850 }
00851 
00852 void PageMagickOverwrite::Close( )
00853 {
00854     cerr << ">>> Deleting " << info->begin << " << " << info->end << endl;
00855     info->GetCommon() ->getPlayList() ->Delete( info->begin, info->end );
00856 }
00857 
00861 class PageMagickCreate : public PageMagickFrames
00862 {
00863 private:
00864     PageMagickInfo *info;
00865     uint8_t *image;
00866     GDKImageCreate *creator;
00867 
00868 public:
00869     PageMagickCreate();
00870     virtual ~PageMagickCreate();
00871     void Initialise( PageMagickInfo * );
00872     void GetFrame( uint8_t *pixels, int16_t **audio, int i );
00873     void GetFrame( uint8_t *pixels, int width, int height, int16_t **audio, int i );
00874     virtual bool IsSynth( )
00875     {
00876         return true;
00877     }
00878 };
00879 
00880 PageMagickCreate::PageMagickCreate() : image( NULL )
00881 {
00882     image = new uint8_t[ 720 * 576 * 3 ];
00883 }
00884 
00885 PageMagickCreate::~PageMagickCreate()
00886 {
00887     delete[] image;
00888 }
00889 
00890 void PageMagickCreate::Initialise( PageMagickInfo *info )
00891 {
00892     this->info = info;
00893     // Get the start of the scene
00894     info->SetBegin( common->getPlayList()->FindStartOfScene( common->g_currentFrame ) );
00895     info->increment = 1;
00896     info->reverse = false;
00897     info->SetAnteFrame( info->begin - 1 );
00898     info->SetPostFrame( info->begin );
00899 
00900 /* Commented to simplify UI to always create before current scene
00901     GtkToggleButton *frameToggle = GTK_TOGGLE_BUTTON( lookup_widget( common->getPageMagick() ->window, "radiobutton_magick_create_before" ) );
00902     if ( gtk_toggle_button_get_active( frameToggle ) )
00903     {
00904         GtkEntry * spin = GTK_ENTRY( lookup_widget( common->getPageMagick() ->window, "spinbutton_magick_create_before" ) );
00905         info->begin = atoi( gtk_entry_get_text( spin ) );
00906     }
00907 */
00908 
00909     creator = info->GetCommon() ->getPageMagick() ->GetImageCreate();
00910     if ( creator != NULL )
00911     {
00912         creator->CreatePAL( info->isPAL );
00913         creator->InterpretWidgets( GTK_BIN( lookup_widget( common->getPageMagick() ->window, "frame_magick_frames_create" ) ) );
00914     }
00915     else
00916         throw _( "Invalid image creator selected" );
00917 
00918     // Indicate proper duration
00919     info->SetEnd( info->begin + creator->GetNumberOfFrames() - 1 );
00920 }
00921 
00922 void PageMagickCreate::GetFrame( uint8_t *pixels, int16_t **audio, int i )
00923 {
00924     // Sanity checks ...
00925     if ( !creator )
00926         throw _( "Invalid image creator selected" );
00927 
00928     if ( pixels )
00929     {
00930         creator->CreateFrame( image, info->width, info->height, time_info( *info, i ).position(), time_info( *info, i ).frame_delta() );
00931         memcpy( pixels, image, info->width * info->height * 3 );
00932     }
00933 
00934     if ( audio )
00935     {
00936         for ( int i = 0; i < 4; i ++ )
00937             memset( audio[ i ], 0, 2 * DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ) );
00938         GDKAudioImport *import = dynamic_cast <GDKAudioImport *>( creator );
00939         if ( import != NULL )
00940             import->CreateAudio( audio, &info->channels, &info->frequency, &info->samples_this_frame );
00941     }
00942 }
00943 
00944 void PageMagickCreate::GetFrame( uint8_t *pixels, int width, int height, int16_t **audio, int i )
00945 {
00946     // Sanity checks ...
00947     if ( !creator )
00948         throw _( "Invalid image creator selected" );
00949 
00950     if ( pixels )
00951     {
00952         creator->CreateFrame( image, width, height, time_info( *info, i ).position(), time_info( *info, i ).frame_delta() );
00953         memcpy( pixels, image, width * height * 3 );
00954     }
00955 
00956     if ( audio )
00957     {
00958         for ( int i = 0; i < 4; i ++ )
00959             memset( audio[ i ], 0, 2 * DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ) );
00960         GDKAudioImport *import = dynamic_cast <GDKAudioImport *>( creator );
00961         if ( import != NULL )
00962             import->CreateAudio( audio, &info->channels, &info->frequency, &info->samples_this_frame );
00963     }
00964 }
00965 
00969 class PageMagickTransition : public PageMagickImage
00970 {
00971 private:
00972     PageMagickInfo *info;
00973     GDKImageTransition *transition;
00974     uint8_t keyFrame[ 720 * 576 * 3 ];
00975     bool animateKey;
00976     int direction;
00977     double start_position;
00978     double end_position;
00979 public:
00980     void Initialise( PageMagickInfo *info );
00981     void PreGetFrame( int keyPosition );
00982     void GetFrame( uint8_t *pixels, int i );
00983     void Close();
00984 };
00985 
00986 void PageMagickTransition::Initialise( PageMagickInfo *info )
00987 {
00988     this->info = info;
00989     this->animateKey = false;
00990 
00991     transition = info->GetCommon() ->getPageMagick() ->GetImageTransition();
00992     if ( transition != NULL )
00993         transition->InterpretWidgets( GTK_BIN( lookup_widget( common->getPageMagick() ->window, "frame_magick_image_transition" ) ) );
00994     else
00995         throw _( "Invalid image transition selected" );
00996 
00997     GtkToggleButton *toggle = GTK_TOGGLE_BUTTON( lookup_widget( common->getPageMagick() ->window, "radiobutton_magick_transition_colour" ) );
00998 
00999     if ( gtk_toggle_button_get_active( toggle ) )
01000     {
01001         GdkColor color;
01002         GtkColorButton * colorButton = GTK_COLOR_BUTTON( lookup_widget( info->GetCommon() ->getPageMagick() ->window, "colorpicker_magick_transition" ) );
01003         gtk_color_button_get_color( colorButton, &color );
01004         
01005         for ( uint8_t * p = keyFrame; p < ( keyFrame + info->width * info->height * 3 ); )
01006         {
01007             *p ++ = color.red >> 8;
01008             *p ++ = color.green >> 8;
01009             *p ++ = color.blue >> 8;
01010         }
01011     }
01012     else
01013     {
01014         GtkMenu *menu = GTK_MENU( gtk_option_menu_get_menu( GTK_OPTION_MENU( lookup_widget( info->GetCommon() ->getPageMagick() ->window, "optionmenu_magick_transition_frame" ) ) ) );
01015         GtkWidget *active_item = gtk_menu_get_active( menu );
01016         switch ( g_list_index ( GTK_MENU_SHELL ( menu ) ->children, active_item ) )
01017         {
01018         case 1:
01019             info->GetPostFrame( keyFrame );
01020             break;
01021         case 2:
01022             info->GetAnteFrame( keyFrame );
01023             break;
01024         case 0:
01025             animateKey = true;
01026             break;
01027         }
01028     }
01029 
01030     GtkMenu *menu = GTK_MENU( gtk_option_menu_get_menu( GTK_OPTION_MENU( lookup_widget( info->GetCommon() ->getPageMagick() ->window, "optionmenu_direction" ) ) ) );
01031     GtkWidget *active_item = gtk_menu_get_active( menu );
01032     direction = g_list_index ( GTK_MENU_SHELL ( menu ) ->children, active_item );
01033 
01034     GtkRange *range = GTK_RANGE( lookup_widget( info->GetCommon() ->getPageMagick() ->window, "hscale_transition_start" ) );
01035     start_position = range->adjustment->value;
01036     range = GTK_RANGE( lookup_widget( info->GetCommon() ->getPageMagick() ->window, "hscale_transition_end" ) );
01037     end_position = range->adjustment->value;
01038 }
01039 
01040 void PageMagickTransition::PreGetFrame( int keyPosition )
01041 {
01042     if ( animateKey )
01043     {
01044         if ( keyPosition > -1 )
01045             info->postFrame = info->end + keyPosition;
01046         info->GetPostFrame( keyFrame );
01047     }
01048     info->postFrame ++;
01049 }
01050 
01051 void PageMagickTransition::GetFrame( uint8_t *pixels, int i )
01052 {
01053     // Sanity checks ...
01054     if ( !transition )
01055         throw _( "Invalid image transition selected" );
01056 
01057     transition->GetFrame( pixels, keyFrame, info->width, info->height, time_info( *info, i, start_position, end_position ).position(), time_info( *info, i, start_position, end_position ).frame_delta(), direction == 1 );
01058 }
01059 
01060 void PageMagickTransition::Close( )
01061 {
01062     if ( this->animateKey )
01063     {
01064         cerr << ">>> Deleting " << info->begin << " << " << info->begin + ( info->end - info->begin ) / info->increment << endl;
01065         info->GetCommon() ->getPlayList() ->Delete( info->begin, ( int ) ( info->begin + ( info->end - info->begin ) / info->increment ) );
01066     }
01067 }
01068 
01072 class PageMagickFilter : public PageMagickImage
01073 {
01074 private:
01075     PageMagickInfo *info;
01076     GDKImageFilter *filter;
01077 public:
01078     void Initialise( PageMagickInfo *info );
01079     void GetFrame( uint8_t *pixels, int i );
01080     bool ChangesImage( );
01081     void PreGetFrame( int keyPosition )
01082     {
01083         if ( keyPosition > -1 )
01084             info->postFrame = info->end + keyPosition;
01085         else
01086             info->postFrame ++;
01087     }
01088 };
01089 
01090 void PageMagickFilter::Initialise( PageMagickInfo *info )
01091 {
01092     this->info = info;
01093     filter = info->GetCommon() ->getPageMagick() ->GetImageFilter();
01094     if ( filter != NULL )
01095         filter->InterpretWidgets( GTK_BIN( lookup_widget( common->getPageMagick() ->window, "frame_magick_image_filter" ) ) );
01096     else
01097         throw _( "Invalid image filter selected" );
01098 }
01099 
01100 void PageMagickFilter::GetFrame( uint8_t *pixels, int i )
01101 {
01102     // Sanity checks ...
01103     if ( !filter )
01104         throw _( "Invalid image filter selected" );
01105 
01106     filter->FilterFrame( pixels, info->width, info->height, time_info( *info, i ).position(), time_info( *info, i ).frame_delta() );
01107 }
01108 
01109 bool PageMagickFilter::ChangesImage( )
01110 {
01111     NullImageFilter * no_image_encode = dynamic_cast <NullImageFilter *>( filter );
01112     return no_image_encode == NULL;
01113 }
01114 
01118 class PageMagickAudioFilter : public PageMagickAudio
01119 {
01120 private:
01121     PageMagickInfo *info;
01122     GDKAudioFilter *filter;
01123 public:
01124     void Initialise( PageMagickInfo *info );
01125     void GetFrame( int16_t **audio, int i, int& samples, int locked_samples );
01126 };
01127 
01128 void PageMagickAudioFilter::Initialise( PageMagickInfo *info )
01129 {
01130     this->info = info;
01131     filter = info->GetCommon() ->getPageMagick() ->GetAudioFilter();
01132     if ( filter != NULL )
01133         filter->InterpretWidgets( GTK_BIN( lookup_widget( common->getPageMagick() ->window, "frame_magick_audio_filter" ) ) );
01134     else
01135         throw _( "Invalid audio filter selected" );
01136 }
01137 
01138 void PageMagickAudioFilter::GetFrame( int16_t **audio, int i, int& samples, int locked_samples )
01139 {
01140     // Sanity checks ...
01141     if ( !filter )
01142         throw _( "Invalid audio filter selected" );
01143     if ( !filter->IsAFrameConsumer() )
01144         samples = locked_samples;
01145     filter->GetFrame( audio, info->frequency, info->channels, samples, time_info( *info, i ).position(), time_info( *info, i ).frame_delta() );
01146 }
01147 
01151 class PageMagickAudioTransition : public PageMagickAudio
01152 {
01153 private:
01154     PageMagickInfo *info;
01155     int16_t *audio_buffers[ 4 ];
01156     GDKAudioTransition *transition;
01157 AudioResample<int16_ne_t,int16_ne_t> * resampler;
01158 public:
01159     PageMagickAudioTransition();
01160     virtual ~PageMagickAudioTransition();
01161     void Initialise( PageMagickInfo *info );
01162     void GetFrame( int16_t **audio, int i, int& samples, int locked_samples );
01163 };
01164 
01165 PageMagickAudioTransition::PageMagickAudioTransition() : resampler( 0 )
01166 {
01167     for ( int index = 0; index < 4; index ++ )
01168         audio_buffers[ index ] = new int16_t[ 2 * DV_AUDIO_MAX_SAMPLES ];
01169 }
01170 
01171 PageMagickAudioTransition::~PageMagickAudioTransition()
01172 {
01173     for ( int index = 0; index < 4; index ++ )
01174         delete[] audio_buffers[ index ];
01175     delete resampler;
01176 }
01177 
01178 void PageMagickAudioTransition::Initialise( PageMagickInfo *info )
01179 {
01180     this->info = info;
01181 
01182     transition = info->GetCommon() ->getPageMagick() ->GetAudioTransition();
01183     if ( transition != NULL )
01184         transition->InterpretWidgets( GTK_BIN( lookup_widget( common->getPageMagick() ->window, "frame_magick_audio_transition" ) ) );
01185     else
01186         throw _( "Invalid audio transition selected" );
01187 }
01188 
01189 void PageMagickAudioTransition::GetFrame( int16_t **audio, int i, int& samples, int locked_samples )
01190 {
01191     // Sanity checks ...
01192     if ( !transition )
01193         throw _( "Invalid audio filter selected" );
01194 
01195     if ( transition->IsBFrameConsumer() )
01196     {
01197         // Pick up the b-frame audio (ugly.. moved by image transition when appropriate)
01198         // should also be resampled to the a-frames frequency - this is going to go haywire in
01199         // mixed sample rate projects :-/
01200         // In truth, even the aframes should be resampled to original aframes frequency... (fun, fun, fun)
01201         Frame* infoFrame = GetFramePool()->GetFrame();
01202         AudioInfo ainfo;
01203         common->getPlayList()->GetFrame( info->GetPostFrame() - 1, *( infoFrame ) );
01204         infoFrame->GetAudioInfo( ainfo );
01205         if ( ainfo.channels )
01206         {
01207             if ( !resampler )
01208                 resampler = AudioResampleFactory<int16_ne_t,int16_ne_t>::createAudioResample(
01209                     AUDIO_RESAMPLE_SRC_SINC_BEST_QUALITY, info->frequency, true );
01210             resampler->Resample( *infoFrame );
01211             int16_t *p = resampler->output;
01212             samples = resampler->size / info->channels / 2;
01213             for ( int s = 0; s < samples; s++ )
01214                 for ( int c = 0; c < info->channels; c++ )
01215                     audio_buffers[ c ][ s ] = *p++;
01216         }
01217         GetFramePool()->DoneWithFrame( infoFrame );
01218     }
01219     else
01220     {
01221         samples = locked_samples;
01222     }
01223     transition->GetFrame( audio, audio_buffers, info->frequency, info->channels, 
01224         samples, time_info( *info, i ).position(), time_info( *info, i ).frame_delta() );
01225 }
01226 
01230 PageMagickInfo::PageMagickInfo( KinoCommon *common ) : preview( false )
01231 {
01232     this->common = common;
01233     this->frameSource = NULL;
01234     this->imageManipulator = NULL;
01235     this->audioManipulator = NULL;
01236 }
01237 
01238 PageMagickInfo::~PageMagickInfo()
01239 {
01240     delete frameSource;
01241     delete imageManipulator;
01242     delete audioManipulator;
01243 }
01244 
01245 void PageMagickInfo::Initialise()
01246 {
01247     Frame* infoFrame = GetFramePool()->GetFrame();
01248     
01249     // Get a sample frame to obtain recording info
01250     if ( common->getPlayList() ->GetFrame( 0, *infoFrame ) )
01251     {
01252         // Get all video and audio info required
01253         width = infoFrame->GetWidth();
01254         height = infoFrame->GetHeight();
01255         isPAL = infoFrame->IsPAL();
01256         isWide = infoFrame->IsWide();
01257         AudioInfo info;
01258         infoFrame->GetAudioInfo( info );
01259         if ( info.channels && info.frequency )
01260         {
01261             channels = info.channels;
01262             frequency = info.frequency;
01263             samples_this_frame = frequency / ( isPAL ? 25 : 30 );
01264         }
01265         else
01266         {
01267             channels = ( short ) 2;
01268             switch ( Preferences::getInstance().defaultAudio )
01269             {
01270             case AUDIO_32KHZ:
01271                 frequency = 32000;
01272                 break;
01273             case AUDIO_44KHZ:
01274                 frequency = 44100;
01275                 break;
01276             case AUDIO_48KHZ:
01277                 frequency = 48000;
01278                 break;
01279             }
01280             samples_this_frame = frequency / ( isPAL ? 25 : 30 );
01281         }
01282     }
01283     else
01284     {
01285         if ( Preferences::getInstance().defaultNormalisation != NORM_UNSPECIFIED )
01286         {
01287             isPAL = Preferences::getInstance().defaultNormalisation == NORM_PAL;
01288         }
01289         else
01290         {
01291             switch ( modal_confirm( "PAL", "NTSC", _("Please choose a video standard") ) )
01292             {
01293             case GTK_RESPONSE_ACCEPT:
01294                 isPAL = true;
01295                 Preferences::getInstance().defaultNormalisation = NORM_PAL;
01296                 break;
01297             case GTK_RESPONSE_CLOSE:
01298                 isPAL = false;
01299                 Preferences::getInstance().defaultNormalisation = NORM_NTSC;
01300                 break;
01301             default:
01302                 // Do nothing - action cancelled
01303                 GetFramePool()->DoneWithFrame( infoFrame );
01304                 throw _("Aborted");
01305             }
01306         }
01307         width = 720;
01308         height = isPAL ? 576 : 480;
01309         isWide = Preferences::getInstance().defaultAspect == ASPECT_169;
01310         channels = ( short ) 2;
01311         switch ( Preferences::getInstance().defaultAudio )
01312         {
01313         case AUDIO_32KHZ:
01314             frequency = 32000;
01315             break;
01316         case AUDIO_44KHZ:
01317             frequency = 44100;
01318             break;
01319         case AUDIO_48KHZ:
01320             frequency = 48000;
01321             break;
01322         }
01323         samples_this_frame = frequency / ( isPAL ? 25 : 30 );
01324     }
01325     GetFramePool()->DoneWithFrame( infoFrame );
01326 
01327     preview = false;
01328 }
01329 
01330 void PageMagickInfo::SetLowQuality( bool low_quality )
01331 {
01332     if ( preview != low_quality )
01333     {
01334         if ( low_quality )
01335         {
01336             width /= 4;
01337             height /= 4;
01338         }
01339         else
01340         {
01341             width *= 4;
01342