'From Vancouver1.0 of 28 September 2004 [latest update: #345] on 13 November 2004 at 2:16:36 am'! "Change Set: mpegMovieViewer-jhm Date: 29 September 2004 Author: John Maloney Merged sw 11/16/2004 from Vancouver updates 0231movieFixes-jhm and 0289moreMovieFixes-jhm. Adds several new functions to the viewer for the MPEGMoviePlayerMorph. Tweaks by Scott: enforce John's desired order of appearance of the items in the viewer; put play, stop, rewind into basic as well as into movie controls"! Morph subclass: #MPEGDisplayMorph instanceVariableNames: 'frameBuffer mpegFile running desiredFrameRate allowFrameDropping repeat soundTrack volume startMSecs startFrame stopFrame subtitles fullScreen subtitlesDisplayer' classVariableNames: '' poolDictionaries: '' category: 'Movies-Player'! !EToyVocabulary methodsFor: 'method list' stamp: 'sw 11/3/2004 20:13'! masterOrderingOfPhraseSymbols "Answer a dictatorially-imposed presentation list of phrase-symbols. This governs the order in which suitable phrases are presented in etoy viewers using the etoy vocabulary. For any given category, the default implementation is that any items that are in this list will occur first, in the order specified here; after that, all other items will come, in alphabetic order by formal selector." ^ #(beep: forward: turn: getX getY getLocationRounded getHeading getScaleFactor getLeft getRight getTop getBottom getLength getWidth getTheta getDistance getHeadingTheta getUnitVector startScript: pauseScript: stopScript: startAll: pauseAll: stopAll: tellAllSiblings: doScript: getColor getUseGradientFill getSecondColor getRadialGradientFill getBorderWidth getBorderColor getBorderStyle getRoundedCorners getDropShadow getShadowColor getVolume play playUntilPosition: stop rewind getIsRunning getRepeat getPosition getTotalFrames getTotalSeconds getFrameGraphic getVideoFileName getSubtitlesFileName getGraphic getBaseGraphic #getAutoExpansion #getAutoLineLayout #getBatchPenTrails #getFenceEnabled #getIndicateCursor #getIsOpenForDragNDrop #getIsPartsBin #getMouseOverHalos #getOriginAtCenter #getShowThumbnail)! ! !MPEGDisplayMorph methodsFor: 'accessing' stamp: 'jm 10/12/2004 12:22'! currentFrameScaled "Answer a Form containing the current frame scaled to my current size." | f | f _ Form extent: self extent depth: 32. frameBuffer ifNil: [^ f fillColor: (Color gray: 0.75)]. self drawScaledOn: ((FormCanvas on: f) copyOffset: self topLeft negated). ^ f! ! !MPEGDisplayMorph methodsFor: 'accessing' stamp: 'jm 10/12/2004 11:40'! totalFrames "Answer the total number of frames in this movie." mpegFile ifNil: [^ 0]. mpegFile fileHandle ifNil: [^ 0]. (FileStream isAFileNamed: mpegFile fileName) ifFalse: [^ 0]. mpegFile hasVideo ifFalse: [^ 0]. ^ mpegFile videoFrames: 0! ! !MPEGDisplayMorph methodsFor: 'accessing' stamp: 'jm 10/12/2004 11:40'! totalSeconds "Answer the total number of seconds in this movie." mpegFile ifNil: [^ 0]. mpegFile fileHandle ifNil: [^ 0]. (FileStream isAFileNamed: mpegFile fileName) ifFalse: [^ 0]. mpegFile hasVideo ifFalse: [^ 0]. ^ self totalFrames asFloat / (mpegFile videoFrameRate: 0)! ! !MPEGDisplayMorph methodsFor: 'commands' stamp: 'jm 10/11/2004 23:06'! playUntilPosition: finalPosition "Play the movie until the given position, then stop." | totalFrames | totalFrames _ self totalFrames. (totalFrames > 0 and: [finalPosition > 0]) ifFalse: [^ self]. "do nothing" self startPlaying. stopFrame _ (finalPosition * totalFrames) asInteger min: totalFrames! ! !MPEGDisplayMorph methodsFor: 'commands' stamp: 'jm 10/10/2004 23:58'! startPlaying "Start playing the movie at the current position." | frameIndex | self stopPlaying. stopFrame _ nil. self mpegFileIsOpen ifFalse: [^ self]. (FileStream isAFileNamed: mpegFile fileName) ifFalse: [ | newFileResult newFileName | self inform: 'Path changed. Enter new one for: ', (FileDirectory localNameFor: mpegFile fileName). newFileResult _ StandardFileMenu oldFile. newFileName _ newFileResult directory fullNameFor: newFileResult name. mpegFile openFile: newFileName]. mpegFile hasAudio ifTrue: [mpegFile hasVideo ifTrue: ["set movie frame position from soundTrack position" soundTrack reset. "ensure file is open before positioning" soundTrack soundPosition: (mpegFile videoGetFrame: 0) asFloat / (mpegFile videoFrames: 0). "now set frame index from the soundtrack position for best sync" frameIndex _ ((soundTrack millisecondsSinceStart * desiredFrameRate) // 1000). frameIndex _ (frameIndex max: 0) min: ((mpegFile videoFrames: 0) - 3). mpegFile videoSetFrame: frameIndex stream: 0]. SoundPlayer stopReverb. soundTrack volume: volume. soundTrack repeat: repeat. soundTrack resumePlaying. startFrame _ startMSecs _ 0] ifFalse: [soundTrack _ nil. startFrame _ mpegFile videoGetFrame: 0. startMSecs _ Time millisecondClockValue]. running _ true! ! !MPEGDisplayMorph methodsFor: 'other' stamp: 'jm 10/11/2004 00:20'! advanceFrame "Advance to the next frame if it is time to do so, skipping frames if necessary." | msecs currentFrame desiredFrame framesToAdvance | mpegFile hasVideo ifFalse: [^ self]. soundTrack ifNil: [msecs _ Time millisecondClockValue - startMSecs] ifNotNil: [msecs _ soundTrack millisecondsSinceStart - SoundPlayer bufferMSecs]. desiredFrame _ startFrame + ((msecs * desiredFrameRate) // 1000) + 1. desiredFrame _ desiredFrame min: (mpegFile videoFrames: 0). currentFrame _ mpegFile videoGetFrame: 0. stopFrame ifNotNil: [desiredFrame _ desiredFrame min: stopFrame. currentFrame >= stopFrame ifTrue: [^ self stopPlaying]]. framesToAdvance _ desiredFrame - currentFrame. framesToAdvance <= 0 ifTrue: [^ self]. (allowFrameDropping and: [framesToAdvance > 1]) ifTrue: [mpegFile videoDropFrames: framesToAdvance - 1 stream: 0]. self nextFrame! ! !MPEGMoviePlayerMorph methodsFor: 'accessing' stamp: 'jm 10/12/2004 11:31'! totalFrames "Answer the total number of frames in this movie." ^ moviePlayer totalFrames! ! !MPEGMoviePlayerMorph methodsFor: 'accessing' stamp: 'jm 10/12/2004 11:31'! totalSeconds "Answer the total number of seconds in this movie." ^ moviePlayer totalSeconds! ! !MPEGMoviePlayerMorph methodsFor: 'e-toy support' stamp: 'jm 9/28/2004 17:06'! getCurrentFrameForm "Answer a Form containing the current frame scaled to the size of my display." ^ moviePlayer currentFrameScaled ! ! !MPEGMoviePlayerMorph methodsFor: 'e-toy support' stamp: 'jm 9/28/2004 16:59'! getCurrentFrameImageMorph "Answer an ImageMorph containing the current frame scaled to the size of my display." ^ ImageMorph new image: (moviePlayer currentFrameScaled) ! ! !MPEGMoviePlayerMorph methodsFor: 'e-toy support' stamp: 'jm 10/12/2004 11:14'! playUntilPosition: finalPosition "Play the movie until the given position, then stop." moviePlayer playUntilPosition: finalPosition! ! !MPEGMoviePlayerMorph class methodsFor: 'scripting' stamp: 'sw 10/13/2004 06:42'! additionsToViewerCategories "Answer a list of ( ) pairs that characterize the phrases this kind of morph wishes to add to various Viewer categories." ^ #( (basic ( (command play 'Start playing the movie/sound') (command stop 'Stop playing the movie/sound') (command rewind 'Rewind the movie/sound'))) (#'movie controls' ( (slot videoFileName 'The name for the video file' String readWrite Player getVideoFileName Player setVideoFileName:) (slot subtitlesFileName 'The name for the subtitles file' String readWrite Player getSubtitlesFileName Player setSubtitlesFileName:) (slot position 'A number representing the current position of the movie/sound.' Number readWrite Player getPosition Player setPosition:) (slot volume 'A number representing the volume of the movie.' Number readWrite Player getVolume Player setVolume:) (command play 'Start playing the movie/sound') (command playUntilPosition: 'Play until the given position, then stop' Number) (command stop 'Stop playing the movie/sound') (command rewind 'Rewind the movie/sound') (slot isRunning 'Whether the movie/sound is being played' Boolean readOnly Player getIsRunning unused unused) (slot repeat 'Whether the movie/sound will play in an endless loop' Boolean readWrite Player getRepeat Player setRepeat:) (slot totalFrames 'Length of this movie in seconds' Number readOnly Player getTotalFrames unused unused) (slot totalSeconds 'Length of this movie in seconds' Number readOnly Player getTotalSeconds unused unused) (slot frameGraphic 'A graphic for the current frame' Graphic readOnly Player getFrameGraphic unused unused) ) ) )! ! !Player methodsFor: 'playing commands' stamp: 'jm 9/28/2004 17:09'! getCurrentFrameForm ^ self sendMessageToCostume: #getCurrentFrameForm ! ! !Player methodsFor: 'playing commands' stamp: 'sw 10/13/2004 06:41'! getFrameGraphic "Answer a form representing the receiver's costume's current graphic" ^ self sendMessageToCostume: #getCurrentFrameForm ! ! !Player methodsFor: 'playing commands' stamp: 'sw 10/13/2004 06:38'! getTotalFrames "Answer the receiver's costume's totalFrames. Applies to MPEGMoviePlayerMorphs" ^ self sendMessageToCostume: #totalFrames ! ! !Player methodsFor: 'playing commands' stamp: 'sw 10/13/2004 06:37'! getTotalSeconds "Answer the total number of seconds in the receiver's costume, typically a movie" ^ self sendMessageToCostume: #totalSeconds ! ! !Player methodsFor: 'playing commands' stamp: 'jm 10/12/2004 11:17'! playUntilPosition: aNumber self sendMessageToCostume: #playUntilPosition: with: aNumber! ! !Player methodsFor: 'playing commands' stamp: 'jm 9/28/2004 16:30'! totalFrames ^ self sendMessageToCostume: #totalFrames ! ! !Player methodsFor: 'playing commands' stamp: 'jm 9/28/2004 16:30'! totalSeconds ^ self sendMessageToCostume: #totalSeconds ! !