10. Working with video

Video playback in NeuroTask.js based on the JavaScript library MediaElement.js, which provides an excellent cross-browser video player that supports both older browsers and newer ones. NeuroTask Scripting hides most of the complexities, though these are still available if you need to do things that are not supported out of the box.

Adding video to a script is straightforward, requiring just two statements:

1 setvideo('big_buck_bunny');
2 await("videoended");

This will show a video player with the movie. You should specify the name of the movie without the exentsion (e.g., write ‘big_buck_bunny’ and not ‘big_buck_bunny.mp4’).

The final statement, awaitkey("videoended") makes sure the script does not close immediately, but waits for the end of the movie. You can also specify other events for which to wait, such as a certain time or a certain key to be pressed.

To actually show a movie, must first upload it to your account. After it will appear in the list of video files in the Quick Reference side panel on the ‘editscript’ page. The movie file should be in .mp4. It is highly recommended to also upload the same file in .webm format, so that it all browsers and platforms are supported. If you just want to run it on Chrome, you only need to provide the .mp4 format. Formats other than .mp4 and .webm are not supported (no .avi, .mkv, etc.), but you can convert any movie into the desired formats with free video conversion tools, such as Any Video Converter.

10.1 Subtitles and chapters

You can add subtitles, chapters (and a little more control) as follows:

1 var s = {
2     subtitles: "bunny_subtitles.srt",
3     chapters: "bunny_chapters.vtt"
4 }
5 
6 main.addblock("center","center",100,60).setvideo('big_buck_bunny',100,100,s);
7 
8 await("videoended");

First you specify all the options in an object (here called s). The two files specify the subtitles and chapters. A subtitle file is in the .srt format, which is a standard format for subtitles. A good website to create these and get more explanation about them is Subtitle Horse. Chapters are shown at the top of the screen and allow jumping through a movie, which may come in handy with instruction videos.

It is necessary to construct the block in which you show the video explicitly so there is enough room to show the subtitles. This also gives you more control over the size and location. If you specify the relative width and height of a video as 100 (percent), as in the statement above, the video will fill exactly the block it is in. You must make sure that the block has a similar shape as the video.

10.2 Advanced options

The following script illustrates some advanced options. This video starts by itself and cannot to be paused or skipped. The participant in the experiment is thus forced to see the entire video. However, as an illustration, we had added the option to skip it by clicking with the left mouse button on block b3, a so called ‘click’ event.

The waitfor ... or ... construct allows two or more events to be specified, where the first one to occur is handled and the rest is ignored. So, we we click on b3, the script is no longer waiting for the end of the movie to occur.

 1 var b1, b2, b3, options, advanced_options;
 2                 
 3 main = new Box();
 4 
 5 b1 = main.addblock("center","top",100,25)
 6          .text("Testing advanced (MediaElement.js) options<br>" 
 7              + "This 1 min movie cannot be skipped or fast forwarded<br>"
 8              + "It has to be watched entirely");  
 9 b2 = main.addblock("center","center",60,60);
10 b3 = main.addblock("center","bottom",100,15).button("Skip Anyway!");
11 
12 var video_options = {
13         autoplay: true,
14         subtitles: "bunny_subtitles.srt"
15     },
16     advanced_options = {
17         clickToPlayPause: false,                        
18 		features: ['volume','fullscreen'],
19 		enableKeyboard: false
20     };
21 
22 waitfor
23 {
24     b2.setvideo('big_buck_bunny',100,80,video_options,"bunny",advanced_options)
25       .await('videoended');
26 }   
27 or
28 {
29     b3.await('click');                    
30 }             
31 
32 await(1000);
33 
34 b2.clear();                
35 b3.clear();
36 b1.text("This could have been an instruction video or a scene for eye-witness questions, e\
37 tc.");

Other options and advanced options are listed in the following sections.

10.3 Supported video options

The following options are supported:

 1 == arguments ==
 2 
 3 video_url   url without an extension, preceded by a path within the videos directory, 
 4             e.g., animals/grazing_cows
 5 width       percentage of block size (100% is default)
 6 height      percentage of block size (100% is default)
 7 options     object with objects, see below for details
 8 id          id for the video/media element (default is 'videoplayer1' for first player 
 9             on page, and then 2, 3, ...)
