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             height *= 4;
01343         }
01344 
01345         preview = low_quality;
01346     }
01347 }
01348 
01349 PageMagickFrames *PageMagickInfo::GetFrameSource()
01350 {
01351     if ( frameSource == NULL )
01352     {
01353         GtkNotebook * notebook = GTK_NOTEBOOK( lookup_widget( this->common->getPageMagick() ->window, "notebook_magick_frames" ) );
01354         int page = gtk_notebook_get_current_page( notebook );
01355 
01356         switch ( page )
01357         {
01358         case 0:
01359             frameSource = new PageMagickOverwrite();
01360             break;
01361         case 1:
01362             frameSource = new PageMagickCreate();
01363             break;
01364         }
01365     }
01366 
01367     if ( frameSource != NULL )
01368         frameSource->Initialise( this );
01369     else
01370         throw _( "The requested frame source has not been implemented yet..." );
01371 
01372     return frameSource;
01373 }
01374 
01375 PageMagickImage *PageMagickInfo::GetImageManipulator()
01376 {
01377     if ( imageManipulator == NULL )
01378     {
01379         GtkNotebook * notebook = GTK_NOTEBOOK( lookup_widget( this->common->getPageMagick() ->window, "notebook_magick_video" ) );
01380         int page = gtk_notebook_get_current_page( notebook );
01381 
01382         switch ( page )
01383         {
01384         case 0:
01385             imageManipulator = new PageMagickFilter();
01386             break;
01387         case 1:
01388             imageManipulator = new PageMagickTransition();
01389             break;
01390         }
01391     }
01392 
01393     if ( imageManipulator != NULL )
01394         imageManipulator->Initialise( this );
01395     else
01396         throw _( "The requested image manipulator has not been implemented yet..." );
01397 
01398     return imageManipulator;
01399 }
01400 
01401 PageMagickAudio *PageMagickInfo::GetAudioManipulator()
01402 {
01403     if ( audioManipulator == NULL )
01404     {
01405         GtkNotebook * notebook = GTK_NOTEBOOK( lookup_widget( this->common->getPageMagick() ->window, "notebook_magick_audio" ) );
01406         int page = gtk_notebook_get_current_page( notebook );
01407 
01408         switch ( page )
01409         {
01410         case 0:
01411             audioManipulator = new PageMagickAudioFilter();
01412             break;
01413         case 1:
01414             audioManipulator = new PageMagickAudioTransition();
01415             break;
01416         }
01417     }
01418 
01419     if ( audioManipulator != NULL )
01420         audioManipulator->Initialise( this );
01421     else
01422         throw _( "The requested audio manipulator has not been implemented yet..." );
01423 
01424     return audioManipulator;
01425 }
01426 
01427 void PageMagickInfo::GetAnteFrame( uint8_t *pixels )
01428 {
01429     if ( this->anteFrame >= 0 )
01430     {
01431         Frame* infoFrame = GetFramePool()->GetFrame();
01432         common->getPlayList() ->GetFrame( this->anteFrame, *infoFrame );
01433         infoFrame->decoder->quality = DV_QUALITY_BEST;
01434         infoFrame->ExtractRGB( pixels );
01435         if ( preview )
01436         {
01437             GdkPixbuf * i1 = gdk_pixbuf_new_from_data( pixels, GDK_COLORSPACE_RGB, FALSE, 8,
01438                              width * 4, height * 4, width * 4 * 3, NULL, NULL );
01439             GdkPixbuf *i2 = gdk_pixbuf_scale_simple( i1, width, height, GDK_INTERP_NEAREST );
01440             memcpy( pixels, gdk_pixbuf_get_pixels( i2 ), width * height * 3 );
01441             g_object_unref( i2 );
01442             g_object_unref( i1 );
01443         }
01444         GetFramePool()->DoneWithFrame( infoFrame );
01445     }
01446     else
01447     {
01448         memset( pixels, 0, 720 * 576 * 3 );
01449     }
01450 }
01451 
01452 void PageMagickInfo::GetPostFrame( uint8_t *pixels )
01453 {
01454     if ( this->postFrame < common->getPlayList() ->GetNumFrames() )
01455     {
01456         Frame* infoFrame = GetFramePool()->GetFrame();
01457         common->getPlayList() ->GetFrame( this->postFrame, *infoFrame );
01458         infoFrame->decoder->quality = DV_QUALITY_BEST;
01459         infoFrame->ExtractRGB( pixels );
01460         if ( preview )
01461         {
01462             GdkPixbuf * i1 = gdk_pixbuf_new_from_data( pixels, GDK_COLORSPACE_RGB, FALSE, 8,
01463                              width * 4, height * 4, width * 4 * 3, NULL, NULL );
01464             GdkPixbuf *i2 = gdk_pixbuf_scale_simple( i1, width, height, GDK_INTERP_NEAREST );
01465             memcpy( pixels, gdk_pixbuf_get_pixels( i2 ), width * height * 3 );
01466             g_object_unref( i2 );
01467             g_object_unref( i1 );
01468         }
01469         GetFramePool()->DoneWithFrame( infoFrame );
01470     }
01471     else
01472     {
01473         memset( pixels, 0, 720 * 576 * 3 );
01474     }
01475 }
01476 
01477 static void on_drawingarea_refresh_required( GtkWidget *some_widget, GdkEventConfigure *event, gpointer user_data );
01478 
01482 PageMagick::PageMagick( KinoCommon *common ) : 
01483     last_page( 0 ),
01484     rendering( false ),
01485     previewing( false ),
01486     previewPosition( 0 ),
01487     keyFrameControllerClient( 0 ),
01488     isGuiLocked( false ),
01489     isPreviousScene( false ),
01490     isNextScene( false )
01491 {
01492     cerr << "> Creating Magick Page" << endl;
01493 
01494     window = glade_xml_get_widget( magick_glade, "window_magick" );
01495     GtkWidget *bin = lookup_widget( common->getWidget(), "frame_magick" );
01496     gtk_widget_reparent( gtk_bin_get_child( GTK_BIN( window ) ), bin );
01497 
01498     this->common = common;
01499 
01500     progressBar = GTK_PROGRESS_BAR( lookup_widget( common->getWidget(), "progressbar" ) );
01501     cerr << ">> Searching " << KINO_PLUGINDIR << " for plugins" << endl;
01502     plugins.Initialise( KINO_PLUGINDIR );
01503 
01504     for ( unsigned int index = 0; index < plugins.Count(); index ++ )
01505     {
01506         image_creators.InstallPlugins( plugins.Get( index ) );
01507         image_filters.InstallPlugins( plugins.Get( index ) );
01508         image_transitions.InstallPlugins( plugins.Get( index ) );
01509         audio_filters.InstallPlugins( plugins.Get( index ) );
01510         audio_transitions.InstallPlugins( plugins.Get( index ) );
01511     }
01512 
01513     GtkOptionMenu *menu = GTK_OPTION_MENU( lookup_widget( window, "optionmenu_magick_filter" ) );
01514     GtkBin *container = GTK_BIN( lookup_widget( window, "frame_magick_image_filter" ) );
01515     image_filters.Initialise( menu, container );
01516     
01517     menu = GTK_OPTION_MENU( lookup_widget( window, "optionmenu_magick_frames_create" ) );
01518     container = GTK_BIN( lookup_widget( window, "frame_magick_frames_create" ) );
01519     image_creators.Initialise( menu, container );
01520 
01521     menu = GTK_OPTION_MENU( lookup_widget( window, "optionmenu_magick_transition" ) );
01522     container = GTK_BIN( lookup_widget( window, "frame_magick_image_transition" ) );
01523     image_transitions.Initialise( menu, container );
01524 
01525     menu = GTK_OPTION_MENU( lookup_widget( window, "optionmenu_magick_audio_filter" ) );
01526     container = GTK_BIN( lookup_widget( window, "frame_magick_audio_filter" ) );
01527     audio_filters.Initialise( menu, container );
01528 
01529     menu = GTK_OPTION_MENU( lookup_widget( window, "optionmenu_magick_audio_transition" ) );
01530     container = GTK_BIN( lookup_widget( window, "frame_magick_audio_transition" ) );
01531     audio_transitions.Initialise( menu, container );
01532 
01533     GtkWidget *drawing_area = lookup_widget( window, "drawingarea_magick_preview" );
01534     g_signal_connect( G_OBJECT( drawing_area ), "expose_event", G_CALLBACK( on_drawingarea_refresh_required ), this );
01535     gtk_widget_set_double_buffered( drawing_area, FALSE );
01536 
01537     GtkWidget *widget = lookup_widget( window, "notebook_magick_frames" );
01538     g_signal_connect_after( G_OBJECT( widget ), "switch_page", G_CALLBACK( on_notebook_magick_switch_page ), this );
01539     widget = lookup_widget( window, "notebook_magick_video" );
01540     g_signal_connect_after( G_OBJECT( widget ), "switch_page", G_CALLBACK( on_notebook_magick_switch_video_page ), NULL );
01541     widget = lookup_widget( window, "notebook_magick_audio" );
01542     g_signal_connect_after( G_OBJECT( widget ), "switch_page", G_CALLBACK( on_notebook_magick_switch_page ), NULL );
01543 
01544     widget = lookup_widget( window, "checkbutton_magick_frame_limit" );
01545     g_signal_connect( G_OBJECT( widget ), "clicked", G_CALLBACK( on_time_range_changed ), NULL );
01546     widget = lookup_widget( window, "spinbutton_magick_limit" );
01547     gtk_spin_button_set_value( GTK_SPIN_BUTTON( widget ), Preferences::getInstance().defaultNormalisation == NORM_NTSC ? 30 : 25 );
01548     g_signal_connect( G_OBJECT( widget ), "value-changed", G_CALLBACK( on_spinbutton_magick_limit_value_changed ), NULL );
01549     widget = lookup_widget( window, "optionmenu_magick_frame_offset" );
01550     g_signal_connect( G_OBJECT( widget ), "changed", G_CALLBACK( on_time_range_changed ), NULL );
01551 
01552     // Attach the scrub bar
01553     scrubAdjustment = GTK_ADJUSTMENT( gtk_adjustment_new( 0, 0, 0, 1, 10, 0 ) );
01554     scrubBar = gtk_enhanced_scale_new( ( GtkObject** ) & scrubAdjustment, 1 );
01555     gtk_widget_set_name( scrubBar, "scrubmar_magick" );
01556     gtk_widget_ref( scrubBar );
01557     gtk_object_set_data_full( GTK_OBJECT( window ), "scrubbar_magick", scrubBar,
01558                               ( GtkDestroyNotify ) gtk_widget_unref );
01559     GtkWidget *vbox_scrub = lookup_widget( window, "vbox_scrub" );
01560     gtk_widget_show( scrubBar );
01561     gtk_box_pack_start( GTK_BOX( vbox_scrub ), scrubBar, FALSE, TRUE, 0 );
01562     g_signal_connect( G_OBJECT( scrubAdjustment ), "value_changed",
01563                       G_CALLBACK( on_scrubbar_magick_value_changed_event ), NULL );
01564     g_signal_connect( G_OBJECT( scrubBar ), "button_press_event",
01565                       G_CALLBACK( on_scrubbar_magick_button_press_event ), NULL );
01566     g_signal_connect( G_OBJECT( scrubBar ), "button_release_event",
01567                       G_CALLBACK( on_scrubbar_magick_button_release_event ), NULL );
01568     widget = lookup_widget( window, "togglebutton_key_frame" );
01569     g_signal_connect( G_OBJECT( widget ), "toggled", G_CALLBACK( on_togglebutton_key_frame_toggled ), this );
01570     widget = lookup_widget( window, "optionmenu_direction" );
01571     g_signal_connect( G_OBJECT( widget ), "changed", G_CALLBACK( Repaint ), this );
01572     widget = lookup_widget( window, "radiobutton_magick_transition_frame" );
01573     g_signal_connect( G_OBJECT( widget ), "toggled", G_CALLBACK( Repaint ), this );
01574     widget = lookup_widget( window, "optionmenu_magick_transition_frame" );
01575     g_signal_connect( G_OBJECT( widget ), "changed", G_CALLBACK( Repaint ), this );
01576     widget = lookup_widget( window, "radiobutton_magick_transition_colour" );
01577     g_signal_connect( G_OBJECT( widget ), "toggled", G_CALLBACK( Repaint ), this );
01578     widget = lookup_widget( window, "colorpicker_magick_transition" );
01579     g_signal_connect( G_OBJECT( widget ), "color-set", G_CALLBACK( Repaint ), this );
01580     widget = lookup_widget( window, "hscale_transition_start" );
01581     g_signal_connect( G_OBJECT( widget ), "value-changed", G_CALLBACK( Repaint ), this );
01582     widget = lookup_widget( window, "hscale_transition_end" );
01583     g_signal_connect( G_OBJECT( widget ), "value-changed", G_CALLBACK( Repaint ), this );
01584 }
01585 
01589 PageMagick::~PageMagick()
01590 {
01591     GtkBin * bin = GTK_BIN( lookup_widget( common->getWidget(), "frame_magick" ) );
01592     gtk_widget_reparent( ( GTK_BIN( bin ) ) ->child, GTK_WIDGET( window ) );
01593     gtk_widget_destroy( window );
01594 }
01595 
01596 void PageMagick::newFile( )
01597 {
01598     last_fx_file = "";
01599 }
01600 
01604 void PageMagick::start()
01605 {
01606     cerr << ">>> Starting magick" << endl;
01607     strcpy( status, "" );
01608 
01609     if ( common->getPlayList() ->GetNumFrames() > 0 )
01610     {
01611         int begin = common->getPlayList() ->FindStartOfScene( common->g_currentFrame );
01612         int end = common->getPlayList() ->FindEndOfScene( common->g_currentFrame );
01613 
01614         GtkSpinButton *startSpin = GTK_SPIN_BUTTON( lookup_widget( window, "spinbutton_magick_start" ) );
01615         GtkSpinButton *endSpin = GTK_SPIN_BUTTON( lookup_widget( window, "spinbutton_magick_end" ) );
01616         gtk_spin_button_set_range( startSpin, 0, end );
01617         gtk_spin_button_set_value( startSpin, begin );
01618         gtk_spin_button_set_range( endSpin, begin, common->getPlayList() ->GetNumFrames() - 1 );
01619         gtk_spin_button_set_value( endSpin, end );
01620 
01621         previewPosition = common->g_currentFrame - common->getPlayList()->FindStartOfScene( common->g_currentFrame );
01622     }
01623     else
01624     {
01625         GtkNotebook * notebook = GTK_NOTEBOOK( lookup_widget( this->window, "notebook_magick_frames" ) );
01626         gtk_notebook_set_current_page( notebook, 1 );
01627     }
01628 
01629     // Default the file name
01630     GtkEntry *fileEntry = GTK_ENTRY( lookup_widget( window, "entry_magick_file" ) );
01631     string fx_file_name = common->getPlayList( ) ->GetProjectDirectory( ) + "/";
01632 
01633     if ( fx_file_name != last_fx_file )
01634     {
01635         last_fx_file = fx_file_name;
01636         gtk_entry_set_text( fileEntry, fx_file_name.c_str() );
01637     }
01638 
01639     audio_transitions.SelectionChange();
01640     gtk_notebook_set_page( GTK_NOTEBOOK( lookup_widget( common->getWidget(), "notebook_keyhelp" ) ), 3 );
01641     gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( lookup_widget( common->getWidget(), "menuitem_fx" ) ), TRUE );
01642     
01643     timeFormatChanged();
01644     RefreshStatus();
01645 }
01646 
01650 gulong PageMagick::activate()
01651 {
01652     if ( rendering )
01653         return VIDEO_PLAY | VIDEO_STOP;
01654     else
01655         return SCENE_LIST |
01656             VIDEO_START_OF_MOVIE |
01657             VIDEO_BACK |
01658             VIDEO_PLAY |
01659             VIDEO_PAUSE |
01660             VIDEO_STOP |
01661             VIDEO_FORWARD |
01662             VIDEO_END_OF_MOVIE |
01663             ( isPreviousScene ? VIDEO_START_OF_SCENE : 0 ) |
01664             ( isNextScene ? VIDEO_NEXT_SCENE : 0 );
01665 }
01666 
01670 void PageMagick::clean()
01671 {
01672     StopPreview();
01673     strcpy( status, "" );
01674 }
01675 
01679 void PageMagick::PlayAudio( int16_t *buffers[], int samples, int frequency, int channels, bool isPAL )
01680 {
01681     dv_audio.frequency = frequency;
01682     dv_audio.samples_this_frame = samples;
01683     dv_audio.num_channels = channels;
01684 
01685     if ( !audio_device_avail && ( audio_sampling_rate = kino_sound_init( 
01686             &dv_audio, audio_device, Preferences::getInstance().audioDevice ) ) != 0 )
01687         audio_device_avail = true;
01688     if ( audio_device_avail )
01689         kino_sound_play( &dv_audio, audio_device, buffers );
01690 }
01691 
01695 void PageMagick::ShowImage( GtkWidget *area, uint8_t *image, int width, int height, bool isWide )
01696 {
01697     GdkPixbuf * pix = gdk_pixbuf_new_from_data( image, GDK_COLORSPACE_RGB, FALSE, 8, width, height, width * 3, NULL, NULL );
01698     GdkPixbuf *im = gdk_pixbuf_scale_simple( pix, area->allocation.width, area->allocation.height, GDK_INTERP_NEAREST );
01699     GdkGC *gc = gdk_gc_new( area->window );
01700     GtkWidget* aspectFrame = lookup_widget( area, "aspectframe1" );
01701     gtk_aspect_frame_set( GTK_ASPECT_FRAME( aspectFrame ), 0.5, 0, isWide ? (16.0/9.0) : (4.0/3.0), FALSE );
01702     gdk_draw_pixbuf( area->window, gc, im, 0, 0, area->allocation.x, area->allocation.y, -1, -1, GDK_RGB_DITHER_NORMAL, 0, 0 );
01703     g_object_unref( im );
01704     g_object_unref( pix );
01705     g_object_unref( gc );
01706 }
01707 
01711 void PageMagick::showFrameInfo( int frame_number )
01712 {
01713     PageMagickInfo *info = new PageMagickInfo( common );
01714     info->GetFrameSource();
01715     int duration = info->end - info->begin + 1;
01716     delete info;
01717     showFrameInfo( frame_number, duration );
01718 }
01719 
01720 void PageMagick::showFrameInfo( int frame_number, int duration )
01721 {
01722     GtkLabel* positionLabelCurrent = GTK_LABEL( lookup_widget( common->getWidget(), "position_label_current" ) );
01723     GtkLabel* positionLabelTotal = GTK_LABEL( lookup_widget( common->getWidget(), "position_label_total" ) );
01724 
01725     gtk_adjustment_set_value( scrubAdjustment, ( gfloat ) previewPosition );
01726     if ( common->getPlayList()->GetNumFrames() > 0 && duration > 0 )
01727     {
01728         Frame &frame = *( GetFramePool( ) ->GetFrame( ) );
01729         FileHandler *media;
01730 
01731         common->g_currentFrame = common->getPlayList()->FindStartOfScene( common->g_currentFrame ) + previewPosition;
01732         if ( common->getPlayList()->GetMediaObject( frame_number, &media ) &&
01733             common->getPlayList()->GetFrame( frame_number, frame ) )
01734         {
01735             common->getTime().setFramerate( frame.GetFrameRate() );
01736             string tc = "<span size=\"x-large\">" + common->getTime().parseFramesToString( frame_number, common->getTimeFormat() ) + "</span>";
01737             gtk_label_set_markup( positionLabelCurrent, tc.c_str() );
01738             gtk_widget_set_redraw_on_allocate( GTK_WIDGET( positionLabelCurrent ), FALSE );
01739             tc = _("Duration: ") + common->getTime().parseFramesToString( duration, common->getTimeFormat() );
01740             gtk_label_set_markup( positionLabelTotal, tc.c_str() );
01741             common->showFrameMoreInfo( frame, media );
01742         }
01743         GetFramePool( ) ->DoneWithFrame( &frame );
01744     }
01745     else
01746     {
01747         gtk_label_set_text( positionLabelCurrent, "" );
01748         gtk_label_set_text( positionLabelTotal, "" );
01749     }
01750 }
01751 
01752 void PageMagick::movedToFrame( int frame_number )
01753 {
01754     if ( common->hasListChanged == TRUE )
01755     {
01756         common->getPageEditor()->ResetBar();
01757         common->hasListChanged = FALSE;
01758         if ( common->getPlayList() ->GetNumFrames() > 0 )
01759         {
01760             std::vector<int> scenes = common->getPageEditor()->GetScene();
01761             int i = 0;
01762             for ( i = 0; i < int( scenes.size() ) && frame_number >= scenes[ i ]; i++ );
01763             selectScene( i );
01764         }
01765         GtkSpinButton *startSpin = GTK_SPIN_BUTTON( lookup_widget( window, "spinbutton_magick_start" ) );
01766         GtkSpinButton *endSpin = GTK_SPIN_BUTTON( lookup_widget( window, "spinbutton_magick_end" ) );
01767         gtk_spin_button_set_range( startSpin, 0, gtk_spin_button_get_value( endSpin ) );
01768         gtk_spin_button_set_range( endSpin, gtk_spin_button_get_value( startSpin ),
01769             common->getPlayList() ->GetNumFrames() - 1 );
01770     }
01771     else
01772     {
01773         try {
01774             StopPreview();
01775             previewPosition = frame_number;
01776             PreviewFrame();
01777         } catch ( const char * exc )
01778         { }
01779     }
01780 }
01781 
01782 void PageMagick::windowMoved()
01783 {
01784     if ( ! previewing )
01785         movedToFrame( previewPosition );
01786 }
01787 
01788 void PageMagick::PreviewFrame()
01789 {
01790     // Make sure we're not already previewing.
01791     // Do not interrupt rendering
01792     if ( rendering || previewing || repainting )
01793         return;
01794     repainting = true;
01795 
01796     PageMagickInfo *info = new PageMagickInfo( common );
01797     info->Initialise();
01798     PageMagickFrames *frames = info->GetFrameSource();
01799     GtkWidget *area = glade_xml_get_widget( magick_glade, "drawingarea_magick_preview" );
01800     if ( previewPosition > info->end - info->begin )
01801         previewPosition = info->end - info->begin;
01802 
01803     try
01804     {
01805         if ( GDK_IS_DRAWABLE(area->window) && ( info->begin <= info->end ) )
01806         {
01807             GtkWidget *qualityButton = glade_xml_get_widget( magick_glade, "checkbutton_low_quality" );
01808             info->SetLowQuality( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( qualityButton ) ) );
01809             PageMagickImage *image = info->GetImageManipulator();
01810             double i = double( info->begin ) + previewPosition * info->increment;
01811             int frame_number = int( i + 0.5 );
01812             uint8_t *pixels = new uint8_t[ FRAME_MAX_WIDTH * FRAME_MAX_HEIGHT * 4 ];
01813 
01814             showFrameInfo( frame_number, info->end - info->begin + 1 );
01815 
01816             // Apply the filter and show image
01817             if ( info->reverse )
01818                 frame_number = int( double( info->end ) - ( i - info->begin ) + 0.5 );
01819             if ( frame_number > info->end )
01820                 frame_number = info->end;
01821             frames->GetFrame( pixels, info->width, info->height, NULL, frame_number );
01822             image->PreGetFrame( frame_number - info->begin );
01823             image->GetFrame( pixels, frame_number );
01824             ShowImage( area, pixels, info->width, info->height, info->isWide );
01825             delete[] pixels;
01826         }
01827         else
01828         {
01829             showFrameInfo( 0, 0 );
01830         }
01831     }
01832     catch ( const char * exc )
01833     {
01834         modal_message( ( char * ) exc );
01835     }
01836 
01837     repainting = false;
01838     delete info;
01839 }
01840 
01843 static pthread_t audioThread;
01844 static pthread_t videoThread;
01845 static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
01846 static pthread_mutex_t condition_mutex = PTHREAD_MUTEX_INITIALIZER;
01847 static pthread_cond_t condition = PTHREAD_COND_INITIALIZER;
01848 static int frameNumber;
01849 
01850 static int WaitForAction( int lastPosition )
01851 {
01852     if ( frameNumber == lastPosition )
01853     {
01854         pthread_mutex_lock( &condition_mutex );
01855         pthread_cond_wait( &condition, &condition_mutex );
01856         pthread_mutex_unlock( &condition_mutex );
01857     }
01858     return frameNumber;
01859 }
01860 
01861 static void TriggerAction( )
01862 {
01863     pthread_mutex_lock( &condition_mutex );
01864     pthread_cond_signal( &condition );
01865     pthread_mutex_unlock( &condition_mutex );
01866 }
01867 
01868 
01869 static void* audioThreadProxy( void* data )
01870 {
01871     PageMagick* o = static_cast< PageMagick* >( data );
01872     o->AudioThread();
01873     return NULL;
01874 }
01875 
01876 static void* videoThreadProxy( void* data )
01877 {
01878     PageMagick* o = static_cast< PageMagick* >( data );
01879     o->VideoThread();
01880     return NULL;
01881 }
01882 
01883 void PageMagick::StartPreview()
01884 {
01885     previewing = true;
01886     pthread_create( &audioThread, NULL, audioThreadProxy, this );
01887     pthread_create( &videoThread, NULL, videoThreadProxy, this );
01888 }
01889 
01890 void PageMagick::AudioThread()
01891 {
01892     // Avoid reentrancy, interrupt rendering, and empty project
01893     if ( rendering )
01894         return;
01895 
01896     GtkWidget *area = GTK_WIDGET( lookup_widget( window, "drawingarea_magick_preview" ) );
01897 
01898     // Create the temporary space
01899     uint8_t *pixels = new uint8_t[ FRAME_MAX_WIDTH * FRAME_MAX_HEIGHT * 4 ];
01900     int16_t *audio_buffers[ 4 ];
01901     for ( int n = 0; n < 4; n++ )
01902         audio_buffers[ n ] = new int16_t [ 2 * DV_AUDIO_MAX_SAMPLES ];
01903 
01904     // Generate the info
01905     PageMagickInfo *info = new PageMagickInfo( common );
01906 
01907     audio_device = kino_sound_new();
01908     audio_device_avail = false;
01909     audio_sampling_rate = 0;
01910     int audio_number = 0;
01911     Frame* infoFrame = GetFramePool()->GetFrame();
01912 
01913     GtkToggleButton *audioButton = GTK_TOGGLE_BUTTON( lookup_widget( window, "checkbutton_magick_preview_audio" ) );
01914     GtkToggleButton *everyButton = GTK_TOGGLE_BUTTON( lookup_widget( window, "checkbutton_magick_preview_every" ) );
01915     GtkToggleButton *loopButton = GTK_TOGGLE_BUTTON( lookup_widget( window, "checkbutton_magick_preview_loop" ) );
01916     GtkToggleButton *contextButton = GTK_TOGGLE_BUTTON( lookup_widget( window, "checkbutton_magick_preview_context" ) );
01917     GtkToggleButton *qualityButton = GTK_TOGGLE_BUTTON( lookup_widget( window, "checkbutton_low_quality" ) );
01918     GtkEntry *contextSpin = GTK_ENTRY( lookup_widget( window, "spinbutton_magick_preview_context" ) );
01919 
01920     try
01921     {
01922         pthread_mutex_lock( &init_mutex );
01923         info->Initialise();
01924         info->SetLowQuality( gtk_toggle_button_get_active( qualityButton ) );
01925         do
01926         {
01927             PageMagickFrames *frames = info->GetFrameSource();
01928             PageMagickImage *image = info->GetImageManipulator();
01929             PageMagickAudio *sound = info->GetAudioManipulator();
01930             pthread_mutex_unlock( &init_mutex );
01931 
01932             if ( info->begin > info->end )
01933                 throw _( "Invalid frame range specified." );
01934 
01935             if ( previewPosition <= 1 )
01936             for ( frameNumber = info->begin - atoi( gtk_entry_get_text( contextSpin ) );
01937                 frameNumber < info->begin &&
01938                 gtk_toggle_button_get_active( contextButton ) &&
01939                 previewing;
01940                 frameNumber++ )
01941             {
01942                 if ( frameNumber >= 0 )
01943                 {
01944                     TriggerAction();
01945                     common->getPlayList()->GetFrame( frameNumber, *( infoFrame ) );
01946                     if ( !gtk_toggle_button_get_active( audioButton ) &&
01947                             Preferences::getInstance().enableAudio )
01948                     {
01949                         if ( infoFrame->ExtractAudio( audio_buffers ) )
01950                             PlayAudio( audio_buffers, info->samples_this_frame, info->frequency, info->channels, info->isPAL );
01951                     }
01952                     if ( !gtk_toggle_button_get_active( everyButton ) || gtk_toggle_button_get_active( audioButton ) )
01953                     {
01954                         infoFrame->ExtractPreviewRGB( pixels );
01955                         gdk_threads_enter();
01956                         ShowImage( area, pixels, infoFrame->GetWidth(), infoFrame->GetHeight(), infoFrame->IsWide() );
01957                         gdk_flush();
01958                         gdk_threads_leave();
01959                     }
01960                 }
01961             }
01962 
01963             int frame_number = info->begin + previewPosition;
01964             for ( double i = ( double ) info->begin + previewPosition;
01965                 frame_number <= info->end && previewing;
01966                 frame_number = ( int )( ( i += info->increment ) + 0.5 ) )
01967             {
01968                 previewPosition = frame_number - info->begin;
01969                 gdk_threads_enter();
01970                 showFrameInfo( frame_number, info->end - info->begin + 1 );
01971                 gdk_threads_leave();
01972                 if ( info->reverse )
01973                     frame_number = info->end - ( ( int ) i - info->begin );
01974 
01975                 frameNumber = frame_number;
01976                 TriggerAction();
01977                 if ( !gtk_toggle_button_get_active( audioButton ) &&
01978                     Preferences::getInstance().enableAudio )
01979                 {
01980                     int samples = info->samples_this_frame;
01981                     int locked_samples = infoFrame->CalculateNumberSamples( info->frequency, audio_number ++ );
01982                     if ( samples == 0 )
01983                         samples = locked_samples;
01984                     frames->GetFrame( NULL, 0, 0, audio_buffers, frame_number );
01985                     if ( gtk_toggle_button_get_active( everyButton ) )
01986                         image->PreGetFrame( );
01987                     sound->GetFrame( audio_buffers, frame_number, samples, locked_samples );
01988                     PlayAudio( audio_buffers, samples, info->frequency, info->channels, info->isPAL );
01989                 }
01990                 if ( !gtk_toggle_button_get_active( everyButton ) || gtk_toggle_button_get_active( audioButton ) )
01991                 {
01992                     frames->GetFrame( pixels, info->width, info->height, NULL, frame_number );
01993                     image->PreGetFrame( );
01994                     image->GetFrame( pixels, frame_number );
01995                     gdk_threads_enter();
01996                     ShowImage( area, pixels, info->width, info->height, info->isWide );
01997                     gdk_flush();
01998                     gdk_threads_leave();
01999                 }
02000             }
02001 
02002             for ( frameNumber = info->postFrame;
02003                 frameNumber < info->postFrame + atoi( gtk_entry_get_text( contextSpin ) ) &&
02004                 gtk_toggle_button_get_active( contextButton ) &&
02005                 previewing;
02006                 frameNumber++ )
02007             {
02008                 if ( frameNumber < common->getPlayList()->GetNumFrames() )
02009                 {
02010                     TriggerAction();
02011                     common->getPlayList()->GetFrame( frameNumber, *( infoFrame ) );
02012                     if ( !gtk_toggle_button_get_active( audioButton ) &&
02013                             Preferences::getInstance().enableAudio )
02014                     {
02015                         if ( infoFrame->ExtractAudio( audio_buffers ) )
02016                             PlayAudio( audio_buffers, info->samples_this_frame, info->frequency, info->channels, info->isPAL );
02017                     }
02018                     if ( !gtk_toggle_button_get_active( everyButton ) || gtk_toggle_button_get_active( audioButton ) )
02019                     {
02020                         infoFrame->ExtractPreviewRGB( pixels );
02021                         gdk_threads_enter();
02022                         ShowImage( area, pixels, infoFrame->GetWidth(), infoFrame->GetHeight(), infoFrame->IsWide() );
02023                         gdk_flush();
02024                         gdk_threads_leave();
02025                     }
02026                 }
02027             }
02028             if ( previewing )
02029                 previewPosition = 0;
02030             pthread_mutex_lock( &init_mutex );
02031         }
02032         while ( previewing && gtk_toggle_button_get_active( loopButton ) );
02033     }
02034     catch ( const char * exc )
02035     {
02036         modal_message( ( char * ) exc );
02037     }
02038     pthread_mutex_unlock( &init_mutex );
02039 
02040     kino_sound_close( audio_device );
02041     previewing = false;
02042     delete info;
02043     delete[] pixels;
02044     for ( int n = 0; n < 4; n++ )
02045         delete[] audio_buffers[ n ];
02046     GetFramePool()->DoneWithFrame( infoFrame );
02047     TriggerAction();
02048 }
02049 
02050 void PageMagick::VideoThread()
02051 {
02052     GtkWidget *area = GTK_WIDGET( lookup_widget( window, "drawingarea_magick_preview" ) );
02053     uint8_t *pixels = new uint8_t[ FRAME_MAX_WIDTH * FRAME_MAX_HEIGHT * 4 ];
02054     PageMagickInfo *info = new PageMagickInfo( common );
02055     Frame* infoFrame = GetFramePool()->GetFrame();
02056     GtkToggleButton *audioButton = GTK_TOGGLE_BUTTON( lookup_widget( window, "checkbutton_magick_preview_audio" ) );
02057     GtkToggleButton *everyButton = GTK_TOGGLE_BUTTON( lookup_widget( window, "checkbutton_magick_preview_every" ) );
02058     int lastFrame = frameNumber;
02059 
02060     pthread_mutex_lock( &init_mutex );
02061     info->Initialise();
02062     GtkToggleButton *qualityButton = GTK_TOGGLE_BUTTON( lookup_widget( window, "checkbutton_low_quality" ) );
02063     info->SetLowQuality( gtk_toggle_button_get_active( qualityButton ) );
02064     PageMagickFrames *frames = info->GetFrameSource();
02065     PageMagickImage *image = info->GetImageManipulator();
02066     pthread_mutex_unlock( &init_mutex );
02067 
02068     if ( Preferences::getInstance().enableAudio )
02069     {
02070         while ( previewing )
02071         {
02072             int frame_number = WaitForAction( lastFrame );
02073             if ( gtk_toggle_button_get_active( everyButton ) && !gtk_toggle_button_get_active( audioButton ) )
02074             {
02075                 if ( frame_number >= info->begin && frame_number <= info->end )
02076                 {
02077                     // Render the effect
02078                     frames->GetFrame( pixels, info->width, info->height, NULL, frame_number );
02079                     image->PreGetFrame( );
02080                     image->GetFrame( pixels, frame_number );
02081                     gdk_threads_enter();
02082                     ShowImage( area, pixels, info->width, info->height, info->isWide );
02083                     gdk_flush();
02084                     gdk_threads_leave();
02085                 }
02086                 else
02087                 {
02088                     // Render video for the fore- and aft-context
02089                     common->getPlayList()->GetFrame( frame_number, *( infoFrame ) );
02090                     infoFrame->ExtractPreviewRGB( pixels );
02091                     gdk_threads_enter();
02092                     ShowImage( area, pixels, infoFrame->GetWidth(), infoFrame->GetHeight(), infoFrame->IsWide() );
02093                     gdk_flush();
02094                     gdk_threads_leave();
02095                 }
02096             }
02097             lastFrame = frame_number;
02098         }
02099     }
02100     delete info;
02101     delete[] pixels;
02102     GetFramePool()->DoneWithFrame( infoFrame );
02103 }
02104 
02108 void PageMagick::StartRender()
02109 {
02110     // Allow immediate render from preview
02111     if ( previewing )
02112         Stop();
02113 
02114     // Make sure we're not already rendering
02115     if ( rendering )
02116         return ;
02117 
02118     // Set the page condition
02119     rendering = true;
02120     paused = false;
02121 
02122     // Show the current button status
02123     buttonMutex = true;
02124     gtk_widget_set_sensitive( lookup_widget( window, "hpaned_magick" ), false );
02125     gtk_widget_set_sensitive( lookup_widget( window, "togglebutton_magick_start" ), false );
02126     gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( lookup_widget( window, "togglebutton_magick_start" ) ), false );
02127     common->toggleComponents( common->getComponentState(), false );
02128     common->toggleComponents( VIDEO_STOP, false );
02129     common->toggleComponents( VIDEO_PLAY, true );
02130     common->commitComponentState();
02131     common->activateWidgets();
02132     gtk_widget_set_sensitive( scrubBar, FALSE );
02133     buttonMutex = false;
02134 
02135     // Create the temporary space
02136     uint8_t *pixels = new unsigned char[ FRAME_MAX_WIDTH * FRAME_MAX_HEIGHT * 4 ];
02137     int16_t *audio_buffers[ 4 ];
02138     for ( int n = 0; n < 4; n++ )
02139         audio_buffers[ n ] = new int16_t [ 2 * DV_AUDIO_MAX_SAMPLES ];
02140     unsigned char *dv_pixels[ 3 ];
02141     dv_pixels[ 0 ] = pixels;
02142 
02143     // Build the info
02144     PageMagickInfo *info = new PageMagickInfo( common );
02145 
02146     // Output file
02147     FILE *output = NULL;
02148 
02149     Frame* infoFrame = GetFramePool()->GetFrame();
02150     
02151     // All exceptions thrown should be safely picked up in the try/catch
02152     try
02153     {
02154         // Get the current date and time to set in dv
02155         time_t datetime = time( NULL );
02156         int frameNum = 0;
02157 
02158         // Initialise the info
02159         info->Initialise();
02160 
02161         int audio_number = 0;
02162 
02163         // Obtain the file name
02164         GtkEntry *fileEntry = GTK_ENTRY( lookup_widget( window, "entry_magick_file" ) );
02165         const char *filename = gtk_entry_get_text( fileEntry );
02166         int counter = 0;
02167         string thisfile;
02168         struct stat stats;
02169 
02170         if ( !strcmp( filename, "" ) )
02171             throw _( "No file name specified" );
02172 
02173         string directory = "";
02174 
02175         // Relative/absolute file checks
02176         if ( filename[ 0 ] != '/' )
02177             directory = common->getPlayList() ->GetProjectDirectory( ) + "/";
02178 
02179         // Generate the full file name
02180         do
02181         {
02182             char name[ 132 ];
02183             sprintf( name, "%s%03d.kinofx.dv", filename, ++ counter );
02184             thisfile = name;
02185             cerr << ">>> Trying " << thisfile << endl;
02186         }
02187         while ( stat( thisfile.c_str(), &stats ) == 0 );
02188 
02189         infoFrame->CreateEncoder( ( info->height == 576 ), info->isWide );
02190 
02191         // Get the source and manipulators
02192         PageMagickFrames *frames = info->GetFrameSource();
02193         PageMagickImage *image = info->GetImageManipulator();
02194         PageMagickAudio *sound = info->GetAudioManipulator();
02195 
02196         // Check that we're rendering a valid set of frames
02197         if ( info->begin > info->end )
02198             throw _( "Invalid frame range specified." );
02199 
02200         // Open the file
02201         output = fopen( thisfile.c_str(), "w" );
02202         if ( output == NULL )
02203             throw _( "Unable to open output file" );
02204 
02205         bool change_image = image->ChangesImage( ) || frames->IsSynth( );
02206 
02207         // Initialise status and progress
02208         startTime = pauseTime - 0.0;
02209 
02210         // For each frame
02211         int frame_number = info->begin;
02212         for ( double i = ( double ) info->begin; 
02213             frame_number <= info->end && rendering; 
02214             frame_number = ( int )( ( i += info->increment ) + 0.5 ) )
02215         {
02216             if ( info->reverse )
02217                 frame_number = info->end - ( ( int ) i - info->begin );
02218 
02219             frames->GetFrame( pixels, audio_buffers, frame_number );
02220             image->PreGetFrame( );
02221 
02222             int samples = info->samples_this_frame; // set in frames->GetFrame() above
02223             int locked_samples = infoFrame->CalculateNumberSamples( info->frequency, audio_number ++ );
02224             if ( samples == 0 )
02225                 samples = locked_samples;
02226 
02227             sound->GetFrame( audio_buffers, frame_number, samples, locked_samples );
02228 
02229             if ( ! change_image )
02230             {
02231                 common->getPlayList()->GetFrame( frame_number, *( infoFrame ) );
02232             }
02233             else
02234             {
02235                 image->GetFrame( pixels, frame_number );
02236                 infoFrame->EncodeRGB( pixels );
02237             }
02238             AudioInfo audioInfo;
02239             audioInfo.channels = info->channels;
02240             audioInfo.frequency = info->frequency;
02241             audioInfo.samples = samples;
02242             infoFrame->EncodeAudio( audioInfo, audio_buffers );
02243             infoFrame->SetRecordingDate( &datetime, frameNum );
02244             infoFrame->SetTimeCode( frameNum++ );
02245 
02246             if ( fwrite( infoFrame->data, ( info->isPAL ? 144000 : 120000 ), 1, output ) != 1 )
02247                 throw _( "Unable to write video - disk full?" );
02248 
02249             if ( info->end != info->begin )
02250                 UpdateStatus( int(i), info->begin, info->end, int( info->increment + 0.5) );
02251         }
02252         struct timeval tv;
02253         if ( 0 == gettimeofday( &tv, NULL ) )
02254         {
02255             double now = tv.tv_sec + tv.tv_usec / 1000000.0;
02256             char buf[ 17 ];
02257             string message;
02258 
02259             if ( rendering )
02260                 message = _( "Rendering finished - time: " );
02261             else
02262                 message = _( "Rendering stopped - time: " );
02263             message += Export::formatSecs( buf, 16, now - startTime );
02264             common->setStatusBar( message.c_str() );
02265         }
02266         UpdateProgress( ( gfloat ) 1 );
02267 
02268         frames->Close();
02269         image->Close();
02270         sound->Close();
02271 
02272         fclose( output );
02273         output = NULL;
02274 
02275         PlayList temp;
02276         temp.LoadMediaObject( ( char * ) thisfile.c_str() );
02277         bool isPlayListEmpty = ( common->getPlayList()->GetNumFrames() == 0 );
02278         common->getPlayList() ->InsertPlayList( temp, info->begin );
02279         common->getPageEditor() ->snapshot();
02280         common->getPageEditor() ->ResetBar();
02281         if ( isPlayListEmpty )
02282             common->setCurrentScene( 0 );
02283     }
02284     catch ( const char * exc )
02285     {
02286         common->setStatusBar( _( "Rendering failed" ) );
02287         modal_message( ( char * ) exc );
02288     }
02289 
02290     rendering = false;
02291 
02292     buttonMutex = true;
02293     gtk_widget_set_sensitive( lookup_widget( window, "hpaned_magick" ), true );
02294     gtk_widget_set_sensitive( lookup_widget( window, "togglebutton_magick_start" ), true );
02295     common->toggleComponents( VIDEO_STOP, true );
02296     common->commitComponentState();
02297     common->activateWidgets();
02298     gtk_widget_set_sensitive( scrubBar, TRUE );
02299     buttonMutex = false;
02300 
02301     if ( output )
02302         fclose( output );
02303 
02304     delete info;
02305     delete[] pixels;
02306     for ( int n = 0; n < 4; n++ )
02307         delete[] audio_buffers[ n ];
02308     GetFramePool()->DoneWithFrame( infoFrame );
02309 }
02310 
02314 void PageMagick::Stop()
02315 {
02316     StopPreview();
02317     rendering = false;
02318 }
02319 
02323 void PageMagick::StopPreview()
02324 {
02325     if ( previewing )
02326     {
02327         previewing = false;
02328         gdk_threads_leave();
02329         pthread_join( audioThread, NULL );
02330         TriggerAction();
02331         pthread_join( videoThread, NULL );
02332         gdk_threads_enter();
02333     }
02334 }
02335 
02340 void PageMagick::UpdateProgress( gfloat val )
02341 {
02342     struct timeval tv;
02343 
02344     long long now;
02345     static long long lastUpdateTime = 0;
02346 
02347     gettimeofday( &tv, 0 );
02348     now = 1000000 * ( long long ) tv.tv_sec + ( long long ) tv.tv_usec;
02349 
02350     /* update every 0.3 second */
02351 
02352     if ( val < 0.0 )
02353         val = 0;
02354     if ( val > 1.0 )
02355         val = 1.0;
02356 
02357     if ( now > lastUpdateTime + 300000 || val == 1.0 )
02358     {
02359         gtk_progress_bar_update( progressBar, val );
02360         lastUpdateTime = now;
02361     }
02362 
02363     while ( gtk_events_pending() )
02364         gtk_main_iteration();
02365 }
02366 
02367 
02368 void PageMagick::UpdateStatus( int currentFrame, int begin, int end, int every )
02369 {
02370     char buf[ 512 ];
02371     struct timeval tv;
02372     if ( 0 != gettimeofday( &tv, NULL ) )
02373     {
02374         cerr << ">>> Error calling gettimeofday?" << endl;
02375     }
02376     double now = tv.tv_sec + tv.tv_usec / 1000000.0;
02377     gfloat ratio = ( gfloat ) ( currentFrame - begin ) / ( gfloat ) ( end + 1 - begin ) ;
02378     /* Figure out how much time we have spend */
02379     if ( 0 == startTime )
02380     {
02381         /* First time */
02382         startTime = now;
02383         nextUpdateTime = now - 1;
02384         snprintf( buf, 512, _( "Rendering frame %i." ), currentFrame );
02385     }
02386     else
02387     {
02388         /* Not first time
02389            We do not care to use difftime on this... */
02390         double time_so_far = now - startTime - pauseTime;
02391         double total_est = time_so_far / ratio;
02392         /* Write the time values into buffers */
02393         char buf1[ 16 ];
02394         char buf2[ 16 ];
02395         char buf3[ 16 ];
02396         snprintf( buf, 512, _( "Rendering frame %i. Time  used: %s,  estimated: %s,  left: %s" ),
02397                   currentFrame + 1,
02398                   Export::formatSecs( buf1, 16, time_so_far ),
02399                   Export::formatSecs( buf2, 16, total_est ),
02400                   Export::formatSecs( buf3, 16, total_est - time_so_far ) );
02401     }
02402 
02403     /* Update status message
02404        TODO: Do filesystem checks first....
02405     */
02406     if ( now > nextUpdateTime )
02407     {
02408         common->setStatusBar( buf );
02409         nextUpdateTime = now + 0.25;
02410     }
02411 
02412     /* Update progressbar - assuming currentFrame have yet to be exported
02413        Updating the progressbar will handle any pending events. */
02414     UpdateProgress( ratio );
02415 
02416     /* Check pause - make sure we ignore time paused in export. */
02417     if ( paused )
02418     {
02419         struct timespec ts;
02420         ts.tv_sec = 0;
02421         ts.tv_nsec = 1000 * 1000 * 20; /* 20 ms + sched overhead */
02422         while ( paused )
02423         {
02424             while ( gtk_events_pending() )
02425                 gtk_main_iteration();
02426             /* Lets try not to hog the CPU */
02427             nanosleep( &ts, NULL );
02428         }
02429         if ( 0 != gettimeofday( &tv, NULL ) )
02430             cerr << ">>> Error calling gettimeofday?" << endl;
02431         double foo = tv.tv_sec + tv.tv_usec / 1000000.0;
02432         pauseTime += ( foo - now );
02433     }
02434 }
02435 
02440 void PageMagick::selectScene( int i )
02441 {
02442     int begin = 0;
02443     int end = 0;
02444     vector <int> scene = common->getPageEditor() ->GetScene();
02445 
02446     begin = i == 0 ? 0 : scene[ i - 1 ];
02447     end = scene[ i ] - 1;
02448     common->g_currentFrame = begin;
02449 
02450     if ( GTK_WIDGET_SENSITIVE( lookup_widget( window, "hpaned_magick" ) ) )
02451     {
02452         GtkSpinButton *startSpin = GTK_SPIN_BUTTON( lookup_widget( window, "spinbutton_magick_start" ) );
02453         GtkSpinButton *endSpin = GTK_SPIN_BUTTON( lookup_widget( window, "spinbutton_magick_end" ) );
02454         gtk_spin_button_set_value( startSpin, begin );
02455         gtk_spin_button_set_value( endSpin, end );
02456 
02457         if ( previewing )
02458         {
02459             StopPreview();
02460             StartPreview();
02461         }
02462         else
02463         {
02464             movedToFrame( 0 );
02465         }
02466     }
02467 
02468     Frame &frame = *( GetFramePool( ) ->GetFrame( ) );
02469     FileHandler *media;
02470     common->getPlayList() ->GetMediaObject( begin, &media );
02471     common->getPlayList() ->GetFrame( begin, frame );
02472     common->showFrameMoreInfo( frame, media );
02473     GetFramePool( ) ->DoneWithFrame( &frame );
02474 
02475     common->setCurrentScene( begin );
02476     RefreshStatus( true );
02477 }
02478 
02479 void PageMagick::videoStartOfMovie()
02480 {
02481     common->toggleComponents( common->getComponentState(), false );
02482     common->toggleComponents( VIDEO_START_OF_MOVIE, false );
02483     common->toggleComponents( VIDEO_STOP, true );
02484     try
02485     {
02486         StopPreview();
02487         previewPosition = 0;
02488         PreviewFrame();
02489     }
02490     catch ( const char * exc )
02491     {
02492     }
02493 }
02494 
02495 void PageMagick::videoBack( int step )
02496 {
02497     common->toggleComponents( common->getComponentState(), false );
02498     common->toggleComponents( VIDEO_BACK, false );
02499     common->toggleComponents( VIDEO_STOP, true );
02500     try
02501     {
02502         PageMagickInfo *info = new PageMagickInfo( common );
02503         info->GetFrameSource();
02504         StopPreview();
02505         previewPosition += step;
02506         if ( previewPosition < 0 )
02507             previewPosition = 0;
02508         delete info;
02509         PreviewFrame();
02510     }
02511     catch ( const char * exc )
02512     {
02513     }
02514 }
02515 
02516 
02517 void PageMagick::videoPlay()
02518 {
02519     if ( previewing )
02520     {
02521         videoStop();
02522     }
02523     else if ( rendering )
02524     {
02525         common->toggleComponents( common->getComponentState(), false );
02526         common->toggleComponents( VIDEO_PLAY, paused );
02527         common->commitComponentState();
02528         paused = !paused;
02529     }
02530     else
02531     {
02532         // Start playing
02533         common->toggleComponents( common->getComponentState(), false );
02534         common->toggleComponents( VIDEO_PLAY, true );
02535         common->commitComponentState();
02536         StartPreview();
02537     }
02538 }
02539 
02540 void PageMagick::videoForward( int step )
02541 {
02542     common->toggleComponents( common->getComponentState(), false );
02543     common->toggleComponents( VIDEO_FORWARD, false );
02544     common->toggleComponents( VIDEO_STOP, true );
02545     try
02546     {
02547         PageMagickInfo *info = new PageMagickInfo( common );
02548         info->GetFrameSource();
02549         StopPreview();
02550         previewPosition += step;
02551         if ( previewPosition > info->end - info->begin )
02552             previewPosition = info->end - info->begin;
02553         delete info;
02554         PreviewFrame();
02555     }
02556     catch ( const char * exc )
02557     {
02558     }
02559 }
02560 
02561 void PageMagick::videoEndOfMovie()
02562 {
02563     common->toggleComponents( common->getComponentState(), false );
02564     common->toggleComponents( VIDEO_END_OF_MOVIE, false );
02565     common->toggleComponents( VIDEO_STOP, true );
02566     try
02567     {
02568         PageMagickInfo *info = new PageMagickInfo( common );
02569         info->GetFrameSource();
02570         StopPreview();
02571         previewPosition = info->end - info->begin;
02572         delete info;
02573         PreviewFrame();
02574     }
02575     catch ( const char * exc )
02576     {
02577     }
02578 }
02579 
02580 void PageMagick::videoPause()
02581 {
02582     videoStop();
02583 }
02584 
02585 void PageMagick::videoStop()
02586 {
02587     common->toggleComponents( common->getComponentState(), false );
02588     common->toggleComponents( VIDEO_STOP, true );
02589     Stop();
02590 }
02591 
02595 void PageMagick::RefreshStatus( bool with_fx_notify )
02596 {
02597     GtkNotebook *notebookFrame = GTK_NOTEBOOK( lookup_widget( this->window, "notebook_magick_frames" ) );
02598     GtkNotebook *notebookImage = GTK_NOTEBOOK( lookup_widget( this->window, "notebook_magick_video" ) );
02599     GtkNotebook *notebookAudio = GTK_NOTEBOOK( lookup_widget( this->window, "notebook_magick_audio" ) );
02600 
02601     int page = gtk_notebook_get_current_page( notebookFrame );
02602     if ( page == 1 )
02603     {
02604         SelectionNotification *notify = dynamic_cast <SelectionNotification *>( GetImageCreate( ) );
02605         if ( with_fx_notify && notify != NULL )
02606             notify->OnSelectionChange( );
02607     }
02608 
02609     page = gtk_notebook_get_current_page( notebookImage );
02610 
02611     if ( page == 0 && GetImageFilter() != NULL )
02612     {
02613         SelectionNotification *notify = dynamic_cast <SelectionNotification *>( GetImageFilter( ) );
02614         if ( with_fx_notify && notify != NULL )
02615             notify->OnSelectionChange( );
02616     }
02617     else if ( page == 1 && GetImageTransition() != NULL )
02618     {
02619         SelectionNotification *notify = dynamic_cast <SelectionNotification *>( GetImageTransition( ) );
02620         if ( with_fx_notify && notify != NULL )
02621             notify->OnSelectionChange( );
02622     }
02623 
02624     page = gtk_notebook_get_current_page( notebookAudio );
02625     if ( page == 0 )
02626     {
02627         SelectionNotification *notify = dynamic_cast <SelectionNotification *>( GetAudioFilter( ) );
02628         if ( with_fx_notify && notify != NULL )
02629             notify->OnSelectionChange( );
02630     }
02631     else if ( page == 1 )
02632     {
02633         SelectionNotification *notify = dynamic_cast <SelectionNotification *>( GetAudioTransition( ) );
02634         if ( with_fx_notify && notify != NULL )
02635             notify->OnSelectionChange( );
02636     }
02637 
02638     ShowCurrentStatus( GetCurrentPosition(), LOCKED_KEY, false, false );
02639 
02640     // This is a special case to cause preview to restart when fx options change
02641     if ( !with_fx_notify )
02642     {
02643         if ( previewing )
02644         {
02645             StopPreview();
02646             StartPreview();
02647         }
02648         else
02649         {
02650             PreviewFrame();
02651         }
02652     }
02653 }
02654 
02655 void PageMagick::timeFormatChanged()
02656 {
02657     on_spinbutton_magick_start_value_changed( GTK_SPIN_BUTTON( lookup_widget( this->window, "spinbutton_magick_start" ) ), NULL );
02658     on_spinbutton_magick_end_value_changed( GTK_SPIN_BUTTON( lookup_widget( this->window, "spinbutton_magick_end" ) ), NULL );
02659     on_spinbutton_magick_limit_value_changed( GTK_SPIN_BUTTON( lookup_widget( this->window, "spinbutton_magick_limit" ) ), NULL );
02660 }
02661 
02662 
02666 GDKImageFilter *PageMagick::GetImageFilter( ) const
02667 {
02668     return image_filters.Get( );
02669 }
02670 
02674 GDKImageTransition *PageMagick::GetImageTransition( ) const
02675 {
02676     return image_transitions.Get( );
02677 }
02678 
02682 GDKAudioFilter *PageMagick::GetAudioFilter( ) const
02683 {
02684     return audio_filters.Get( );
02685 }
02686 
02690 GDKAudioTransition *PageMagick::GetAudioTransition( ) const
02691 {
02692     return audio_transitions.Get( );
02693 }
02694 
02698 GDKImageCreate *PageMagick::GetImageCreate( ) const
02699 {
02700     return image_creators.Get( );
02701 }
02702 
02703 gboolean PageMagick::processKeyboard( GdkEventKey *event )
02704 {
02705     gboolean ret = FALSE;
02706 
02707     // Translate special keys to equivalent command
02708     switch ( event->keyval )
02709     {
02710     case GDK_Escape:
02711         if ( rendering || previewing )
02712         {
02713             common->keyboardFeedback( "", _( "Stop" ) );
02714             common->videoStop();
02715         }
02716         else
02717         {
02718             common->changePageRequest( PAGE_EDITOR );
02719         }
02720     default:
02721         break;
02722     }
02723 
02724     return ret;
02725 }
02726 
02727 gboolean PageMagick::processCommand( char *cmd )
02728 {
02729     /* play, pause */
02730 
02731     if ( strcmp( cmd, " " ) == 0 )
02732     {
02733         if ( !previewing )
02734         {
02735             common->keyboardFeedback( cmd, _( "Play" ) );
02736             common->videoPlay( );
02737         }
02738         else
02739         {
02740             common->keyboardFeedback( cmd, _( "Pause" ) );
02741             common->videoPause( );
02742         }
02743     }
02744 
02745     /* advance one frame */
02746 
02747     else if ( strcmp( cmd, "l" ) == 0 )
02748     {
02749         common->keyboardFeedback( cmd, _( "Move forward" ) );
02750         common->moveByFrames( 1 );
02751     }
02752 
02753     /* backspace one frame */
02754 
02755     else if ( strcmp( cmd, "h" ) == 0 )
02756     {
02757         common->keyboardFeedback( cmd, _( "Move backward" ) );
02758         common->moveByFrames( -1 );
02759     }
02760 
02761     /* advance one second */
02762 
02763     else if ( strcmp( cmd, "w" ) == 0 || strcmp( cmd, "W" ) == 0 ||
02764               strcmp( cmd, "e" ) == 0 || strcmp( cmd, "E" ) == 0 )
02765     {
02766         common->keyboardFeedback( cmd, _( "Move forward second" ) );
02767         common->moveByFrames( _getOneSecond() );
02768     }
02769 
02770     /* backspace one second */
02771 
02772     else if ( ( strcmp( cmd, "b" ) == 0 ) || ( strcmp( cmd, "B" ) == 0 ) )
02773     {
02774         common->keyboardFeedback( cmd, _( "Move backwards one second" ) );
02775         common->moveByFrames( -1 * _getOneSecond() );
02776     }
02777 
02778     /* start of scene */
02779 
02780     else if ( ( strcmp( cmd, "0" ) == 0 ) || ( strcmp( cmd, "^" ) == 0 ) )
02781     {
02782         common->videoStartOfScene( );
02783         common->keyboardFeedback( cmd, _( "Move to start of scene" ) );
02784     }
02785 
02786     /* end of scene */
02787 
02788     else if ( strcmp( cmd, "$" ) == 0 )
02789     {
02790         common->videoEndOfScene( );
02791         common->keyboardFeedback( cmd, _( "Move to end of scene" ) );
02792     }
02793 
02794     /* start of next scene */
02795 
02796     else if ( ( strcmp( cmd, "j" ) == 0 ) || strcmp( cmd, "+" ) == 0 )
02797     {
02798         common->videoNextScene( );
02799         common->keyboardFeedback( cmd, _( "Move to start of next scene" ) );
02800     }
02801 
02802     /* start of previous scene */
02803 
02804     else if ( ( strcmp( cmd, "k" ) == 0 ) || ( strcmp( cmd, "-" ) == 0 ) )
02805     {
02806         common->videoPreviousScene( );
02807         common->keyboardFeedback( cmd, _( "Move to start of previous scene" ) );
02808     }
02809 
02810     /* first frame */
02811 
02812     else if ( strcmp( cmd, "gg" ) == 0 )
02813     {
02814         common->videoStartOfMovie( );
02815         common->keyboardFeedback( cmd, _( "Move to first frame" ) );
02816     }
02817 
02818     /* last frame */
02819 
02820     else if ( strcmp( cmd, "G" ) == 0 )
02821     {
02822         common->videoEndOfMovie( );
02823         common->keyboardFeedback( cmd, _( "Move to last frame" ) );
02824     }
02825 
02826     /* write PlayList */
02827 
02828     else if ( strcmp( cmd, ":w" ) == 0 )
02829     {
02830         common->keyboardFeedback( cmd, _( "Write playlist" ) );
02831         common->savePlayList( );
02832     }
02833 
02834     else if ( strcmp( cmd, "Enter" ) == 0 )
02835     {
02836         common->keyboardFeedback( cmd, _( "Start Render" ) );
02837         GdkEvent ev;
02838         ev.key.type = GDK_KEY_PRESS;
02839         ev.key.window = common->getWidget()->window;
02840         ev.key.send_event = TRUE;
02841         ev.key.state = 0;
02842         ev.key.length = 0;
02843         ev.key.string = "";
02844         ev.key.keyval = GDK_Return;
02845         ev.key.group = 0;
02846         gdk_event_put( &ev );
02847     }
02848 
02849     else if ( strcmp( cmd, "Esc" ) == 0 )
02850     {
02851         common->keyboardFeedback( cmd, _( "Stop" ) );
02852         common->videoStop();
02853     }
02854 
02855     else if ( strcmp( cmd, "F2" ) == 0 )
02856     {
02857         common->keyboardFeedback( cmd, _( "Edit" ) );
02858         common->changePageRequest( PAGE_EDITOR );
02859     }
02860 
02861     else if ( strcmp( cmd, "A" ) == 0 )
02862     {
02863         common->keyboardFeedback( cmd, _( "Capture, append to movie" ) );
02864         common->changePageRequest( PAGE_EDITOR );
02865     }
02866 
02867     else if ( strcmp( cmd, "v" ) == 0 )
02868     {
02869         common->keyboardFeedback( cmd, _( "Timeline" ) );
02870         common->changePageRequest( PAGE_TIMELINE );
02871     }
02872 
02873     else if ( strcmp( cmd, "t" ) == 0 )
02874     {
02875         common->keyboardFeedback( cmd, _( "Trim" ) );
02876         common->changePageRequest( PAGE_TRIM );
02877     }
02878 
02879     else if ( strcmp( cmd, ":W" ) == 0 )
02880     {
02881         common->keyboardFeedback( cmd, _( "Export" ) );
02882         common->changePageRequest( PAGE_TIMELINE );
02883     }
02884 
02885     /* quit */
02886 
02887     else if ( strcmp( cmd, ":q" ) == 0 )
02888     {
02889         common->keyboardFeedback( cmd, _( "quit" ) );
02890         kinoDeactivate();
02891     }
02892 
02893     return FALSE;
02894 }
02895 
02896 void PageMagick::OnTimeRangeChanged()
02897 {
02898     try
02899     {
02900         PageMagickInfo *info = new PageMagickInfo( common );
02901 
02902         info->GetFrameSource();
02903         scrubAdjustment->upper = info->end - info->begin + 1;
02904         if ( gtk_adjustment_get_value( scrubAdjustment ) >= scrubAdjustment->upper )
02905             previewPosition = info->end - info->begin;
02906         delete info;
02907         PreviewFrame();
02908         g_signal_emit_by_name( scrubAdjustment, "changed" );
02909     }
02910     catch ( const char * exc )
02911     {
02912     }
02913 }
02914 
02915 static void on_drawingarea_refresh_required( GtkWidget *some_widget, GdkEventConfigure *event, gpointer user_data )
02916 {
02917     try
02918     {
02919         ( ( PageMagick * ) user_data )->PreviewFrame();
02920     }
02921     catch ( const char * exc )
02922     {
02923     }
02924 }
02925 
02926 
02927 class FXSelectedFrames : public SelectedFrames
02928 {
02929 protected:
02930     bool seekable;
02931     int start;
02932     int end;
02933     double increment;
02934     bool frames_reverse;
02935     bool effect_reverse;
02936     double real_start;
02937     double real_end;
02938     int b_frame_type;
02939     GdkColor color;
02940     PageMagick* magick;
02941 
02942 public:
02943     void Initialise( PageMagick *page )
02944     {
02945         GtkNotebook * notebook = GTK_NOTEBOOK( lookup_widget( page->window, "notebook_magick_frames" ) );
02946         int source = gtk_notebook_get_current_page( notebook );
02947         magick = page;
02948 
02949         if ( source == 0 )
02950         {
02951             // Obtain begining and ending of sequence
02952             start = 0;
02953             end = GetCurrentPlayList().GetNumFrames();
02954             increment = 1;
02955             frames_reverse = false;
02956             effect_reverse = false;
02957             real_start = 0;
02958             real_end = 1;
02959 
02960             GtkEntry *startSpin = GTK_ENTRY( lookup_widget( page->window, "spinbutton_magick_start" ) );
02961             GtkEntry *endSpin = GTK_ENTRY( lookup_widget( page->window, "spinbutton_magick_end" ) );
02962 
02963             if ( GetCurrentPlayList().GetNumFrames() != 0 )
02964             {
02965                 seekable = true;
02966                 start = atoi( gtk_entry_get_text( startSpin ) );
02967                 end = atoi( gtk_entry_get_text( endSpin ) );
02968                 GtkToggleButton *limit = GTK_TOGGLE_BUTTON( lookup_widget( page->window, "checkbutton_magick_frame_limit" ) );
02969                 if ( gtk_toggle_button_get_active( limit ) )
02970                 {
02971                     GtkEntry * spin = GTK_ENTRY( lookup_widget( page->window, "spinbutton_magick_limit" ) );
02972                     GtkMenu *menu = GTK_MENU( gtk_option_menu_get_menu( GTK_OPTION_MENU( lookup_widget( page->window, "optionmenu_magick_frame_offset" ) ) ) );
02973                     GtkWidget *active_item = gtk_menu_get_active( menu );
02974                     if ( g_list_index ( GTK_MENU_SHELL ( menu ) ->children, active_item ) == 1 )
02975                     {
02976                         int requested_end = start + atoi( gtk_entry_get_text( spin ) ) - 1;
02977                         if ( requested_end < end )
02978                             end = requested_end;
02979                     }
02980                     else
02981                     {
02982                         start = end - atoi( gtk_entry_get_text( spin ) ) + 1;
02983                     }
02984                 }
02985             }
02986             else
02987             {
02988                 seekable = false;
02989             }
02990 
02991             // Determine speed
02992             GtkToggleButton *speed = GTK_TOGGLE_BUTTON( lookup_widget( page->window, "checkbutton_speed" ) );
02993             if ( gtk_toggle_button_get_active( speed ) )
02994             {
02995                 GtkRange * range = GTK_RANGE( lookup_widget( page->window, "hscale_speed" ) );
02996                 increment = range->adjustment->value;
02997             }
02998 
02999             // Determine direction
03000             GtkToggleButton *reverse_button = GTK_TOGGLE_BUTTON( lookup_widget( page->window, "checkbutton_reverse" ) );
03001             frames_reverse = gtk_toggle_button_get_active( reverse_button );
03002         }
03003         else
03004         {
03005             seekable = false;
03006         }
03007 
03008         // Check if we're reversed (currently only image transitions have a global effect reverse)
03009         GtkNotebook *notebookImage = GTK_NOTEBOOK( lookup_widget( page->window, "notebook_magick_video" ) );
03010 
03011         int current = gtk_notebook_get_current_page( notebookImage );
03012 
03013         if ( current == 1 )
03014         {
03015             GtkMenu * menu = GTK_MENU( gtk_option_menu_get_menu( GTK_OPTION_MENU( lookup_widget( page->window, "optionmenu_direction" ) ) ) );
03016             GtkWidget *active_item = gtk_menu_get_active( menu );
03017             effect_reverse = g_list_index ( GTK_MENU_SHELL ( menu ) ->children, active_item ) == 1;
03018 
03019             GtkRange *range = GTK_RANGE( lookup_widget( page->window, "hscale_transition_start" ) );
03020             real_start = range->adjustment->value;
03021             range = GTK_RANGE( lookup_widget( page->window, "hscale_transition_end" ) );
03022             real_end = range->adjustment->value;
03023 
03024             GtkColorButton *colorButton = GTK_COLOR_BUTTON( lookup_widget( page->window, "colorpicker_magick_transition" ) );
03025             gtk_color_button_get_color( colorButton, &color );
03026 
03027             GtkToggleButton *toggle = GTK_TOGGLE_BUTTON( lookup_widget( page->window, "radiobutton_magick_transition_colour" ) );
03028 
03029             if ( !gtk_toggle_button_get_active( toggle ) )
03030             {
03031                 GtkMenu * menu = GTK_MENU( gtk_option_menu_get_menu( GTK_OPTION_MENU( lookup_widget( page->window, "optionmenu_magick_transition_frame" ) ) ) );
03032                 GtkWidget *active_item = gtk_menu_get_active( menu );
03033                 b_frame_type = g_list_index ( GTK_MENU_SHELL ( menu ) ->children, active_item );
03034             }
03035             else
03036             {
03037                 b_frame_type = 3;
03038             }
03039         }
03040         else
03041         {
03042             b_frame_type = -1;
03043             effect_reverse = false;
03044             real_start = 0;
03045             real_end = 1;
03046         }
03047     }
03048 
03049     int GetNumInputFrames( )
03050     {
03051         if ( seekable )
03052             return end - start + 1;
03053         else
03054             return 0;
03055     }
03056 
03057     bool IsEffectReversed( )
03058     {
03059         return effect_reverse;
03060     }
03061 
03062     double GetRealStart( )
03063     {
03064         return real_start;
03065     }
03066 
03067     double GetRealEnd( )
03068     {
03069         return real_end;
03070     }
03071 
03072     int GetNumOutputFrames( )
03073     {
03074         return ( int ) ( GetNumInputFrames( ) / increment );
03075     }
03076 
03077     double GetPosition( int index )
03078     {
03079         return index / GetNumOutputFrames( );
03080     }
03081 
03082     double GetFrameDelta( )
03083     {
03084         return 1 / GetNumOutputFrames( );
03085     }
03086 
03087     int GetIndex( double position )
03088     {
03089         if ( frames_reverse )
03090             position = 1 - position;
03091         return ( int ) ( GetNumOutputFrames( ) * position + 0.5 );
03092     }
03093 
03094     void GetScaledImage( int index, uint8_t *image, int width = 0, int height = 0 )
03095     {
03096         // Get the current playlist
03097         PlayList & list = GetCurrentPlayList();
03098 
03099         if ( index >= 0 && index < list.GetNumFrames( ) )
03100         {
03101             // Get a frame to work with
03102             Frame & frame = *( GetFramePool() ->GetFrame() );
03103 
03104             frame.decoder->quality = DV_QUALITY_BEST;
03105 
03106             // Obtain the frame as specified by the index
03107             list.GetFrame( index, frame );
03108 
03109             // If the width and height is specified
03110             if ( width != 0 && height != 0 )
03111             {
03112                 // Create a temporary space to hold the full RGB image
03113                 uint8_t * temp = new uint8_t[ frame.GetWidth( ) * frame.GetHeight( ) * 3 ];
03114 
03115                 // Extract it
03116                 frame.ExtractRGB( temp );
03117 
03118                 // Convert to a GDK Image
03119                 GdkPixbuf *im1 = gdk_pixbuf_new_from_data( temp, GDK_COLORSPACE_RGB, FALSE, 8,
03120                                  frame.GetWidth( ), frame.GetHeight( ), frame.GetWidth( ) * 3, NULL, NULL );
03121 
03122                 // Clone and scale
03123                 GdkPixbuf *im2 = gdk_pixbuf_scale_simple( im1, width, height, GDK_INTERP_HYPER );
03124 
03125                 // Copy it into the image
03126                 memcpy( image, gdk_pixbuf_get_pixels( im2 ), width * height * 3 );
03127 
03128                 // Destroy the GDK images
03129                 g_object_unref( im2 );
03130                 g_object_unref( im1 );
03131 
03132                 // Delete the temporary space
03133                 delete[] temp;
03134             }
03135             else
03136             {
03137                 // Extract it
03138                 frame.ExtractRGB( image );
03139             }
03140 
03141             GetFramePool() ->DoneWithFrame( &frame );
03142         }
03143         else
03144         {
03145             uint8_t *end = image + width * height * 3;
03146             for ( uint8_t * p = image; p < end; )
03147             {
03148                 *p ++ = color.red >> 8;
03149                 *p ++ = color.green >> 8;
03150                 *p ++ = color.blue >> 8;
03151             }
03152         }
03153     }
03154 
03155     void GetImageA( double position, uint8_t *image, int width = 0, int height = 0 )
03156     {
03157         GetScaledImage( start + GetIndex( position ), image, width, height );
03158     }
03159 
03160     void GetImageB( double position, uint8_t *image, int width = 0, int height = 0 )
03161     {
03162         switch ( b_frame_type )
03163         {
03164         case 1:
03165             GetScaledImage( ( int ) ( end + 1 ), image, width, height );
03166             break;
03167         case 2:
03168             GetScaledImage( ( int ) ( start - 1 ), image, width, height );
03169             break;
03170         case 0:
03171             GetScaledImage( ( int ) ( end + 1 + position * GetNumInputFrames( ) ), image, width, height );
03172             break;
03173         case - 1:
03174         case 3:
03175             {
03176                 uint8_t *end = image + width * height * 3;
03177                 for ( uint8_t * p = image; p < end; )
03178                 {
03179                     *p ++ = color.red >> 8;
03180                     *p ++ = color.green >> 8;
03181                     *p ++ = color.blue >> 8;
03182                 }
03183             }
03184             break;
03185         }
03186     }
03187 
03188     void GetAudio( int index, int16_t **audio, short int &channels, int &frequency, int &samples )
03189     {
03190         // Get the current playlist
03191         PlayList & list = GetCurrentPlayList();
03192 
03193         if ( index >= 0 && index < list.GetNumFrames( ) )
03194         {
03195             // Get a frame to work with
03196             Frame & frame = *( GetFramePool() ->GetFrame() );
03197 
03198             // Obtain the frame as specified by the index
03199             list.GetFrame( index, frame );
03200 
03201             // Extract the audio
03202             if ( frame.ExtractAudio( audio ) )
03203             {
03204                 // Update the info
03205                 AudioInfo info;
03206                 frame.GetAudioInfo( info );
03207                 channels = info.channels;
03208                 frequency = info.frequency;
03209                 samples = info.samples;
03210             }
03211             else
03212             {
03213                 channels = 2;
03214                 // XXX: frequency not known! But are any plugins really using this?
03215                 frequency = 48000;
03216                 samples = frequency / int( frame.GetFrameRate() );
03217                 for ( int i = 0; i < channels; i++ )
03218                     memset( audio[i], 0, samples * sizeof(int16_t) );
03219             }
03220             // Return the frame to the pool
03221             GetFramePool() ->DoneWithFrame( &frame );
03222         }
03223         else if ( list.GetNumFrames( ) )
03224         {
03225             // Get a frame to work with
03226             Frame & frame = *( GetFramePool() ->GetFrame() );
03227 
03228             // Obtain the frame as specified by the index
03229             list.GetFrame( index, frame );
03230 
03231             // Update the info
03232             AudioInfo info;
03233             frame.GetAudioInfo( info );
03234             channels = info.channels;
03235             frequency = info.frequency;
03236             samples = info.samples;
03237 
03238             // Wipe the audio
03239             for ( int i = 0; i < channels; i ++ )
03240                 memset( audio[ i ], 0, samples * sizeof( int16_t ) );
03241 
03242             // Return the frame to the pool
03243             GetFramePool() ->DoneWithFrame( &frame );
03244         }
03245     }
03246 
03247     void GetAudioA( double position, int16_t **audio, short int &channels, int &frequency, int &samples )
03248     {
03249         GetAudio( start + GetIndex( position ), audio, channels, frequency, samples );
03250     }
03251 
03252     void GetAudioB( double position, int16_t **audio, short int &channels, int &frequency, int &samples )
03253     {
03254         switch ( b_frame_type )
03255         {
03256         case 0:
03257             GetAudio( ( int ) ( end + 1 + position * GetNumInputFrames( ) ), audio, channels, frequency, samples );
03258             break;
03259         case - 1:
03260         case 1:
03261         case 2:
03262         case 3:
03263             GetAudio( -1, audio, channels, frequency, samples );
03264             break;
03265         }
03266     }
03267 
03268     void Repaint( )
03269     {
03270         while ( gtk_events_pending() )
03271             gtk_main_iteration();
03272         if ( magick )
03273             magick->PreviewFrame();
03274     }
03275 
03276     bool IsRepainting( )
03277     {
03278         return magick->IsRepainting();
03279     }
03280 
03281     bool IsPreviewing( )
03282     {
03283         return magick->IsPreviewing();
03284     }
03285 };
03286 
03287 // Get the selected frames for FX
03288 SelectedFrames &GetSelectedFramesForFX( )
03289 {
03290     static FXSelectedFrames selected;
03291     selected.Initialise( common->getPageMagick( ) );
03292     return selected;
03293 }
03294 
03295 GtkWindow* GetKinoWidgetWindow( )
03296 {
03297     return KinoCommon::getWidgetWindow( common->getWidget() );
03298 }
03299 
03300 void Repaint( )
03301 {
03302     GetSelectedFramesForFX().Repaint();
03303 }
03304 
03305 
03306 void PageMagick::ShowCurrentStatus( double position, frame_type type, bool hasPrev, bool hasNext )
03307 {
03308     newPosition = position;
03309     isGuiLocked = true;
03310     // Determine Key button status
03311     GtkWidget *widget = lookup_widget( window, "togglebutton_key_frame" );
03312     if ( rendering )
03313     {
03314         gtk_widget_set_sensitive( widget, false );
03315     }
03316     else
03317     {
03318         gtk_widget_set_sensitive( widget, keyFrameControllerClient != 0 );
03319         if ( type & LOCKED_KEY )     // Locked Key
03320         {
03321             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( widget ), true );
03322             GtkImage* img = GTK_IMAGE( lookup_widget( window, "image_key_frame" ) );
03323             gtk_image_set_from_stock( img, GTK_STOCK_REMOVE, GTK_ICON_SIZE_BUTTON );
03324         }
03325         else if ( type & KEY )      // Normal Key
03326         {
03327             
03328             GtkImage* img = GTK_IMAGE( lookup_widget( window, "image_key_frame" ) );
03329             gtk_image_set_from_stock( img, GTK_STOCK_REMOVE, GTK_ICON_SIZE_BUTTON );
03330             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( widget ), true );
03331         }
03332         else                        // Not Key
03333         {
03334             GtkImage* img = GTK_IMAGE( lookup_widget( window, "image_key_frame" ) );
03335             gtk_image_set_from_stock( img, GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON );
03336             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( widget ), false );
03337         }
03338         isPreviousScene = hasPrev;
03339         isNextScene = hasNext;
03340         common->activateWidgets();
03341     }
03342     isGuiLocked = false;
03343 }
03344 
03345 double PageMagick::GetCurrentPosition( )
03346 {
03347     try
03348     {
03349         PageMagickInfo info( common );
03350         info.GetFrameSource();
03351         return time_info( info, info.begin + previewPosition ).position();
03352     }
03353     catch( const char * exc )
03354     {
03355         return 0;
03356     }
03357 }
03358 
03359 void PageMagick::videoPreviousScene()
03360 {
03361     common->toggleComponents( common->getComponentState(), false );
03362     common->toggleComponents( VIDEO_START_OF_SCENE, false );
03363     common->toggleComponents( VIDEO_STOP, true );
03364     StopPreview();
03365     if ( !isGuiLocked && keyFrameControllerClient )
03366     {
03367         double position = GetCurrentPosition( );
03368         keyFrameControllerClient->OnControllerPrevKey( position );
03369         previewPosition = GetSelectedFramesForFX().GetIndex( newPosition );
03370         PreviewFrame();
03371     }
03372 }
03373 
03374 void PageMagick::videoNextScene()
03375 {
03376     common->toggleComponents( common->getComponentState(), false );
03377     common->toggleComponents( VIDEO_NEXT_SCENE, false );
03378     common->toggleComponents( VIDEO_STOP, true );
03379     StopPreview();
03380     if ( !isGuiLocked && keyFrameControllerClient )
03381     {
03382         double position = GetCurrentPosition( );
03383         keyFrameControllerClient->OnControllerNextKey( position );
03384         previewPosition = GetSelectedFramesForFX().GetIndex( newPosition );
03385         PreviewFrame();
03386     }
03387 }
03388 
03389 void PageMagick::OnKeyFrameControllerKeyChanged( GtkToggleButton* togglebutton )
03390 {
03391     if ( !isGuiLocked && keyFrameControllerClient )
03392     {
03393         double position = GetCurrentPosition( );
03394         keyFrameControllerClient->OnControllerKeyChanged( position,
03395             gtk_toggle_button_get_active( togglebutton ) );
03396     }
03397 }
03398 
03399 
03403 KeyFrameController *GetKeyFrameController( KeyFrameControllerClient *client )
03404 {
03405     common->getPageMagick()->SetKeyFrameControllerClient( client );
03406     return static_cast< KeyFrameController* >( common->getPageMagick() );
03407 }
03408 

Generated on Sun Mar 11 22:11:46 2007 for Kino by  doxygen 1.4.2