001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.video;
031
032import java.awt.Color;
033import java.awt.Dimension;
034import java.awt.Graphics;
035import java.awt.GridBagConstraints;
036import java.awt.GridBagLayout;
037import java.awt.Insets;
038import java.awt.event.MouseAdapter;
039import java.awt.event.MouseEvent;
040import java.awt.image.BufferedImage;
041import java.io.IOException;
042import java.lang.reflect.InvocationTargetException;
043import java.lang.reflect.Method;
044import java.util.ArrayList;
045import java.util.HashMap;
046import java.util.Map;
047
048import javax.imageio.ImageIO;
049import javax.swing.BorderFactory;
050import javax.swing.ImageIcon;
051import javax.swing.JFrame;
052import javax.swing.JLabel;
053import javax.swing.JPanel;
054import javax.swing.JProgressBar;
055
056import org.openimaj.audio.AudioStream;
057import org.openimaj.content.animation.animator.LinearTimeBasedIntegerValueAnimator;
058import org.openimaj.image.DisplayUtilities.ImageComponent;
059import org.openimaj.image.Image;
060import org.openimaj.video.timecode.HrsMinSecFrameTimecode;
061
062/**
063 *      This class is an extension of the {@link VideoDisplay} class that provides
064 *      GUI elements for starting, stopping, pausing and rewinding video. 
065 *      <p>
066 *      The class relies on the underlying {@link VideoDisplay} to actually provide 
067 *      the main functionality for video playing and indeed still allows its
068 *      methods to be used. This class then provides a simple API for starting,
069 *      pausing and stopping video.
070 *      <p>
071 *      Unlike {@link VideoDisplay}, the VideoPlayer class does not create a frame
072 *      when the {@link #createVideoPlayer(Video)} methods are called. Use the
073 *      {@link #showFrame()} method to produce a visible frame. 
074 * 
075 *      @author David Dupplaw (dpd@ecs.soton.ac.uk)
076 *      @created 10 Aug 2012
077 *      @version $Author$, $Revision$, $Date$
078 *      @param <T> The type of the video frame
079 */
080public class VideoPlayer<T extends Image<?, T>> extends VideoDisplay<T>
081        implements VideoDisplayStateListener
082{
083        /**
084         *      The video player components encapsulates the buttons and their
085         *      functionalities, as well as animating buttons, etc.
086         * 
087         *      @author David Dupplaw (dpd@ecs.soton.ac.uk)
088         *      @created 10 Aug 2012
089         *      @version $Author$, $Revision$, $Date$
090         */
091        protected class VideoPlayerComponent extends JPanel
092        {
093                /** */
094                private static final long serialVersionUID = 1L;
095
096                /**
097                 *      This class represents the widgets in the video player
098                 * 
099                 *      @author David Dupplaw (dpd@ecs.soton.ac.uk)
100                 *      @created 10 Aug 2012
101                 *      @version $Author$, $Revision$, $Date$
102                 */
103                protected class ButtonsPanel extends JPanel implements VideoDisplayListener<T>
104                {
105                        /** */
106                        private static final long serialVersionUID = 1L;
107
108                        /* The graphic for the play button */
109                        private final static String PLAY = "/play.png";
110                        private final static String STOP = "/stop.png";
111                        private final static String PAUSE = "/pause.png";
112                        private final static String STEP_BACK = "/step-backward.png";
113                        private final static String STEP_FORWARD = "/step-forward.png";
114                        
115                        /** A map that makes it easier to replace buttons */
116                        private final Map<String,String> buttonsMap = new HashMap<String,String>();
117                        
118                        /** The default list of buttons in order of their display */
119                        private String[] buttons = null;
120                        
121                        /** The methods to use for each of the buttons */
122                        private Method[] methods = null;
123                        
124                        /** Insets */
125                        private final int inset = 2;
126                        
127                        /** Progress bar */
128                        private final JProgressBar progress = new JProgressBar( 0 , 100 );
129                        
130                        /** The background image */
131                        private BufferedImage img = null;
132                        
133                        /** Label showing the current position */
134                        private final JLabel label = new JLabel("0:00:00/0:00:00");
135                        
136                        /**
137                         *      Construct a new buttons panel
138                         */
139                        public ButtonsPanel()
140                        {
141                                // We will only allow these methods to be called
142                                this.buttonsMap.put( "play", ButtonsPanel.PLAY );
143                                this.buttonsMap.put( "stop", ButtonsPanel.STOP );
144                                this.buttonsMap.put( "pause", ButtonsPanel.PAUSE );
145                                this.buttonsMap.put( "stepBack", ButtonsPanel.STEP_BACK );
146                                this.buttonsMap.put( "stepForward", ButtonsPanel.STEP_FORWARD );
147
148                                try
149                                {
150                                        this.img = ImageIO.read( this.getClass().getResource( 
151                                                        "/brushed-metal.png" ) );
152                                }
153                                catch( final IOException e )
154                                {
155                                        e.printStackTrace();
156                                }
157                                
158                                // Set up the methods list (calls init())
159                                this.setButtons( new String[]{"pause", "play", "stop"} );
160                                
161                                this.setPreferredSize( new Dimension( 
162                                                (100+this.inset)*this.buttons.length, 
163                                                100+this.inset ) );
164                                this.setSize( this.getPreferredSize() );
165                                
166                                VideoPlayer.this.addVideoListener( this );
167
168                        }
169                        
170                        /**
171                         *      Set the list of buttons available on the player. The array
172                         *      of strings should match the names of methods in the {@link VideoPlayer}
173                         *      class for navigating the video. That is {@link VideoPlayer#pause()},
174                         *      {@link VideoPlayer#stop()}, {@link VideoPlayer#play()}, 
175                         *      {@link VideoPlayer#stepBack()} or {@link VideoPlayer#stepForward()}.
176                         *      The order specifies the order they will be shown in the player.
177                         *  
178                         *      @param buttons The order of the buttons
179                         */
180                        public void setButtons( final String[] buttons )
181                        {
182                                this.buttons = buttons;
183
184                                final ArrayList<Method> methodsList = new ArrayList<Method>();
185                                for( final String button: buttons )
186                                {
187                                        // Make sure we're only allowing the methods predetermined
188                                        // by us, so not any old method could be put in.
189                                        if( this.buttonsMap.get( button ) != null )
190                                        {
191                                                try
192                                                {
193                                                        methodsList.add( VideoPlayer.this.getClass().
194                                                                        getMethod(button) );
195                                                }
196                                                catch( final SecurityException e )
197                                                {
198                                                        e.printStackTrace();
199                                                }
200                                                catch( final NoSuchMethodException e )
201                                                {
202                                                        e.printStackTrace();
203                                                }
204                                        }
205                                }
206                                
207                                this.methods = methodsList.toArray( new Method[0] );
208                                this.init();
209                        }
210
211                        /**
212                         * 
213                         */
214                        private void init()
215                        {
216                                this.removeAll();
217                                this.setLayout( new GridBagLayout() );
218                                this.setOpaque( false );
219                                
220                                final GridBagConstraints gbc = new GridBagConstraints();
221                                gbc.fill = GridBagConstraints.HORIZONTAL;
222                                gbc.weightx = gbc.weighty = 0;
223                                gbc.gridx = gbc.gridy = 1;
224                                gbc.insets = new Insets( this.inset, this.inset, this.inset, this.inset );
225
226                                // ------------------------------------------------------------
227                                // Progress bar
228                                // ------------------------------------------------------------
229                                gbc.gridy = 0;
230                                gbc.weightx = 1;
231                                gbc.gridwidth = this.buttons.length;
232                                this.add( this.progress, gbc );
233                                this.progress.addMouseListener( new MouseAdapter()
234                                {
235                                        @Override
236                                        public void mouseClicked( final MouseEvent e )
237                                        {
238                                                System.out.println( "Clicked at "+e.getX() );
239                                                VideoPlayer.this.setPosition( e.getX() * 100 /
240                                                                ButtonsPanel.this.getWidth() );
241                                        }
242                                } );
243
244                                // ------------------------------------------------------------
245                                // Navigation Buttons
246                                // ------------------------------------------------------------
247                                final JPanel buttonsPanel = new JPanel( new GridBagLayout() );
248                                buttonsPanel.setBorder( BorderFactory.createEmptyBorder() );
249                                buttonsPanel.setOpaque( false );
250                                
251                                gbc.weightx = gbc.weighty = 0;
252                                gbc.gridx = gbc.gridy = 1;
253                                gbc.gridwidth = 1;
254                                for( int i = 0; i < this.buttons.length; i++ )
255                                {
256                                        final String b = this.buttons[i];
257                                        final ImageIcon buttonIcon = new ImageIcon( this.getClass()
258                                                        .getResource( this.buttonsMap.get(b) ) );
259                                        final JLabel button = new JLabel( buttonIcon );
260                                        button.setBorder( BorderFactory.createEmptyBorder() );                                                  
261                                        final int j = i;
262                                        button.addMouseListener( new MouseAdapter()
263                                        {
264                                                @Override
265                                                public void mouseClicked( final MouseEvent e ) 
266                                                {
267                                                        try
268                                                        {
269                                                                ButtonsPanel.this.methods[j].invoke( 
270                                                                                VideoPlayer.this );
271                                                        }
272                                                        catch( final IllegalArgumentException e1 )
273                                                        {
274                                                                e1.printStackTrace();
275                                                        }
276                                                        catch( final IllegalAccessException e1 )
277                                                        {
278                                                                e1.printStackTrace();
279                                                        }
280                                                        catch( final InvocationTargetException e1 )
281                                                        {
282                                                                e1.printStackTrace();
283                                                        }
284                                                };
285                                                
286                                                @Override
287                                                public void mouseEntered(final MouseEvent e) 
288                                                {
289                                                        button.setBorder( BorderFactory.createLineBorder( Color.yellow ) );
290                                                };
291                                                
292                                                @Override
293                                                public void mouseExited(final MouseEvent e) 
294                                                {
295                                                        button.setBorder( BorderFactory.createEmptyBorder() );                                                  
296                                                };
297                                        } );
298                                        buttonsPanel.add( button, gbc );
299                                        gbc.gridx++;
300                                }
301                                buttonsPanel.add( this.label, gbc );
302                                
303                                gbc.gridy = 2;
304                                gbc.gridx = 1;
305                                this.add( buttonsPanel, gbc );
306                        }
307
308                        @Override
309                        public void paint( final Graphics g )
310                        {
311                                g.drawImage( this.img, 0, 0, null );
312                                super.paint( g );
313                        }
314                        
315                        /**
316                         *      Set the progress (0-100)
317                         *      @param pc The %age value
318                         */
319                        public void setProgress( final double pc )
320                        {
321                                this.progress.setValue( (int)pc );
322                        }
323
324                        @Override
325                        public void afterUpdate( final VideoDisplay<T> display )
326                        {
327                                this.setProgress( display.getPosition() );
328                                
329                                // The end timecode
330                                final HrsMinSecFrameTimecode end = new HrsMinSecFrameTimecode( 
331                                                VideoPlayer.this.getVideo().countFrames(), 
332                                                VideoPlayer.this.getVideo().getFPS() );
333                                
334                                final HrsMinSecFrameTimecode current = new HrsMinSecFrameTimecode( 
335                                                VideoPlayer.this.getVideo().currentFrame, 
336                                                VideoPlayer.this.getVideo().getFPS() );
337                                
338                                this.label.setText( current.toString()+" / "+end.toString() );
339                        }
340
341                        @Override
342                        public void beforeUpdate( final T frame )
343                        {
344                        }
345                }
346                
347                /**
348                 *      Class used to animate the buttons panel on and off the screen. 
349                 *
350                 *      @author David Dupplaw (dpd@ecs.soton.ac.uk)
351                 *  @created 14 Aug 2012
352                 *      @version $Author$, $Revision$, $Date$
353                 */
354                public class AnimatorThread implements Runnable
355                {
356                        public boolean stopNow = false;
357                        public boolean buttonValue;
358                        
359                        /**
360                         *      Create a new animator thread. If the thread succeeds the
361                         *      showButtons value will be set to the tf value given.
362                         *      @param tf Whether the buttons are shown (TRUE) or hidden
363                         */
364                        public AnimatorThread( final boolean tf )
365                        {
366                                this.buttonValue = tf;
367                        }
368                        
369                        @Override
370                        public void run()
371                        {
372                                // Animate the buttons
373                                while( !this.stopNow && VideoPlayerComponent.this.animator != null &&
374                                                !VideoPlayerComponent.this.animator.isComplete() )
375                                {
376                                        VideoPlayerComponent.this.bp.setBounds( 
377                                                VideoPlayerComponent.this.bp.getBounds().x, 
378                                                VideoPlayerComponent.this.animator.nextValue(),
379                                                VideoPlayerComponent.this.bp.getBounds().width,
380                                                VideoPlayerComponent.this.bp.getBounds().height );
381                                        try
382                                        {
383                                                // Sleep for 40ms - animates at roughly 25fps
384                                                Thread.sleep( 40 );
385                                        }
386                                        catch( final InterruptedException e )
387                                        {
388                                        }
389                                }
390                                
391                                if( !this.stopNow )
392                                        VideoPlayerComponent.this.showButtons = this.buttonValue;
393                        }                       
394                }
395
396                /** The buttons panel */
397                private ButtonsPanel bp = null;
398                
399                /** Whether to show the buttons */
400                private boolean showButtons = true;
401                
402                /** The current mode of the buttons */
403                private Mode currentMode = Mode.PLAY;
404                
405                /** The animator used to animate the buttons */
406                private LinearTimeBasedIntegerValueAnimator animator = null;
407                
408                /** The animator thread */
409                private AnimatorThread animatorThread = null;
410
411                /**
412                 * Create a new player component using the display component
413                 * 
414                 * @param ic The video display component
415                 */
416                public VideoPlayerComponent( final ImageComponent ic )
417                {
418                        try
419                        {
420                                this.init( ic );
421                        }
422                        catch( final SecurityException e )
423                        {
424                                e.printStackTrace();
425                        }
426                        catch( final NoSuchMethodException e )
427                        {
428                                e.printStackTrace();
429                        }
430                }
431
432                /**
433                 * Set up the widgets
434                 * 
435                 * @param ic The video display component
436                 * @throws NoSuchMethodException 
437                 * @throws SecurityException 
438                 */
439                private void init( final ImageComponent ic ) 
440                                throws SecurityException, NoSuchMethodException
441                {
442                        this.setLayout( null );
443                        
444                        // Add the buttons
445                        this.bp = new ButtonsPanel();
446                        this.add( this.bp );
447
448                        // Add the video
449                        this.add( ic );
450                        
451                        // Set the size of the components based on the video component
452                        this.setPreferredSize( ic.getSize() );
453                        this.setSize( ic.getSize() );
454
455                        // Position the buttons panel
456                        this.bp.setBounds( 0, this.getHeight()-this.bp.getSize().height, 
457                                        this.getWidth(), 
458                                        this.bp.getSize().height );
459
460                        this.showButtons = true;
461
462                        // Add a mouse listener to toggle the button display.
463                        final MouseAdapter ma = new MouseAdapter()
464                        {
465                                @Override
466                                public void mouseEntered(final MouseEvent e) 
467                                {
468                                        VideoPlayerComponent.this.setShowButtons( true );
469                                };
470                                
471                                @Override
472                                public void mouseExited(final MouseEvent e) 
473                                {
474                                        if( !VideoPlayerComponent.this.getVisibleRect().contains( 
475                                                        e.getPoint() ) )
476                                        {
477                                                VideoPlayerComponent.this.setShowButtons( false );
478                                        }
479                                };
480                        };
481                        ic.addMouseListener( ma );
482                        this.bp.addMouseListener( ma );
483                }
484
485                /**
486                 *      Reset the button states to the current state of the video player
487                 */
488                public void updateButtonStates()
489                {
490                        // If we're changing mode
491                        if( this.currentMode != VideoPlayer.this.getMode() )
492                        {
493                                // Pop the buttons up if the mode changes.
494                                this.showButtons = true;
495                                
496                                // TODO: Update the graphics depending on the mode
497                                switch( VideoPlayer.this.getMode() )
498                                {
499                                        case PLAY:
500                                                break;
501                                        case STOP:
502                                                break;
503                                        case PAUSE:
504                                                break;
505                                        default:
506                                                break;
507                                }
508                                
509                                // Update the buttons to reflect the current video player mode
510                                this.currentMode = VideoPlayer.this.getMode();
511                        }
512                }
513                
514                /**
515                 *      Set whether the buttons are in view or not.
516                 *      @param tf TRUE to show the buttons
517                 */
518                public void setShowButtons( final boolean tf )
519                {
520                        // Only need to do anything if the buttons are different to what
521                        // we want.
522                        if( tf != this.showButtons )
523                        {
524                                // Kill the current thread if there is one
525                                if( this.animatorThread != null )
526                                {
527                                        this.animatorThread.stopNow = true;
528                                        this.animatorThread = null;
529                                }
530                                
531                                // Create an animator to animate the buttons over 1/2 second
532                                // Animates from the current position to either off the screen
533                                // or on the screen depending on the value of tf
534                                this.animator = new LinearTimeBasedIntegerValueAnimator( 
535                                                this.bp.getBounds().y, 
536                                                this.getHeight()-(tf?this.bp.getSize().height:0), 
537                                                500 );
538                                
539                                // Start the thread
540                                this.animatorThread = new AnimatorThread( tf );
541                                new Thread( this.animatorThread ).start();
542                                
543                                this.showButtons = tf;
544                        }
545                }
546        }
547
548        /** The frame showing the player */
549        private JFrame frame = null;
550
551        /** The player component */
552        private VideoPlayerComponent component = null;
553
554        /**
555         * Create the video player to play the given video.
556         * 
557         * @param v The video to play
558         */
559        public VideoPlayer( final Video<T> v )
560        {
561                this( v, null, new ImageComponent() );
562        }
563
564        /**
565         * Create the video player to play the given video.
566         * 
567         * @param v The video to play
568         * @param audio The audio to play
569         */
570        public VideoPlayer( final Video<T> v, final AudioStream audio )
571        {
572                this( v, audio, new ImageComponent() );
573        }
574
575        /**
576         * Created the video player for the given video on the given image
577         * component.
578         * 
579         * @param v The video
580         * @param audio The audio
581         * @param screen The screen to draw the video to.
582         */
583        protected VideoPlayer( final Video<T> v, final AudioStream audio, final ImageComponent screen )
584        {
585                super( v, audio, screen );
586
587                screen.setSize( v.getWidth(), v.getHeight() );
588                screen.setPreferredSize( new Dimension( v.getWidth(), v.getHeight() ) );
589                screen.setAllowZoom( false );
590                screen.setAllowPanning( false );
591                screen.setTransparencyGrid( false );
592                screen.setShowPixelColours( false );
593                screen.setShowXYPosition( false );
594                
595                this.component = new VideoPlayerComponent( screen );
596                this.component.setShowButtons( false );
597                this.addVideoDisplayStateListener( this );
598        }
599
600        /**
601         * Creates a new video player in a new thread and starts it running
602         * (initially in pause mode).
603         * 
604         * @param video The video
605         * @return The video player
606         */
607        public static <T extends Image<?, T>> VideoPlayer<T> createVideoPlayer(
608                        final Video<T> video )
609        {
610                final VideoPlayer<T> vp = new VideoPlayer<T>( video );
611                new Thread( vp ).start();
612                return vp;
613        }
614        
615        /**
616         * Creates a new video player in a new thread and starts it running
617         * (initially in pause mode).
618         * 
619         * @param video The video
620         * @param audio The udio
621         * @return The video player
622         */
623        public static <T extends Image<?, T>> VideoPlayer<T> createVideoPlayer(
624                        final Video<T> video, final AudioStream audio )
625        {
626                final VideoPlayer<T> vp = new VideoPlayer<T>( video, audio );
627                new Thread( vp ).start();
628                return vp;
629        }
630
631        /**
632         * Shows the video player in a frame. If a frame already exists it will be
633         * made visible.
634         * @return Returns the frame shown
635         */
636        public JFrame showFrame()
637        {
638                if( this.frame == null )
639                {
640                        this.frame = new JFrame();
641                        this.frame.add( this.component );
642                        this.frame.pack();
643                }
644
645                this.frame.setVisible( true );
646                return this.frame;
647        }
648
649        /**
650         *      Returns a JPanel video player which can be incorporated into other
651         *      GUIs.
652         *      @return A VideoPlayer in a JPanel
653         */
654        public JPanel getVideoPlayerPanel()
655        {
656                return this.component;
657        }
658        
659        /**
660         * Play the video.
661         */
662        public void play()
663        {
664                this.setMode( Mode.PLAY );
665        }
666
667        /**
668         * Stop the video
669         */
670        public void stop()
671        {
672                this.setMode( Mode.STOP );
673        }
674
675        /**
676         * Pause the video
677         */
678        public void pause()
679        {
680                this.setMode( Mode.PAUSE );
681        }
682
683        /**
684         * Step back a frame.
685         */
686        public void stepBack()
687        {
688
689        }
690
691        /**
692         * Step forward a frame.
693         */
694        public void stepForward()
695        {
696
697        }
698
699        /**
700         *      {@inheritDoc}
701         *      @see org.openimaj.video.VideoDisplayStateListener#videoStopped(org.openimaj.video.VideoDisplay)
702         */
703        @Override
704        public void videoStopped( final VideoDisplay<?> v )
705        {
706                // If this is called it means the video mode was changed and the video
707                // has stopped playing. We must let our buttons know that this has happened.
708                this.component.updateButtonStates();
709        }
710
711        /**
712         *      {@inheritDoc}
713         *      @see org.openimaj.video.VideoDisplayStateListener#videoPlaying(org.openimaj.video.VideoDisplay)
714         */
715        @Override
716        public void videoPlaying( final VideoDisplay<?> v )
717        {
718                // If this is called it means the video mode was changed and the video
719                // has started playing. We must let our buttons know that this has happened.
720                this.component.updateButtonStates();
721        }
722
723        /**
724         *      {@inheritDoc}
725         *      @see org.openimaj.video.VideoDisplayStateListener#videoPaused(org.openimaj.video.VideoDisplay)
726         */
727        @Override
728        public void videoPaused( final VideoDisplay<?> v )
729        {
730                // If this is called it means the video mode was changed and the video
731                // has been paused. We must let our buttons know that this has happened.
732                this.component.updateButtonStates();
733        }
734
735        /**
736         *      {@inheritDoc}
737         *      @see org.openimaj.video.VideoDisplayStateListener#videoStateChanged(org.openimaj.video.VideoDisplay.Mode, org.openimaj.video.VideoDisplay)
738         */
739        @Override
740        public void videoStateChanged(
741                        final org.openimaj.video.VideoDisplay.Mode mode,
742                        final VideoDisplay<?> v )
743        {
744                // As we've implemented the other methods in this listener, so
745                // we don't need to implement this one too.
746        }
747        
748        /**
749         *      Set the buttons to show on this video player. Available buttons are:
750         *      <p>
751         *      <ul>
752         *      <li>play</li>
753         *      <li>stop</li>
754         *      <li>pause</li>
755         *      <li>stepBack</li>
756         *      <li>stepForward</li>
757         *      </ul>
758         *      <p>
759         *      Buttons not from this list will be ignored.
760         *      <p>
761         *      The order of the array will determine the order of the buttons shown
762         *      on the player.
763         * 
764         *      @param buttons The buttons to show on the player.
765         */
766        public void setButtons( final String[] buttons )
767        {
768                this.component.bp.setButtons( buttons );
769        }
770}