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