00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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 }
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 )
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
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
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
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
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
00901
00902
00903
00904
00905
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
00919 info->SetEnd( info->begin + creator->GetNumberOfFrames() - 1 );
00920 }
00921
00922 void PageMagickCreate::GetFrame( uint8_t *pixels, int16_t **audio, int i )
00923 {
00924
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
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
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
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
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
01192 if ( !transition )
01193 throw _( "Invalid audio filter selected" );
01194
01195 if ( transition->IsBFrameConsumer() )
01196 {
01197
01198
01199
01200
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
01250 if ( common->getPlayList() ->GetFrame( 0, *infoFrame ) )
01251 {
01252
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
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
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
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
01791
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
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
01893 if ( rendering )
01894 return;
01895
01896 GtkWidget *area = GTK_WIDGET( lookup_widget( window, "drawingarea_magick_preview" ) );
01897
01898
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
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
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
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
02111 if ( previewing )
02112 Stop();
02113
02114
02115 if ( rendering )
02116 return ;
02117
02118
02119 rendering = true;
02120 paused = false;
02121
02122
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
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
02144 PageMagickInfo *info = new PageMagickInfo( common );
02145
02146
02147 FILE *output = NULL;
02148
02149 Frame* infoFrame = GetFramePool()->GetFrame();
02150
02151
02152 try
02153 {
02154
02155 time_t datetime = time( NULL );
02156 int frameNum = 0;
02157
02158
02159 info->Initialise();
02160
02161 int audio_number = 0;
02162
02163
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
02176 if ( filename[ 0 ] != '/' )
02177 directory = common->getPlayList() ->GetProjectDirectory( ) + "/";
02178
02179
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
02192 PageMagickFrames *frames = info->GetFrameSource();
02193 PageMagickImage *image = info->GetImageManipulator();
02194 PageMagickAudio *sound = info->GetAudioManipulator();
02195
02196
02197 if ( info->begin > info->end )
02198 throw _( "Invalid frame range specified." );
02199
02200
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
02208 startTime = pauseTime - 0.0;
02209
02210
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;
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
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
02379 if ( 0 == startTime )
02380 {
02381
02382 startTime = now;
02383 nextUpdateTime = now - 1;
02384 snprintf( buf, 512, _( "Rendering frame %i." ), currentFrame );
02385 }
02386 else
02387 {
02388
02389
02390 double time_so_far = now - startTime - pauseTime;
02391 double total_est = time_so_far / ratio;
02392
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
02404
02405
02406 if ( now > nextUpdateTime )
02407 {
02408 common->setStatusBar( buf );
02409 nextUpdateTime = now + 0.25;
02410 }
02411
02412
02413
02414 UpdateProgress( ratio );
02415
02416
02417 if ( paused )
02418 {
02419 struct timespec ts;
02420 ts.tv_sec = 0;
02421 ts.tv_nsec = 1000 * 1000 * 20;
02422 while ( paused )
02423 {
02424 while ( gtk_events_pending() )
02425 gtk_main_iteration();
02426
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
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
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
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
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
02746
02747 else if ( strcmp( cmd, "l" ) == 0 )
02748 {
02749 common->keyboardFeedback( cmd, _( "Move forward" ) );
02750 common->moveByFrames( 1 );
02751 }
02752
02753
02754
02755 else if ( strcmp( cmd, "h" ) == 0 )
02756 {
02757 common->keyboardFeedback( cmd, _( "Move backward" ) );
02758 common->moveByFrames( -1 );
02759 }
02760
02761
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
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
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
02787
02788 else if ( strcmp( cmd, "$" ) == 0 )
02789 {
02790 common->videoEndOfScene( );
02791 common->keyboardFeedback( cmd, _( "Move to end of scene" ) );
02792 }
02793
02794
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
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
02811
02812 else if ( strcmp( cmd, "gg" ) == 0 )
02813 {
02814 common->videoStartOfMovie( );
02815 common->keyboardFeedback( cmd, _( "Move to first frame" ) );
02816 }
02817
02818
02819
02820 else if ( strcmp( cmd, "G" ) == 0 )
02821 {
02822 common->videoEndOfMovie( );
02823 common->keyboardFeedback( cmd, _( "Move to last frame" ) );
02824 }
02825
02826
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
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
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
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
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
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
03097 PlayList & list = GetCurrentPlayList();
03098
03099 if ( index >= 0 && index < list.GetNumFrames( ) )
03100 {
03101
03102 Frame & frame = *( GetFramePool() ->GetFrame() );
03103
03104 frame.decoder->quality = DV_QUALITY_BEST;
03105
03106
03107 list.GetFrame( index, frame );
03108
03109
03110 if ( width != 0 && height != 0 )
03111 {
03112
03113 uint8_t * temp = new uint8_t[ frame.GetWidth( ) * frame.GetHeight( ) * 3 ];
03114
03115
03116 frame.ExtractRGB( temp );
03117
03118
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
03123 GdkPixbuf *im2 = gdk_pixbuf_scale_simple( im1, width, height, GDK_INTERP_HYPER );
03124
03125
03126 memcpy( image, gdk_pixbuf_get_pixels( im2 ), width * height * 3 );
03127
03128
03129 g_object_unref( im2 );
03130 g_object_unref( im1 );
03131
03132
03133 delete[] temp;
03134 }
03135 else
03136 {
03137
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
03191 PlayList & list = GetCurrentPlayList();
03192
03193 if ( index >= 0 && index < list.GetNumFrames( ) )
03194 {
03195
03196 Frame & frame = *( GetFramePool() ->GetFrame() );
03197
03198
03199 list.GetFrame( index, frame );
03200
03201
03202 if ( frame.ExtractAudio( audio ) )
03203 {
03204
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
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
03221 GetFramePool() ->DoneWithFrame( &frame );
03222 }
03223 else if ( list.GetNumFrames( ) )
03224 {
03225
03226 Frame & frame = *( GetFramePool() ->GetFrame() );
03227
03228
03229 list.GetFrame( index, frame );
03230
03231
03232 AudioInfo info;
03233 frame.GetAudioInfo( info );
03234 channels = info.channels;
03235 frequency = info.frequency;
03236 samples = info.samples;
03237
03238
03239 for ( int i = 0; i < channels; i ++ )
03240 memset( audio[ i ], 0, samples * sizeof( int16_t ) );
03241
03242
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
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
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 )
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 )
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
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