10 
11 == options ==
12 
13 options object (all members below are optional; all paths are within the videos directory)
14 
15 hasposter   false by default (this is the image shown at the beginning, before playing)
16 poster      path/name.jpg or .png (default is url.jpg), e.g., animals/grazing_cows_evening\
17 .jpg
18 
19 autoplay    false On true, start playing immediately
20 
21 style       'ted', 'wmp', or 'mejs' (= default). N.B. Must be lower-case.
22 formats     ['mp4','webm'] is default. Also allowed: 'ogv'. N.B. Even with one format, 
23             you still need an array, e.g., ['mp4']. 
 1 subtitles   path/name.srt, e.g., animals/cows.srt (e.g., 
 2             see http://subtitle-horse.com/ for online editor)
 3 chapters    path/name.vtt, e.g., animals/cows_and_horses.vtt
 4 
 5 from        position where to start in ms (0 is default)
 6 to          position where to end in ms (-1, signals end of movie, is 
 7             default) (the to option is not implemented yet)
 8 
 9 
10 volume      80, initial volume (mejs uses 0.8 here; we remain conisistent with SoundManage\
11 r2)

In addition, the following advanced options are supported:

 1 // if the video width is not specified, this is the default
 2 defaultVideoWidth: 480,
 3 // if the video height is not specified, this is the default
 4 defaultVideoHeight: 270,
 5 // if set, overrides video width
 6 videoWidth: -1,
 7 // if set, overrides video height
 8 videoHeight: -1,
 9 // width of audio player
10 audioWidth: 400,
11 // height of audio player
12 audioHeight: 30,
13 // initial volume when the player starts
14 startVolume: 0.8,
15 // useful for audio player loops; the mediaelement player can also play (just) audio
16 loop: false,
17 // enables Flash and Silverlight to resize to content size
18 enableAutosize: true,
19 // the order of controls you want on the control bar (and other plugins below)
20 features: ['playpause','progress','current','duration','tracks','volume','fullscreen'],
21 // Hide controls when playing and mouse is not over the video
22 alwaysShowControls: false,
23 // force iPad's native controls
24 iPadUseNativeControls: false,
25 // force iPhone's native controls
26 iPhoneUseNativeControls: false,	
27 // force Android's native controls
28 AndroidUseNativeControls: false,
29 // forces the hour marker (##:00:00)
30 alwaysShowHours: false,
31 // show framecount in timecode (##:00:00:00)
32 showTimecodeFrameCount: false,
33 // used when showTimecodeFrameCount is set to true
34 framesPerSecond: 25,
35 // turns keyboard support on and off for this instance
36 enableKeyboard: true,
37 // when this player starts, it will pause other players
38 pauseOtherPlayers: true,
39 // array of keyboard commands
40 keyActions: []

10.4 Getting the video player

Once created with b.setvideo(), using the correct arguments, the video player in block b can be accessed with b.video. This allows a few additional functions to be used, such as b.video.play() and b.video.pause(). There is no stop() function because the HTML5 standard does not include this. Other properties can be found at http://mediaelementjs.com/#api. We will incorportate and document additional options later.

10.5 Showing the same video simultaneously in two blocks

For some purposes you may want to show the same video simultaneously in several blocks, e.g., left and right of a fixation point to test the distracting effect of certain moving stimuli. It is not possible to achieve absolutely simultaneous playback but you can get pretty close. The following script shows two movies, left and right, which start automatically and run to the end. There are no options for the subject to change anything about these movies: no skipping, full-screen, etc.

 1 var b1, b2, b3, cover, options, advanced_options;
 2                 
 3 b1 = addblock("center","top",100,25)
 4      .text("Two snakes");  
 5              
 6 b2 = addblock("left","center",30,20);
 7 b3 = addblock("right","center",30,20);
 8 
 9 // Cover player until it is playing to hide initial startup stuff 
10 cover2 = addblock("left","center",32,32,"white");
11 cover3 = addblock("right","center",32,32,"white");
12 
13 var video_options = {
14         autoplay: true              // Start right away
15     },
16     advanced_options = {
17       clickToPlayPause: false,    // Disable click                    
18 		features: [],               // No controls visible (Play etc.)
19 		pauseOtherPlayers: false,   // Allow two or more players
20 		enableKeyboard: false       // No keyboard shortcuts
21     };
22 
23 b2.setvideo('animated_snake_moving_1',100,100,video_options,"snake1",advanced_options);
24 // no black background
25 query(".mejs-container",b2.node).style("background-color","white"); 
26 query(".mejs-controls",b2.node).style("display","none"); // Hide controls
27 
28 // Make sure the second video player has a different ID, here 'snake2'
29 b3.setvideo('animated_snake_moving_1',100,100,video_options,"snake2",advanced_options);
30 query(".mejs-container",b3.node).style("background-color","white");
31 query(".mejs-controls",b3.node).style("display","none");
32 
33 b3.await('videoplaying'); // Starting a video may take some time, so we wait for this
34 
35 cover2.style("background-color","transparent"); // Then, we remove the cover on playing
36 cover3.style("background-color","transparent"); 
37 
38 await("videoended"); // We finish up as soon as the first player has ended
39 
40 b2.deletevideo(); // Delete the players; we will (re)create new ones all the time
41 b3.deletevideo();
42 b2.clear(); // We clear the block
43 b3.clear();                
44 
45 await(500);
46 
47 b1.text("That's all folks!");
48 
49 await(2000);

Blocks b2 and b3 show the same video, which is assumed to be available in ‘mp3’ and ‘webm’ format. Both blocks are initially covered by two white, non-transparent ‘cover’ blocks. The reason we do this here is that while the video players are loading their movie, they will show a wait cursor and may occasionally flash. This is now hidden behind the cover. Both videos will start playing nearly immediately at which point they emit the ‘videoplaying’ event. The covers are then made transparent. As soon as the videos have ended we delete the video players and clear the blocks.

The MediaElement player will show black bars if the video native size does not coincide with the specified size. We restyle these black bars to white bars, making them invisible. This done by finding the background DOM node with query(".mejs-container",b2.node) and then using the style() function on the returned DOM node. We similarly make the block with volume controls etc. invisible. Though we specifed with the features option, features: [], that no controls should be visible, some browsers still show an empty gray area for this.