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

page_editor.cc

Go to the documentation of this file.
00001 /*
00002 * page_edit.cc Notebook Editor Page Object
00003 * Copyright (C) 2001 Charles Yates <charles.yates@pandora.be>
00004 * Copyright (C) 2001-2007 Dan Dennedy <dan@dennedy.org>
00005 *
00006 * This program is free software; you can redistribute it and/or modify
00007 * it under the terms of the GNU General Public License as published by
00008 * the Free Software Foundation; either version 2 of the License, or
00009 * (at your option) any later version.
00010 *
00011 * This program is distributed in the hope that it will be useful,
00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 * GNU General Public License for more details.
00015 *
00016 * You should have received a copy of the GNU General Public License
00017 * along with this program; if not, write to the Free Software Foundation,
00018 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019 */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include <config.h>
00023 #endif
00024 
00025 #include <iostream>
00026 using std::cerr;
00027 using std::endl;
00028 
00029 #include "page_editor.h"
00030 #include "frame.h"
00031 #include "commands.h"
00032 #include "sys/time.h"
00033 #include "pthread.h"
00034 #include "message.h"
00035 #include "filehandler.h"
00036 #include "ieee1394io.h"
00037 #include "gtkenhancedscale.h"
00038 #include "callbacks.h"
00039 #include "storyboard.h"
00040 
00041 #undef PLAY_WITH_STATS
00042 
00043 extern "C"
00044 {
00045 #include "support.h"
00046 
00047     extern KinoCommon *common;
00048     extern struct navigate_control g_nav_ctl;
00049     char cmd[ 256 ] = { 0 };
00050     char lastcmd[ 256 ] = { 0 };
00051     static int _getOneSecond( void );
00052 
00053     static void resetThreads( );
00054     static void *readThread( void * info );
00055     static void *audioThread( void * info );
00056     static void *videoThread( void * info );
00057     static pthread_t readthread = 0;
00058     static pthread_t audiothread = 0;
00059     static pthread_t videothread = 0;
00060     static pthread_mutex_t threadlock = PTHREAD_MUTEX_INITIALIZER;
00061     static pthread_mutex_t readlock = PTHREAD_MUTEX_INITIALIZER;
00062     static int newFrame = 0;
00063     static int lastFrame = -1;
00064 
00065 #define PLAYBACK_FRAMES 50
00066 
00067     static Frame *frameContent[ PLAYBACK_FRAMES ];
00068     IEEE1394Writer *writer1394 = NULL;
00069 
00070     static gboolean doScrub = FALSE;
00071     gboolean
00072     on_scrub_bar_button_press_event ( GtkWidget * widget,
00073                                       GdkEventButton * event,
00074                                       gpointer user_data )
00075     {
00076         doScrub = TRUE;
00077         videoPause();
00078         return FALSE;
00079     }
00080 
00081 
00082     gboolean
00083     on_scrub_bar_button_release_event ( GtkWidget * widget,
00084                                         GdkEventButton * event,
00085                                         gpointer user_data )
00086     {
00087         doScrub = FALSE;
00088         return FALSE;
00089     }
00090 
00091     gboolean
00092     on_scrub_bar_value_changed_event ( GtkWidget * widget,
00093                                        GdkEventButton * event,
00094                                        gpointer user_data )
00095     {
00096         if ( doScrub == TRUE )
00097             moveToFrame( ( int ) GTK_ADJUSTMENT( widget ) ->value );
00098         return FALSE;
00099     }
00100 
00101 }
00102 
00108 PageEditor::PageEditor( KinoCommon *common )
00109 {
00110     cerr << "> Creating page editor" << endl;
00111     this->common = common;
00112 
00113     this->frameArea = GTK_DRAWING_AREA( lookup_widget( common->getWidget(), "drawingarea1" ) );
00114     gtk_widget_set_double_buffered( GTK_WIDGET( frameArea ), FALSE );
00115     this->positionLabelCurrent = GTK_LABEL( lookup_widget( common->getWidget(), "position_label_current" ) );
00116     this->positionLabelTotal = GTK_LABEL( lookup_widget( common->getWidget(), "position_label_total" ) );
00117     this->lastFrameShown = -1;
00118     this->g_copiedPlayList = new PlayList();
00119 
00120     scrubAdjustment = GTK_ADJUSTMENT( gtk_adjustment_new( 0, 0, 0, 1, 10, 0 ) );
00121     g_signal_connect( G_OBJECT( scrubAdjustment ), "value_changed",
00122                       G_CALLBACK( on_scrub_bar_value_changed_event ), NULL );
00123 
00124     scrubBar = gtk_enhanced_scale_new( ( GtkObject** ) & scrubAdjustment, 1 );
00125     sceneIndex = g_array_new( FALSE, FALSE, sizeof( int ) );
00126     gtk_widget_set_name( scrubBar, "scrubBar" );
00127     gtk_widget_ref( scrubBar );
00128     gtk_object_set_data_full( GTK_OBJECT( common->getWidget() ), "scrubBar", scrubBar,
00129                               ( GtkDestroyNotify ) gtk_widget_unref );
00130     GtkWidget *vbox_edit = lookup_widget( common->getWidget(), "vbox58" );
00131     gtk_widget_show( scrubBar );
00132     gtk_box_pack_start( GTK_BOX( vbox_edit ), scrubBar, FALSE, TRUE, 0 );
00133     g_signal_connect( G_OBJECT( scrubBar ), "button_press_event",
00134                       G_CALLBACK( on_scrub_bar_button_press_event ), NULL );
00135     g_signal_connect( G_OBJECT( scrubBar ), "button_release_event",
00136                       G_CALLBACK( on_scrub_bar_button_release_event ), NULL );
00137 
00138 }
00139 
00143 PageEditor::~PageEditor( )
00144 {
00145     cerr << "> Destroying page editor" << endl;
00146     delete this->g_copiedPlayList;
00147     if ( sceneIndex != NULL )
00148         g_array_free( sceneIndex, TRUE );
00149 }
00150 
00154 void PageEditor::newFile()
00155 {
00156     this->stopNavigator();
00157     common->loadSplash( frameArea );
00158     this->ResetBar( );
00159 }
00160 
00164 void PageEditor::start()
00165 {
00166     cerr << ">> Starting Editor" << endl;
00167     
00168     for ( int i = 0; i < PLAYBACK_FRAMES; i ++ )
00169         frameContent[ i ] = GetFramePool( ) ->GetFrame( );
00170 
00171     this->displayer = new FrameDisplayer();
00172     if ( Preferences::getInstance().dv1394Preview )
00173     {
00174 #ifdef HAVE_IEC61883
00175         AVC avc;
00176         Preferences::getInstance( ).phyID = avc.getNodeId( Preferences::getInstance( ).avcGUID );
00177         Preferences::getInstance( ).phyID = avc.isPhyIDValid( Preferences::getInstance( ).phyID );
00178         if ( !writer1394 )
00179             writer1394 = new iec61883Writer(
00180                          ( avc.getPort() < 0 ) ? 0 : avc.getPort(),
00181                          Preferences::getInstance().channel,
00182                          2 );
00183 #else
00184         if ( Preferences::getInstance().dvExportDevice > 0 && !writer1394 )
00185             writer1394 = new dv1394Writer(
00186                          Preferences::getInstance().dvExportDevice,
00187                          Preferences::getInstance().channel,
00188                          2,
00189                          Preferences::getInstance().cip_n,
00190                          Preferences::getInstance().cip_d,
00191                          Preferences::getInstance().syt_offset );
00192 #endif
00193     }
00194 
00195     this->lastFrameShown = common->g_currentFrame;
00196 
00197     gtk_widget_grab_focus( GTK_WIDGET( frameArea ) );
00198     common->packIt( "packer_edit", "packer_edit_outer" );
00199 
00200     gtk_notebook_set_page( GTK_NOTEBOOK( lookup_widget( common->getWidget(), "notebook_keyhelp" ) ), 0 );
00201     gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( lookup_widget( common->getWidget(), "menuitem_editor" ) ), TRUE );
00202 }
00203 
00207 gulong PageEditor::activate()
00208 {
00209     return EDIT_MENU |
00210            SCENE_LIST |
00211            VIDEO_START_OF_MOVIE |
00212            VIDEO_START_OF_SCENE |
00213            VIDEO_REWIND |
00214            VIDEO_BACK |
00215            VIDEO_PLAY |
00216            VIDEO_PAUSE |
00217            VIDEO_STOP |
00218            VIDEO_FORWARD |
00219            VIDEO_FAST_FORWARD |
00220            VIDEO_NEXT_SCENE |
00221            VIDEO_END_OF_MOVIE |
00222            VIDEO_SHUTTLE |
00223            INFO_FRAME;
00224 }
00225 
00229 void PageEditor::clean()
00230 {
00231     cerr << ">> Leaving Editor" << endl;
00232     stopNavigator();
00233     delete displayer;
00234     displayer = 0;
00235     delete writer1394;
00236     writer1394 = NULL;
00237     for ( int i = 0; i < PLAYBACK_FRAMES; i ++ )
00238         GetFramePool( ) ->DoneWithFrame( frameContent[ i ] );
00239     gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( lookup_widget( common->getWidget(), "menuitem_editor" ) ), FALSE );
00240     cerr << ">> Left Editor" << endl;
00241 }
00242 
00246 void PageEditor::startNavigator()
00247 {
00248     stopNavigator( );
00249     g_nav_ctl.active = TRUE;
00250     resetThreads( );
00251     pthread_create( &readthread, NULL, readThread, &g_nav_ctl );
00252     pthread_create( &audiothread, NULL, audioThread, &g_nav_ctl );
00253     pthread_create( &videothread, NULL, videoThread, &g_nav_ctl );
00254 }
00255 
00259 void PageEditor::stopNavigator()
00260 {
00261     if ( g_nav_ctl.active )
00262     {
00263         g_nav_ctl.active = FALSE;
00264         gdk_threads_leave();
00265         pthread_join( readthread, NULL );
00266         pthread_join( audiothread, NULL );
00267         pthread_join( videothread, NULL );
00268         gdk_threads_enter();
00269         getFrameDisplayer()->CloseSound();
00270     }
00271 }
00272 
00279 void PageEditor::movedToFrame( int frame )
00280 {
00281     if ( g_nav_ctl.active == FALSE )
00282     {
00283         showFrame( frame, ( frame == lastFrameShown ) || ( Preferences::getInstance().audioScrub == FALSE ) );
00284     }
00285     else
00286     {
00287         stopNavigator();
00288         common->g_currentFrame = frame;
00289         startNavigator();
00290     }
00291 }
00292 
00299 void PageEditor::showFrame( int i, gboolean no_audio )
00300 {
00301     DrawBar( i );
00302     if ( common->getPlayList() ->GetNumFrames() == 0 )
00303     {
00304         common->loadSplash( frameArea );
00305         common->showFrameInfo( 0 );
00306     }
00307     else
00308     {
00309         Frame *frame = GetFramePool( ) ->GetFrame( );
00310         common->getPlayList() ->GetFrame( i, *frame );
00311         common->showFrameInfo( i );
00312         if ( writer1394 != NULL )
00313             writer1394->SendFrame( *frame, false ) ;
00314         getFrameDisplayer() ->Put( *frame, GTK_WIDGET( frameArea ), no_audio );
00315         lastFrameShown = i;
00316         GetFramePool( ) ->DoneWithFrame( frame );
00317     }
00318 }
00319 
00323 void PageEditor::videoStartOfMovie()
00324 {
00325     common->moveToFrame( 0 );
00326     common->toggleComponents( VIDEO_START_OF_MOVIE, false );
00327 }
00328 
00332 void PageEditor::videoPreviousScene()
00333 {
00334     int frame = common->getPlayList() ->FindStartOfScene( common->g_currentFrame );
00335 
00336     if ( g_nav_ctl.active == FALSE && frame == common->g_currentFrame )
00337         frame = common->getPlayList() ->FindStartOfScene( frame - 1 );
00338     else if ( g_nav_ctl.active == TRUE && ( frame == common->g_currentFrame || ( common->g_currentFrame - frame ) <= 15 ) )
00339         frame = common->getPlayList() ->FindStartOfScene( frame - 1 );
00340 
00341     common->moveToFrame( frame );
00342     common->toggleComponents( VIDEO_START_OF_SCENE, false );
00343 }
00344 
00348 void PageEditor::videoStartOfScene()
00349 {
00350     int frame = common->getPlayList() ->FindStartOfScene( common->g_currentFrame );
00351     common->moveToFrame( frame );
00352     common->toggleComponents( VIDEO_START_OF_SCENE, false );
00353 }
00354 
00358 void PageEditor::videoRewind()
00359 {
00360     common->toggleComponents( common->getComponentState(), false );
00361     stopNavigator();
00362     // Toggle Rewind state
00363     if ( g_nav_ctl.step == -10 )
00364     {
00365         g_nav_ctl.step = 1;
00366         g_nav_ctl.rate = 1;
00367         common->toggleComponents( VIDEO_REWIND, false );
00368         common->toggleComponents( VIDEO_STOP, true );
00369     }
00370     else
00371     {
00372         common->toggleComponents( VIDEO_REWIND, true );
00373         g_nav_ctl.step = -10;
00374         g_nav_ctl.rate = 0;
00375         startNavigator();
00376     }
00377 }
00378 
00383 void PageEditor::videoBack(int step)
00384 {
00385     common->toggleComponents( common->getComponentState(), false );
00386     if ( g_nav_ctl.active )
00387     {
00388         stopNavigator();
00389         if ( g_nav_ctl.step != -1 )
00390         {
00391             g_nav_ctl.step = -1;
00392             g_nav_ctl.rate = 1;
00393             common->toggleComponents( VIDEO_BACK, true );
00394             startNavigator();
00395         }
00396         else
00397         {
00398             g_nav_ctl.step = 1;
00399             g_nav_ctl.rate = 0;
00400             common->toggleComponents( VIDEO_BACK, false );
00401             common->toggleComponents( VIDEO_STOP, true );
00402         }
00403     }
00404     else
00405     {
00406         common->moveByFrames( step );
00407         common->toggleComponents( VIDEO_BACK, false );
00408         common->toggleComponents( VIDEO_STOP, true );
00409     }
00410 }
00411 
00415 void PageEditor::videoPlay()
00416 {
00417     common->toggleComponents( common->getComponentState(), false );
00418     if ( g_nav_ctl.active == FALSE || g_nav_ctl.step != 1 )
00419     {
00420         common->toggleComponents( VIDEO_PLAY, true );
00421         stopNavigator();
00422         g_nav_ctl.step = 1;
00423         g_nav_ctl.rate = 1;
00424         startNavigator();
00425     }
00426     else
00427     {
00428         stopNavigator();
00429         common->toggleComponents( VIDEO_PLAY, false );
00430         common->toggleComponents( VIDEO_STOP, true );
00431     }
00432 }
00433 
00437 void PageEditor::videoPause()
00438 {
00439     videoStop();
00440 }
00441 
00445 void PageEditor::videoStop()
00446 {
00447     common->toggleComponents( common->getComponentState(), false );
00448     common->toggleComponents( VIDEO_STOP, true );
00449     stopNavigator();
00450     g_nav_ctl.step = 0;
00451     g_nav_ctl.rate = 0;
00452 }
00453 
00458 void PageEditor::videoForward(int step)
00459 {
00460     
00461     common->toggleComponents( common->getComponentState(), false );
00462     if ( g_nav_ctl.active && g_nav_ctl.step != 1 )
00463     {
00464         common->toggleComponents( VIDEO_FORWARD, true );
00465         stopNavigator();
00466         g_nav_ctl.step = 1;
00467         g_nav_ctl.rate = 1;
00468         startNavigator();
00469     }
00470     else
00471     {
00472         stopNavigator();
00473         common->moveByFrames( step );
00474         common->toggleComponents( VIDEO_FORWARD, false );
00475         common->toggleComponents( VIDEO_STOP, true );
00476     }
00477 }
00478 
00482 void PageEditor::videoFastForward()
00483 {
00484     common->toggleComponents( common->getComponentState(), false );
00485     stopNavigator();
00486     if ( g_nav_ctl.step != 10 )
00487     {
00488         common->toggleComponents( VIDEO_FAST_FORWARD, true );
00489         g_nav_ctl.step = 10;
00490         g_nav_ctl.rate = 0;
00491         startNavigator();
00492     }
00493     else
00494     {
00495         g_nav_ctl.step = 1;
00496         g_nav_ctl.rate = 1;
00497         common->toggleComponents( VIDEO_FAST_FORWARD, false );
00498         common->toggleComponents( VIDEO_STOP, true );
00499     }
00500 }
00501 
00509 void PageEditor::videoShuttle( int angle )
00510 {
00511     int frames_sec = _getOneSecond();
00512     int speedTable[] = {
00513             0,
00514             8,  10, 15, 20, 33, 50, 75,
00515             100,
00516             200, 300, 400, 500, 800, 1200,
00517             ( frames_sec * 100 ) };
00518     char s[ 64 ];
00519 
00520     if ( angle < -15 )
00521         angle = -15;
00522     if ( angle > 15 )
00523         angle = 15;
00524 
00525     int speed = speedTable[ ( angle < 0 ) ? -angle : angle ] * ( ( angle < 0 ) ? -1 : 1 );
00526     if ( speed == 0 || g_nav_ctl.step != speed / 100 || g_nav_ctl.rate != 100 / speed )
00527     {
00528         stopNavigator( );
00529         if ( speed == 0 )
00530         {
00531             common->keyboardFeedback( "", "" );
00532             common->toggleComponents( VIDEO_STOP, true );
00533         }
00534         else
00535         {
00536             g_nav_ctl.step = speed / 100;
00537             g_nav_ctl.rate = 100 / speed;
00538             g_nav_ctl.subframe = 0;
00539             startNavigator();
00540             snprintf( s, 63, _( "Shuttle %+.1f fps" ), ( float ) speed / 100.0 * frames_sec );
00541             common->keyboardFeedback( "", s );
00542         }
00543     }
00544 }
00545 
00549 void PageEditor::videoNextScene()
00550 {
00551     int frame = common->getPlayList() ->FindEndOfScene( common->g_currentFrame );
00552     common->moveToFrame( frame + 1 );
00553     common->toggleComponents( VIDEO_NEXT_SCENE, false );
00554 }
00555 
00559 void PageEditor::videoEndOfScene()
00560 {
00561     int frame = common->getPlayList() ->FindEndOfScene( common->g_currentFrame );
00562     common->moveToFrame( frame );
00563     common->toggleComponents( VIDEO_NEXT_SCENE, false );
00564 }
00565 
00569 void PageEditor::videoEndOfMovie()
00570 {
00571     common->toggleComponents( common->getComponentState(), false );
00572     common->toggleComponents( VIDEO_END_OF_MOVIE, true );
00573     stopNavigator();
00574     common->moveToFrame( common->getPlayList() ->GetNumFrames() - 1 );
00575     common->toggleComponents( VIDEO_END_OF_MOVIE, false );
00576     common->toggleComponents( VIDEO_STOP, true );
00577 }
00578 
00584 void PageEditor::selectScene( int i )
00585 {
00586     vector <int> scene = GetScene();
00587     int value = i == 0 ? 0 : scene[ i - 1 ];
00588     common->moveToFrame( value );
00589 }
00590 
00596 gboolean PageEditor::processKeyboard( GdkEventKey *event )
00597 {
00598     gboolean ret = FALSE;
00599 
00600     // Only process while not escape mode
00601     if ( g_nav_ctl.escaped == FALSE )
00602     {
00603         if ( strcmp( lastcmd, "alt" ) == 0 )
00604         {
00605             strcpy( lastcmd, "" );
00606             return ret;
00607         }
00608 
00609         // Translate special keys to equivalent command
00610         switch ( event->keyval )
00611         {
00612         case GDK_Home:
00613             strcat( cmd, "gg");
00614             ret = TRUE;
00615             break;
00616         case GDK_End:
00617             strcat( cmd, "G");
00618             ret = TRUE;
00619             break;
00620         case GDK_Page_Up:
00621             strcat( cmd, "5^" );
00622             ret = TRUE;
00623             break;
00624         case GDK_Page_Down:
00625             strcat( cmd, "5$" );
00626             ret = TRUE;
00627             break;
00628         case GDK_BackSpace:
00629         case GDK_Left:
00630             strcat( cmd, "h" );
00631             ret = TRUE;
00632             break;
00633         case GDK_Up:
00634             strcat( cmd, "k" );
00635             ret = TRUE;
00636             break;
00637         case GDK_Right:
00638             strcat( cmd, "l" );
00639             ret = TRUE;
00640             break;
00641         case GDK_Return:
00642             if ( cmd[ 0 ] != 0 )
00643             {
00644                 // Last command is now
00645                 strcpy( lastcmd, cmd );
00646 
00647                 // end the command entry
00648                 cmd[ 0 ] = 0;
00649                 common->setStatusBar( "" );
00650             }
00651             break;
00652         case GDK_Down:
00653             strcat( cmd, "j" );
00654             ret = TRUE;
00655             break;
00656         case GDK_Delete:
00657             strcat( cmd, "x" );
00658             ret = TRUE;
00659             break;
00660         case GDK_Escape:
00661             common->keyboardFeedback( cmd, _( "Stop" ) );
00662             common->videoStop( );
00663             cmd[ 0 ] = 0;
00664             return ret;
00665         case GDK_Alt_L:
00666         case GDK_Alt_R:
00667             strcpy( lastcmd, "alt" );
00668             return ret;
00669         default:
00670             if ( strcmp( event->string, "." ) )
00671                 strcat( cmd, event->string );
00672             break;
00673         }
00674 
00675         if ( !strcmp( event->string, "." ) )
00676             strcpy( cmd, lastcmd );
00677         else if ( cmd[ 0 ] == 0x06)   // Ctrl+f
00678             strcpy( cmd, "5$" );
00679         else if ( cmd[ 0 ] == 0x02 )   // Ctrl+b
00680             strcpy( cmd, "5^" );
00681         else if ( cmd[ 0 ] == 0x12 )
00682             strcpy( cmd, "Ctrl+R" );
00683 
00684 #if 0
00685         printf( "send_event: %2.2x\n", event->send_event );
00686         printf( "time  : %8.8x\n", event->time );
00687         printf( "state : %8.8x\n", event->state );
00688         printf( "keyval: %8.8x\n", event->keyval );
00689         printf( "length: %8.8x\n", event->length );
00690         printf( "string: %s\n", event->string );
00691         printf( "(hex) : %2.2x\n", event->string[ 0 ] );
00692         printf( "cmd   : %s\n", cmd );
00693         printf( "(hex) : %8.8x\n", cmd[ 0 ] );
00694         fflush( stdout );
00695 #endif
00696 
00697         processCommand( cmd );
00698     }
00699 
00700     return ret;
00701 }
00702 
00708 gboolean PageEditor::processCommand( char *command )
00709 {
00710     int start, end;
00711     int count = 1;
00712     char real[ 256 ] = "";
00713 
00714     strcpy( cmd, command );
00715 
00716     switch ( sscanf( cmd, "%d%s", &count, real ) )
00717     {
00718     case 1:
00719         // Numeric value only - return immediately if the cmd is not "0"
00720         if ( strcmp( cmd, "0" ) )
00721         {
00722             common->keyboardFeedback( cmd, "" );
00723             return FALSE;
00724         }
00725         break;
00726     case 0:
00727         sscanf( cmd, "%s", real );
00728         count = 1;
00729         break;
00730     }
00731 
00732     if ( strcmp( cmd, "." ) )
00733         strcpy( lastcmd, cmd );
00734 
00735     /* Navigation */
00736 
00737     /* play, pause */
00738 
00739     if ( strcmp( cmd, " " ) == 0 )
00740     {
00741         if ( g_nav_ctl.active == FALSE )
00742         {
00743             common->keyboardFeedback( cmd, _( "Play" ) );
00744             common->videoPlay( );
00745         }
00746         else
00747         {
00748             common->keyboardFeedback( cmd, _( "Pause" ) );
00749             common->videoPause( );
00750         }
00751         cmd[ 0 ] = 0;
00752     }
00753 
00754     else if ( strcmp( real, "Esc" ) == 0 )
00755     {
00756         common->keyboardFeedback( cmd, _( "Stop" ) );
00757         common->videoStop( );
00758         cmd[ 0 ] = 0;
00759     }
00760 
00761     /* advance one frame */
00762 
00763     else if ( strcmp( real, "l" ) == 0 )
00764     {
00765         common->keyboardFeedback( cmd, _( "Move forward" ) );
00766         common->moveByFrames( count );
00767         cmd[ 0 ] = 0;
00768     }
00769 
00770     /* backspace one frame */
00771 
00772     else if ( strcmp( real, "h" ) == 0 )
00773     {
00774         common->keyboardFeedback( cmd, _( "Move backward" ) );
00775         common->moveByFrames( 0 - count );
00776         cmd[ 0 ] = 0;
00777     }
00778 
00779     /* advance one second */
00780 
00781     else if ( strcmp( real, "w" ) == 0 || strcmp( real, "W" ) == 0 ||
00782               strcmp( real, "e" ) == 0 || strcmp( real, "E" ) == 0 )
00783     {
00784         common->keyboardFeedback( cmd, _( "Move forward second" ) );
00785         common->moveByFrames( count * _getOneSecond() );
00786         cmd[ 0 ] = 0;
00787     }
00788 
00789     /* backspace one second */
00790 
00791     else if ( ( strcmp( real, "b" ) == 0 ) || ( strcmp( real, "B" ) == 0 ) )
00792     {
00793         common->keyboardFeedback( cmd, _( "Move backwards one second" ) );
00794         common->moveByFrames( 0 - count * _getOneSecond() );
00795         cmd[ 0 ] = 0;
00796     }
00797 
00798     /* start of scene */
00799 
00800     else if ( ( strcmp( cmd, "0" ) == 0 ) || ( strcmp( real, "^" ) == 0 ) )
00801     {
00802         common->videoStartOfScene( );
00803         for ( ; count > 1 && common->g_currentFrame > 0; count -- )
00804         {
00805             common->g_currentFrame --;
00806             common->videoStartOfScene( );
00807         }
00808         common->keyboardFeedback( cmd, _( "Move to start of scene" ) );
00809         cmd[ 0 ] = 0;
00810     }
00811 
00812     /* end of scene */
00813 
00814     else if ( strcmp( real, "$" ) == 0 )
00815     {
00816         common->videoEndOfScene( );
00817         for ( ; count > 1 && common->g_currentFrame < common->getPlayList() ->GetNumFrames() - 1; count -- )
00818         {
00819             common->g_currentFrame ++;
00820             common->videoEndOfScene( );
00821         }
00822         common->keyboardFeedback( cmd, _( "Move to end of scene" ) );
00823         cmd[ 0 ] = 0;
00824     }
00825 
00826     /* start of next scene */
00827 
00828     else if ( ( strcmp( real, "j" ) == 0 ) || strcmp( real, "+" ) == 0 )
00829     {
00830         for ( ; count >= 1 && common->g_currentFrame < common->getPlayList() ->GetNumFrames() - 1; count -- )
00831             common->videoNextScene( );
00832         common->keyboardFeedback( cmd, _( "Move to start of next scene" ) );
00833         cmd[ 0 ] = 0;
00834     }
00835 
00836     /* start of previous scene */
00837 
00838     else if ( ( strcmp( real, "k" ) == 0 ) || ( strcmp( real, "-" ) == 0 ) )
00839     {
00840         for ( ; count >= 1 && common->g_currentFrame > 0; count -- )
00841             common->videoPreviousScene( );
00842         common->keyboardFeedback( cmd, _( "Move to start of previous scene" ) );
00843         cmd[ 0 ] = 0;
00844     }
00845 
00846     /* first frame */
00847 
00848     else if ( strcmp( cmd, "gg" ) == 0 )
00849     {
00850         common->videoStartOfMovie( );
00851         common->keyboardFeedback( cmd, _( "Move to first frame" ) );
00852         cmd[ 0 ] = 0;
00853     }
00854 
00855     /* last frame */
00856 
00857     else if ( strcmp( cmd, "G" ) == 0 )
00858     {
00859         common->videoEndOfMovie( );
00860         common->keyboardFeedback( cmd, _( "Move to last frame" ) );
00861         cmd[ 0 ] = 0;
00862     }
00863 
00864     /* delete current frame */
00865 
00866     else if ( ( strcmp( real, "x" ) == 0 ) || ( strcmp( cmd, "d " ) == 0 ) || ( strcmp( real, "dl" ) == 0 ) )
00867     {
00868         CopyFrames( common->g_currentFrame, common->g_currentFrame + count - 1 );
00869         DeleteFrames( common->g_currentFrame, common->g_currentFrame + count - 1 );
00870         common->moveToFrame( );
00871         common->keyboardFeedback( cmd, _( "Cut current frame" ) );
00872         DrawBar( common->g_currentFrame );
00873         cmd[ 0 ] = 0;
00874     }
00875 
00876     /* delete one second */
00877 
00878     else if ( strcmp( cmd, "dw" ) == 0 )
00879     {
00880         end = common->g_currentFrame + _getOneSecond() - 1;
00881         CopyFrames( common->g_currentFrame, end );
00882         DeleteFrames( common->g_currentFrame, end );
00883         common->moveToFrame( );
00884         common->keyboardFeedback( cmd, _( "Cut one second" ) );
00885         DrawBar( common->g_currentFrame );
00886         cmd[ 0 ] = 0;
00887     }
00888 
00889     /* delete current scene */
00890 
00891     else if ( strcmp( real, "dd" ) == 0 )
00892     {
00893         start = common->getPlayList() ->FindStartOfScene( common->g_currentFrame );
00894         end = start;
00895         for ( ; count >= 1 && end <= common->getPlayList() ->GetNumFrames() - 1; count -- )
00896         {
00897             end = common->getPlayList() ->FindEndOfScene( end );
00898             end ++;
00899         }
00900         CopyFrames( start, end - 1 );
00901         DeleteFrames( start, end - 1 );
00902         common->moveToFrame( start );
00903         common->keyboardFeedback( cmd, _( "Cut current scene" ) );
00904         DrawBar( common->g_currentFrame );
00905         cmd[ 0 ] = 0;
00906     }
00907 
00908     /* delete from current frame up to end of scene */
00909 
00910     else if ( ( strcmp( cmd, "o" ) == 0 ) || strcmp( cmd, "d$" ) == 0 )
00911     {
00912         start = common->g_currentFrame;
00913         if ( strcmp( cmd, "o" ) == 0 )
00914             ++start;
00915         end = common->getPlayList() ->FindEndOfScene( common->g_currentFrame );
00916         CopyFrames( start, end );
00917         DeleteFrames( start, end );
00918         common->moveToFrame( );
00919         common->keyboardFeedback( cmd, _( "Cut to end of scene" ) );
00920         DrawBar( common->g_currentFrame );
00921         cmd[ 0 ] = 0;
00922     }
00923 
00924     /* delete from current frame up to end of file */
00925 
00926     else if ( strcmp( cmd, "dG" ) == 0 )
00927     {
00928         end = common->getPlayList() ->GetNumFrames();
00929         CopyFrames( common->g_currentFrame, end );
00930         DeleteFrames( common->g_currentFrame, end );
00931         common->moveByFrames( -1 );
00932         common->keyboardFeedback( cmd, _( "Cut to end of movie" ) );
00933         DrawBar( common->g_currentFrame );
00934         cmd[ 0 ] = 0;
00935     }
00936 
00937     /* delete from start of scene just before current frame */
00938 
00939     else if ( ( strcmp( cmd, "i" ) == 0 ) || ( strcmp( cmd, "d0" ) == 0 ) || strcmp( cmd, "d^" ) == 0 )
00940     {
00941         start = common->getPlayList() ->FindStartOfScene( common->g_currentFrame );
00942         if ( start < common->g_currentFrame )
00943         {
00944             CopyFrames( start, common->g_currentFrame - 1 );
00945             DeleteFrames( start, common->g_currentFrame - 1 );
00946             common->moveToFrame( start );
00947         }
00948         common->keyboardFeedback( cmd, _( "Cut from start of scene" ) );
00949         DrawBar( common->g_currentFrame );
00950         cmd[ 0 ] = 0;
00951     }
00952 
00953     /* delete from start of file just before current frame */
00954 
00955     else if ( strcmp( cmd, "dgg" ) == 0 )
00956     {
00957         CopyFrames( 0, common->g_currentFrame - 1 );
00958         DeleteFrames( 0, common->g_currentFrame - 1 );
00959         common->moveToFrame( 0 );
00960         common->keyboardFeedback( cmd, _( "Cut from start of movie" ) );
00961         DrawBar( common->g_currentFrame );
00962         cmd[ 0 ] = 0;
00963     }
00964 
00965     /* copy current frame */
00966 
00967     else if ( ( strcmp( cmd, "y " ) == 0 ) || ( strcmp( real, "yl" ) == 0 ) )
00968     {
00969         CopyFrames( common->g_currentFrame, common->g_currentFrame + count - 1 );
00970         common->keyboardFeedback( cmd, _( "Copy current frame" ) );
00971         cmd[ 0 ] = 0;
00972     }
00973 
00974     /* copy current scene */
00975 
00976     else if ( ( strcmp( real, "yy" ) == 0 ) || ( strcmp( real, "Y" ) == 0 ) )
00977     {
00978         start = common->getPlayList() ->FindStartOfScene( common->g_currentFrame );
00979         end = start;
00980         for ( ; count >= 1; count -- )
00981         {
00982             end = common->getPlayList() ->FindEndOfScene( end );
00983             end ++;
00984         }
00985         CopyFrames( start, end - 1 );
00986         common->keyboardFeedback( cmd, _( "Copy current scene" ) );
00987         cmd[ 0 ] = 0;
00988     }
00989 
00990     /* copy from current frame up to end of scene */
00991 
00992     else if ( strcmp( cmd, "y$" ) == 0 )
00993     {
00994         end = common->getPlayList() ->FindEndOfScene( common->g_currentFrame );
00995         CopyFrames( common->g_currentFrame, end );
00996         common->keyboardFeedback( cmd, _( "Copy to end of scene" ) );
00997         cmd[ 0 ] = 0;
00998     }
00999 
01000     /* copy from start of scene just before current frame */
01001 
01002     else if ( ( strcmp( cmd, "y0" ) == 0 ) || strcmp( cmd, "y^" ) == 0 )
01003     {
01004         start = common->getPlayList() ->FindStartOfScene( common->g_currentFrame );
01005         if ( start < common->g_currentFrame )
01006         {
01007             CopyFrames( start, common->g_currentFrame - 1 );
01008             common->moveToFrame( start );
01009         }
01010         common->keyboardFeedback( cmd, _( "Copy from start of scene" ) );
01011         cmd[ 0 ] = 0;
01012     }
01013 
01014     /* paste after current frame */
01015 
01016     else if ( strcmp( real, "p" ) == 0 )
01017     {
01018         start = common->g_currentFrame;
01019         for ( ; count >= 1; count -- )
01020             PasteFrames( common->g_currentFrame + 1 );
01021         common->moveToFrame( start + 1 );
01022         common->keyboardFeedback( cmd, _( "Paste after current frame" ) );
01023         DrawBar( common->g_currentFrame );
01024         cmd[ 0 ] = 0;
01025     }
01026 
01027     /* paste before current frame */
01028 
01029     else if ( strcmp( real, "P" ) == 0 )
01030     {
01031         for ( ; count >= 1; count -- )
01032             PasteFrames( common->g_currentFrame );
01033         end = common->getPlayList() ->FindEndOfScene( common->g_currentFrame + 1 );
01034         common->moveToFrame( );
01035         common->keyboardFeedback( cmd, _( "Paste before current frame" ) );
01036         DrawBar( common->g_currentFrame );
01037         cmd[ 0 ] = 0;
01038     }
01039 
01040     /* Switch to capture mode */
01041 
01042     else if ( strcmp( cmd, "a" ) == 0 )
01043     {
01044         common->keyboardFeedback( cmd, "Capture, insert after frame" );
01045         end = common->getPlayList() ->FindEndOfScene( common->g_currentFrame );
01046         common->moveToFrame( end );
01047         FileTracker::GetInstance().SetMode( CAPTURE_FRAME_APPEND );
01048         common->changePageRequest( PAGE_CAPTURE );
01049         cmd[ 0 ] = 0;
01050     }
01051 
01052     else if ( strcmp( cmd, "A" ) == 0 )
01053     {
01054         common->keyboardFeedback( cmd, _( "Capture, append to movie" ) );
01055         end = common->getPlayList() ->GetNumFrames();
01056         common->moveToFrame( end );
01057         FileTracker::GetInstance().SetMode( CAPTURE_MOVIE_APPEND );
01058         common->changePageRequest( PAGE_CAPTURE );
01059         cmd[ 0 ] = 0;
01060     }
01061 
01062     else if ( strcmp( cmd, "t" ) == 0 )
01063     {
01064         common->keyboardFeedback( cmd, _( "Trim" ) );
01065         common->changePageRequest( PAGE_TRIM );
01066         cmd[ 0 ] = 0;
01067     }
01068 
01069     else if ( strcmp( cmd, "v" ) == 0 )
01070     {
01071         common->keyboardFeedback( cmd, _( "Timeline" ) );
01072         common->changePageRequest( PAGE_TIMELINE );
01073         cmd[ 0 ] = 0;
01074     }
01075 
01076     else if ( strcmp( cmd, "C" ) == 0 )
01077     {
01078         common->keyboardFeedback( cmd, _( "FX" ) );
01079         common->changePageRequest( PAGE_MAGICK );
01080         cmd[ 0 ] = 0;
01081     }
01082 
01083     else if ( strcmp( cmd, "u" ) == 0 )
01084     {
01085         GetEditorBackup() ->Undo( common->getPlayList() );
01086         common->keyboardFeedback( cmd, _( "Undo" ) );
01087         common->hasListChanged = TRUE;
01088         DrawBar( common->g_currentFrame );
01089         common->moveToFrame( );
01090         cmd[ 0 ] = 0;
01091     }
01092 
01093     else if ( strcmp( cmd, "Ctrl+R" ) == 0 )
01094     {
01095         GetEditorBackup() ->Redo( common->getPlayList() );
01096         common->keyboardFeedback( cmd, _( "Redo" ) );
01097         common->hasListChanged = TRUE;
01098         DrawBar( common->g_currentFrame );
01099         common->moveToFrame( );
01100         cmd[ 0 ] = 0;
01101     }
01102 
01103     else if ( strcmp( real, "J" ) == 0 )
01104     {
01105         common->keyboardFeedback( cmd, _( "Join scenes" ) );
01106         for ( ; count >= 1 && common->getPlayList() ->JoinScenesAt( common->g_currentFrame ); count -- )
01107             common->hasListChanged = TRUE;
01108         if ( common->hasListChanged == TRUE )
01109         {
01110             common->moveToFrame();
01111             DrawBar( common->g_currentFrame );
01112             GetEditorBackup() ->Store( common->getPlayList() );
01113             cmd[ 0 ] = 0;
01114         }
01115     }
01116 
01117     /* read AVI or PlayList */
01118 
01119     else if ( strcmp( cmd, ":r" ) == 0 )
01120     {
01121         common->keyboardFeedback( cmd, _( "Insert file" ) );
01122         common->insertFile( );
01123         cmd[ 0 ] = 0;
01124     }
01125 
01126     else if ( strcmp( cmd, ":a" ) == 0 )
01127     {
01128         common->keyboardFeedback( cmd, _( "Append file to scene" ) );
01129         int end = common->getPlayList() ->FindEndOfScene( common->g_currentFrame );
01130         common->moveToFrame( end );
01131         common->appendFile( );
01132         cmd[ 0 ] = 0;
01133     }
01134 
01135     else if ( strcmp( cmd, ":A" ) == 0 )
01136     {
01137         common->keyboardFeedback( cmd, _( "Append file to movie" ) );
01138         int end = common->getPlayList() ->GetNumFrames();
01139         common->moveToFrame( end );
01140         common->appendFile( );
01141         cmd[ 0 ] = 0;
01142     }
01143 
01144     /* switch to export mode */
01145 
01146     else if ( strcmp( cmd, ":W" ) == 0 )
01147     {
01148         common->keyboardFeedback( cmd, _( "Export" ) );
01149         common->changePageRequest( PAGE_EXPORT );
01150         cmd[ 0 ] = 0;
01151     }
01152 
01153     /* write PlayList */
01154 
01155     else if ( strcmp( cmd, ":w" ) == 0 )
01156     {
01157         common->keyboardFeedback( cmd, _( "Write playlist" ) );
01158         common->savePlayList( );
01159         cmd[ 0 ] = 0;
01160     }
01161 
01162     /* quit */
01163 
01164     else if ( strcmp( cmd, ":q" ) == 0 )
01165     {
01166         common->keyboardFeedback( cmd, _( "quit" ) );
01167         kinoDeactivate();
01168         cmd[ 0 ] = 0;
01169     }
01170 
01171     /* split scene */
01172 
01173     else if ( strcmp( cmd, "Ctrl+J" ) == 0 )
01174     {
01175         common->keyboardFeedback( cmd, _( "Split scene before frame" ) );
01176         if ( common->getPlayList() ->SplitSceneBefore( common->g_currentFrame ) )
01177         {
01178             common->hasListChanged = TRUE;
01179             common->moveToFrame();
01180             DrawBar( common->g_currentFrame );
01181             GetEditorBackup() ->Store( common->getPlayList() );
01182             cmd[ 0 ] = 0;
01183         }
01184     }
01185 
01186     /* goto a frame */
01187     else if ( strncmp( cmd, ":", 1 ) == 0 )
01188     {
01189         int val = 0;
01190         char t[ 132 ] = "";
01191         if ( sscanf( cmd + 1, "%d", &val ) == 1 )
01192         {
01193             common->moveToFrame( val );
01194             sprintf( t, _( "Move to frame %d" ), val );
01195             common->keyboardFeedback( cmd, t );
01196         }
01197         else
01198             common->setStatusBar( cmd );
01199     }
01200 
01201     else
01202     {
01203         // Check for invalid commands
01204         if ( strlen( real ) > 5 )
01205             cmd[ 0 ] = 0;
01206         else if ( strchr( "dgy ", real[ strlen( real ) - 1 ] ) == NULL )
01207             cmd[ 0 ] = 0;
01208 
01209         common->keyboardFeedback( cmd, "" );
01210 
01211     }
01212 
01213     common->setWindowTitle( );
01214 
01215     return FALSE;
01216 }
01217 
01224 void PageEditor::CopyFrames( int first, int last )
01225 {
01226     PlayList * playList = new PlayList;
01227 
01228     // Delete the old list
01229     delete g_copiedPlayList;
01230     // Create the one requested
01231     common->getPlayList() ->GetPlayList( first, last, *playList );
01232     g_copiedPlayList = playList;
01233     playList->SetDocName( "" );
01234     playList->SetDirty( true );
01235 }
01236 
01237 
01243 void PageEditor::PasteFrames( int before )
01244 {
01245     PlayList temp( *g_copiedPlayList );
01246 
01247     if ( common->getPlayList() ->InsertPlayList( temp, before ) )
01248     {
01249         common->hasListChanged = TRUE;
01250         GetEditorBackup() ->Store( common->getPlayList() );
01251     }
01252     common->setWindowTitle( );
01253 }
01254 
01261 void PageEditor::DeleteFrames( int first, int last )
01262 {
01263     int before, after;
01264 
01265     before = common->getPlayList() ->GetNumFrames();
01266     if ( common->getPlayList() ->Delete( first, last ) )
01267     {
01268         after = common->getPlayList() ->GetNumFrames();
01269         common->hasListChanged = TRUE;
01270         GetEditorBackup() ->Store( common->getPlayList() );
01271     }
01272     common->setWindowTitle( );
01273 }
01274 
01275 void PageEditor::showFrame( int position, Frame& frame )
01276 {
01277     gdk_threads_enter();
01278     if ( common->getPlayList() ->GetNumFrames() == 0 )
01279     {
01280         common->loadSplash( frameArea );
01281     }
01282     else
01283     {
01284         DrawBar( position );
01285         getFrameDisplayer() ->Put( frame, GTK_WIDGET( frameArea ), TRUE );
01286         showFrameInfo( position, frame );
01287         common->g_currentFrame = position;
01288     }
01289     gdk_flush();
01290     if ( position >= ( common->getPlayList()->GetNumFrames() - 1 ) ||
01291         ( position <= 0 && ( g_nav_ctl.step < 0 || g_nav_ctl.rate < 0 ) ) )
01292     {
01293         common->videoStop();
01294     }
01295     gdk_threads_leave();
01296 }
01297 
01298 
01299 void PageEditor::windowMoved()
01300 {
01301     if ( g_nav_ctl.active == FALSE )
01302     {
01303         if ( common->getPlayList() ->GetNumFrames() )
01304         {
01305             showFrame( common->g_currentFrame, TRUE );
01306         }
01307         else
01308         {
01309             common->loadSplash( frameArea );
01310         }
01311     }
01312 }
01313 
01314 
01315 void PageEditor::showFrameInfo( int i )
01316 {
01317     if ( common->g_currentFrame == -1 )
01318     {
01319         gtk_label_set_text( positionLabelCurrent, "" );
01320         gtk_label_set_text( positionLabelTotal, "" );
01321         return ;
01322     }
01323 
01324     Frame *frame = GetFramePool() ->GetFrame();
01325     common->getPlayList() ->GetFrame( i, *frame );
01326     showFrameInfo( i, *frame );
01327     GetFramePool() ->DoneWithFrame( frame );
01328 }
01329 
01330 void PageEditor::showFrameInfo( int i, Frame &frame )
01331 {
01332     FileHandler * media;
01333     int total = common->getPlayList() ->GetNumFrames();
01334 
01335     common->getPlayList() ->GetMediaObject( i, &media );
01336     common->showFrameMoreInfo( frame, media );
01337 
01338     common->getTime().setFramerate( frame.GetFrameRate() );
01339     string tc = "<span size=\"x-large\">" + common->getTime().parseFramesToString( i, common->getTimeFormat() ) + "</span>";
01340     gtk_label_set_markup( positionLabelCurrent, tc.c_str() );
01341     gtk_widget_set_redraw_on_allocate( GTK_WIDGET( positionLabelCurrent ), FALSE );
01342     tc = _("Duration: ") + common->getTime().parseFramesToString( total, common->getTimeFormat() );
01343     gtk_label_set_markup( positionLabelTotal, tc.c_str() );
01344     common->setCurrentScene( i );
01345 }
01346 
01347 void PageEditor::DrawBar( int currentFrame )
01348 {
01349     if ( common->hasListChanged == TRUE )
01350     {
01351         ResetBar();
01352         common->hasListChanged = FALSE;
01353     }
01354     if ( currentFrame > -1 )
01355         gtk_adjustment_set_value( scrubAdjustment, ( gfloat ) currentFrame );
01356 }
01357 
01358 void PageEditor::ResetBar()
01359 {
01360     int frameNum = 0, lastFrame = 0;
01361 
01362     sceneStartList.erase( sceneStartList.begin(), sceneStartList.end() );
01363 
01364     if ( sceneIndex != NULL )
01365         g_array_free( sceneIndex, TRUE );
01366     sceneIndex = g_array_new( FALSE, FALSE, sizeof( int ) );
01367     g_array_set_size( sceneIndex, 0 );
01368 
01369     while ( frameNum < common->getPlayList() ->GetNumFrames() )
01370     {
01371         lastFrame = frameNum = common->getPlayList() ->FindEndOfScene( frameNum );
01372         frameNum++;
01373         g_array_append_val( sceneIndex, frameNum );
01374         sceneStartList.insert( sceneStartList.end(), frameNum );
01375     }
01376     GetStoryboard() ->reset();
01377     GetStoryboard() ->redraw();
01378     frameNum = common->getPlayList() ->GetNumFrames() - 1;
01379     if ( frameNum < 0 )
01380         frameNum = 0;
01381     scrubAdjustment->upper = frameNum;
01382     g_signal_emit_by_name( scrubAdjustment, "changed" );
01383     gtk_enhanced_scale_set_breaks( scrubBar, sceneIndex );
01384 }
01385 
01386 vector <int> PageEditor::GetScene()
01387 {
01388     return sceneStartList;
01389 }
01390 
01391 void PageEditor::snapshot()
01392 {
01393     GetEditorBackup() ->Store( common->getPlayList() );
01394     common->setWindowTitle( );
01395 }
01396 
01397 extern "C"
01398 {
01399 
01400     // Share the frames extracted from the audio and video thread - this
01401     // provides a smoother playback and is less intensive on the CPU. The
01402     // code assumes the video will never fall more than PLAYBACK_FRAMES/2
01403     // behind the audio.
01404     //
01405     // The read thread is responsible for write access to the queues of
01406     // frameNumber and frameContent.
01407 
01408     static int frameNumber[ PLAYBACK_FRAMES ];
01409     static int pending = 0;
01410     static int head = -1;
01411     static int tail = -1;
01412     static bool playing = false;
01413     static bool showing = false;
01414 
01415     static void resetThreads( )
01416     {
01417         playing = false;
01418         showing = false;
01419         pending = 0;
01420         head = 0;
01421         tail = 0;
01422     }
01423 
01433     static void *readThread( void * info )
01434     {
01435         struct navigate_control * ctl = ( struct navigate_control * ) info;
01436         newFrame = 0;
01437         lastFrame = common->g_currentFrame - 1;
01438         gint totalFrames = common->getPlayList() ->GetNumFrames();
01439         gint countFrames = 0;
01440         static Preferences &prefs = Preferences::getInstance();
01441         int time_per_frame = 1000000 / _getOneSecond( );
01442 
01443         // cerr << ">>> Starting read thread " << endl;
01444 
01445         // Get start of time
01446         struct timeval start;
01447         struct timeval end;
01448         gettimeofday( &start, NULL );
01449 
01450         // Loop while active
01451         while ( ctl->active )
01452         {
01453             // Calculate time for next frame
01454             start.tv_usec += time_per_frame;
01455             if ( start.tv_usec >= 1000000 )
01456             {
01457                 start.tv_usec -= 1000000;
01458                 start.tv_sec ++;
01459             }
01460 
01461             pthread_mutex_lock( &readlock );
01462             // Determine the frame to render
01463             newFrame = lastFrame + ctl->step;
01464 
01465             // determine new frame based upon jogshuttle rate
01466             if ( ctl->step == 0 )
01467             {
01468                 ctl->subframe++;
01469                 if ( ctl->rate < 0 )
01470                 {
01471                     if ( ctl->subframe >= -ctl->rate )
01472                     {
01473                         newFrame --;
01474                         ctl->subframe = 0;
01475                     }
01476                 }
01477                 else
01478                 {
01479                     if ( ctl->subframe >= ctl->rate )
01480                     {
01481                         newFrame ++;
01482                         ctl->subframe = 0;
01483                     }
01484                 }
01485             }
01486             pthread_mutex_unlock( &readlock );
01487 
01488             // Check the bounds and adjust as necessary
01489             if ( newFrame < 0 )
01490                 newFrame = 0;
01491             else if ( newFrame >= totalFrames )
01492                 newFrame = totalFrames - 1;
01493 
01494             // Determine which locations in frameNumber and frameContent we need to use
01495             if ( pending >= PLAYBACK_FRAMES - 10 )
01496             {
01497                 // Queue is full.. do nothing
01498                 playing = true;
01499                 struct timespec t = { 0, 0 };
01500                 nanosleep( &t, NULL );
01501             }
01502             else
01503             {
01504                 frameNumber[ head ] = newFrame;
01505                 common->getPlayList() ->GetFrame( frameNumber[ head ], *frameContent[ head ] );
01506                 if ( writer1394 != NULL )
01507                     writer1394->SendFrame( *frameContent[ head ], false );
01508                 
01509                 pthread_mutex_lock( &threadlock );
01510                 ++pending;
01511                 head = ( head + 1 ) % PLAYBACK_FRAMES;
01512                 pthread_mutex_unlock( &threadlock );
01513 
01514                 // We have a frame, so start playing
01515                 playing = true;
01516 
01517                 // Render all frames if requested
01518                 if ( ( ! prefs.dropFrame || ! prefs.enableAudio ) && ctl->active )
01519                 {
01520                     if ( prefs.enableAudio && ( frameNumber[ tail ] != lastFrame || ctl->rate > 1 || ctl->rate < -1 ) )
01521                         common->getPageEditor() ->getFrameDisplayer() ->PutSound( *frameContent[ tail ] );
01522                     common->getPageEditor() ->showFrame( frameNumber[ tail ], *frameContent[ tail ] );
01523                     tail = ( tail + 1 ) % PLAYBACK_FRAMES;
01524                     --pending;
01525 
01526                     // Determine how far from the next frame we really are
01527                     gettimeofday( &end, NULL );
01528                     int difference = ( ( start.tv_sec * 1000000 + start.tv_usec ) - ( end.tv_sec * 1000000 + end.tv_usec ) );
01529 
01530                     if ( difference > 2000 && difference < time_per_frame )
01531                     {
01532                         // Sleep for half the remaining time when audio is disabled
01533                         if ( ! prefs.enableAudio )
01534                         {
01535                             struct timespec t =
01536                                 {
01537                                     0, difference * 500
01538                                 };
01539                             nanosleep( &t, NULL );
01540                         }
01541                     }
01542                     else if ( difference < 0 || difference >= time_per_frame )
01543                     {
01544                         gettimeofday( &start, NULL );
01545                     }
01546                 }
01547 
01548                 // update the lastFrame and lastPos variables
01549                 lastFrame = newFrame;
01550 
01551                 // Incrment the frame count
01552                 countFrames ++;
01553             }
01554         }
01555         // cerr << ">>> Ending read thread " << countFrames << endl;
01556 
01557         return NULL;
01558     }
01559 
01560     static void *audioThread( void * info )
01561     {
01562 
01563         static Preferences & prefs = Preferences::getInstance();
01564         struct navigate_control *ctl = ( struct navigate_control * ) info;
01565         int lastFrame = common->g_currentFrame - 1;
01566         int time_per_frame = 1000000 / _getOneSecond( );
01567 
01568         // cerr << ">>> Starting audio thread" << endl;
01569 
01570         while ( ctl->active )
01571         {
01572             // Only do this when drop frames is active (otherwise the audio thread takes care of it)
01573             if ( prefs.dropFrame && prefs.enableAudio )
01574             {
01575                 // As long as its different to the previous one, then display it
01576                 if ( playing && pending > 0 )
01577                 {
01578                     // Play the audio
01579                     if ( prefs.enableAudio && ( frameNumber[ tail ] != lastFrame || ctl->rate > 1 || ctl->rate < -1 ) )
01580                     {
01581                         common->getPageEditor() ->getFrameDisplayer() ->PutSound( *frameContent[ tail ] );
01582                         if ( pending < 10 )
01583                         {
01584                             struct timespec t = { 0, 0 };
01585                             nanosleep( &t, NULL );
01586                         }
01587                     }
01588                     else if ( ctl->step == 0 && !prefs.audioScrub )
01589                     {
01590                         struct timespec t =
01591                             {
01592                                 0, time_per_frame * 1000
01593                             };
01594                         nanosleep( &t, NULL );
01595                     }
01596 
01597                     // Last encountered audio frame
01598                     lastFrame = frameNumber[ tail ];
01599 
01600                     // Move the tail
01601                     pthread_mutex_lock( &threadlock );
01602                     --pending;
01603                     tail = ( tail + 1 ) % PLAYBACK_FRAMES;;
01604                     pthread_mutex_unlock( &threadlock );
01605 
01606                     // Start showing frames from this point onwards
01607                     showing = true;
01608                 }
01609                 else
01610                 {
01611                     playing = false;
01612                     struct timespec t = { 0, 0 };
01613                     nanosleep( &t, NULL );
01614                 }
01615             }
01616             else
01617             {
01618                 // It is safe to cancel the audio thread here since a change to prefs necessitates a restart.
01619                 // cerr << ">>> Audio Thread not needed" << endl;
01620                 return NULL;
01621             }
01622         }
01623         // cerr << ">>> Ending audio thread" << endl;
01624 
01625         return NULL;
01626     }
01627 
01628     static void *videoThread( void * info )
01629     {
01630 
01631         static Preferences & prefs = Preferences::getInstance();
01632         struct navigate_control *ctl = ( struct navigate_control * ) info;
01633         int lastFrame = common->g_currentFrame - 1;
01634 
01635 #ifdef PLAY_WITH_STATS
01636         // Statistical analysis variables
01637         int dropped = 0;
01638         int count = 0;
01639 #endif
01640 
01641         // cerr << ">>> Starting video thread" << endl;
01642         while ( ctl->active )
01643         {
01644             // Only do this when drop frames is active (otherwise the audio thread takes care of it)
01645             if ( prefs.dropFrame && prefs.enableAudio )
01646             {
01647                 if ( showing && pending > 0 && ctl->active )
01648                 {
01649                     // Store the current tail
01650                     int my_tail = tail;
01651 
01652                     // As long as its different to the previous one, then display it
01653                     if ( frameNumber[ my_tail ] != lastFrame || ctl->rate > 1 )
01654                     {
01655 #ifdef PLAY_WITH_STATS
01656                         // Statistical analysis of frame playback (useful for limited kinds of tests)
01657                         if ( ctl->step == 1 )
01658                         {
01659                             int skipped = frameNumber[ my_tail ] - lastFrame - 1;
01660                             count += skipped + 1;
01661                             if ( skipped != 0 && lastFrame != 0 && count != 0 )
01662                             {
01663                                 dropped += skipped;
01664                                 cerr << ">>>> Dropped " << dropped << " in " << count << " frames - " << ( double ) ( ( ( double ) dropped / ( double ) count ) * 100.0 ) << "%" << endl;
01665                             }
01666                             lastFrame = frameNumber[ my_tail ];
01667                         }
01668 #endif
01669                         // Show this frame
01670                         common->getPageEditor() ->showFrame( frameNumber[ my_tail ], *frameContent[ my_tail ] );
01671                     }
01672                 }
01673                 struct timespec t = { 0, 0 };
01674                 nanosleep( &t, NULL );
01675             }
01676             else
01677             {
01678                 // It is safe to cancel the video thread here since a change to prefs necessitates a restart.
01679                 // cerr << ">>> Video Thread not needed" << endl;
01680                 return NULL;
01681             }
01682         }
01683 
01684 #ifdef PLAY_WITH_STATS
01685         cerr << ">>>> Video stopped: Dropped " << dropped << " in " << count << " frames - " << ( double ) ( ( ( double ) dropped / ( double ) count ) * 100.0 ) << "%" << endl;
01686 #endif
01687         // cerr << ">>> Ending video thread" << endl;
01688 
01689         return NULL;
01690     }
01691 
01692     static int _getOneSecond( void )
01693     {
01694         Frame & frame = *( GetFramePool() ->GetFrame( ) );
01695         common->getPlayList() ->GetFrame( common->g_currentFrame, frame );
01696         int value = ( frame.IsPAL() ? 25 : 30 );
01697         GetFramePool( ) ->DoneWithFrame( &frame );
01698         return value;
01699     }
01700 
01701 }

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