'From etoys4.0 of 9 October 2008 [latest update: #2207] on 26 March 2009 at 12:56:44 pm'! "Change Set: GStreamerUI18ForEtoys Date: 26 March 2009 Author: John McIntosh and others The diff from the code in Etoys and GStreamer-UI-JMM.18.mcz"! !GStreamerMoviePlayerMorph class methodsFor: 'class initialization' stamp: 'JMM 3/27/2008 14:14'! initialize "GStreamerMoviePlayerMorph initialize." FileList registerFileReader: self. self registerInFlapsRegistry. ! ! !GStreamerPlayer methodsFor: 'accessing' stamp: 'jcg 8/13/2008 15:51'! videoFrameHeight self pipeLineIsSane ifFalse:[^1]. ^self pipeLine height! ! !GStreamerPlayer methodsFor: 'accessing' stamp: 'jcg 8/13/2008 15:51'! videoFrameRate self pipeLineIsSane ifFalse:[^1]. ^self pipeLine fps.! ! !GStreamerPlayer methodsFor: 'accessing' stamp: 'jcg 8/13/2008 15:51'! videoFrameWidth self pipeLineIsSane ifFalse:[^1]. ^self pipeLine width! ! !GStreamerPlayer methodsFor: 'actions' stamp: 'JMM 11/27/2008 23:02'! pause self tryReopen ifFalse: [^ self]. self pipeLineIsSane ifFalse:[^self]. ^self setStateToThisValue: #paused! ! !GStreamerPlayer methodsFor: 'actions' stamp: 'JMM 11/27/2008 23:02'! play | result | self tryReopen ifFalse: [^ self]. self pipeLineIsSane ifFalse:[^self]. result := self setStateToThisValue: #playing. self soundTrack play. ^result ! ! !GStreamerPlayer methodsFor: 'actions' stamp: 'yo 8/13/2008 11:20'! rewind self tryReopen ifFalse: [^ self]. self pipeLineIsSane ifFalse:[^self]. self pipeLine seekToTimeInSeconds: 0. self processAudioGiveTo: nil. " clean out pending data" self pause.! ! !GStreamerPlayer methodsFor: 'actions' stamp: 'yo 8/13/2008 11:20'! seekToTimeInSecondsEnsurePlaying: seconds self tryReopen ifFalse: [^ self]. self pipeLineIsSane ifFalse:[^nil]. self hasVideo ifFalse: [self pipeLine seekToTimeInSecondsEnsurePlaying: seconds] ifTrue: [self pause. self halt. self pipeLine seekToTimeInSecondsEnsurePlaying: seconds. self play] ! ! !GStreamerPlayer methodsFor: 'actions' stamp: 'JMM 11/27/2008 23:01'! setStateToThisValue: newState self tryReopen ifFalse: [^ nil]. self pipeLineIsSane ifFalse:[^nil]. ^self pipeLine setStateToThisValue: newState! ! !GStreamerPlayer methodsFor: 'initialize-release' stamp: 'JMM 11/29/2008 21:51'! oggHookupToSqueakAudioAndVideo | oggdemux vorbisdec vorbisdecSinkPad result audiosink audioconvert theoradec ffmpegcolorspace ximagesink theoradecSinkPad queueVideo oggdemuxSinkPad fileSrcPad audioresample caps capsfilterVideo capsfilter file bus message | "Play both audio and video using a mux, this uses two dynamically created pads just to show how they are done" "gst-launch filesrc location=test1.ogg !! oggdemux name=demux demux. !! vorbisdec !! audioconvert !! SqueakAudioSink demux. !! queue !! theoradec !! ffmpegcolorspace !! SqueakVideoSink" "Note QUEUES are needed, otherwise the video/sound will not play" file := GStreamerElement elementFactoryMake: 'filesrc' name: 'filesrc'. file setKey: 'location' toStringValue: self filesrc. oggdemux := GStreamerElement elementFactoryMake: 'oggdemux' name: 'oggdemux'. vorbisdec := GStreamerElement elementFactoryMake: 'vorbisdec' name: 'vorbisdec'. capsfilter := GStreamerElement elementFactoryMake: 'capsfilter' name: 'capsfilter'. caps := GStreamerPipelineSqueakSink audioCapsLittle. capsfilter setKey: 'caps' toPointerValue: caps handle. audiosink := GstElemSqueakAudioSink elementFactoryMake: 'fakesink' name: 'fakesinkAudio'. audiosink setKey: 'sync' toBooleanValue: true. audioconvert := GStreamerElement elementFactoryMake: 'audioconvert' name: 'audioconvert'. audioresample := GStreamerElement elementFactoryMake: 'audioresample' name: 'audioresample'. theoradec := GStreamerElement elementFactoryMake: 'theoradec' name: 'theoradec'. ffmpegcolorspace := GStreamerElement elementFactoryMake: 'ffmpegcolorspace' name: 'ffmpegcolorspace'. caps := Display depth = 32 ifTrue: [GStreamerPipelineSqueakSink videoCapsBig32] ifFalse: [GStreamerPipelineSqueakSink videoCapsBig16]. capsfilterVideo := GStreamerElement elementFactoryMake: 'capsfilter' name: 'capsfilterVideo'. capsfilterVideo setKey: 'caps' toPointerValue: caps handle. ximagesink := GstElemSqueakVideoSink elementFactoryMake: 'fakesink' name: 'fakesinkVideo'. ximagesink setKey: 'sync' toBooleanValue: true. queueVideo := GStreamerElement elementFactoryMake: 'queue' name: 'queueVideo'. volumePlayer := GStreamerElement elementFactoryMake: 'volume' name: 'volume'. "Setup the pipeline" pipeLine := GStreamerPipelineSqueakVideoSink name: 'my-pipeline'. result := pipeLine addElement: oggdemux. result := pipeLine addElement: vorbisdec. result := pipeLine addElement: file. result := pipeLine addElement: capsfilter. result := pipeLine addElement: capsfilterVideo. result := pipeLine addElement: audiosink. result := pipeLine addElement: audioconvert. result := pipeLine addElement: audioresample. result := pipeLine addElement: theoradec. result := pipeLine addElement: ffmpegcolorspace. result := pipeLine addElement: ximagesink. "result := pipeLine addElement: capsfilterVideo." result := pipeLine addElement: queueVideo. result := pipeLine addElement: volumePlayer. " NOTE SETUP OF SEMAPHORE AND REGISTER STEP" pipeLine setupSemaphore. pipeLine register. result := GStreamer default linkElementSrc: vorbisdec toDest: audioconvert. result := GStreamer default linkElementSrc: audioconvert toDest: audioresample. result := GStreamer default linkElementSrc: audioresample toDest: capsfilter. result := GStreamer default linkElementSrc: capsfilter toDest: volumePlayer. result := GStreamer default linkElementSrc: volumePlayer toDest: audiosink. result := GStreamer default linkElementSrc: queueVideo toDest: theoradec. result := GStreamer default linkElementSrc: theoradec toDest: ffmpegcolorspace. result := GStreamer default linkElementSrc: ffmpegcolorspace toDest: capsfilterVideo. result := GStreamer default linkElementSrc: capsfilterVideo toDest: ximagesink. "Ok here we get the demux sink pad and hook to the filesrc we could just hook the elements together but let's explore hooking pad to pad" vorbisdecSinkPad := vorbisdec requestStaticPadByName: 'sink'. theoradecSinkPad := queueVideo requestStaticPadByName: 'sink'. oggdemuxSinkPad := oggdemux requestStaticPadByName: 'sink'. fileSrcPad := file requestPadThatIsCompatibleTo: oggdemuxSinkPad capsFilter: oggdemuxSinkPad getCaps. GStreamer default linkPadSrc: fileSrcPad toDest: oggdemuxSinkPad. "Now lets setup the dynamic pad" oggdemux requestCallBackForSignal: 'pad-added' useArray: (Array with: vorbisdecSinkPad with: theoradecSinkPad). pipeLine setStateTo: #paused. bus := pipeLine getBus. message := bus waitUntilErrorOrMessage: 'tag' uptoMilliseconds: 5000. hasAudio := GStreamer default callbackSignalSeenForIndex: 1. hasVideo := GStreamer default callbackSignalSeenForIndex: 2. (hasVideo not or: [hasAudio not]) ifTrue: [pipeLine release. pipeLine := nil. ^self]. message := bus waitUntilErrorOrMessage: {'state-changed'. 2. #pending. pipeLine} uptoMilliseconds: 2000.! ! !GStreamerPlayer methodsFor: 'initialize-release' stamp: 'yo 8/12/2008 22:39'! oggHookupToSqueakVideo | oggdemux result theoradec ffmpegcolorspace ximagesink theoradecSinkPad queueVideo oggdemuxSinkPad fileSrcPad caps capsfilterVideo file | "Play video using a mux, this uses two dynamically created pads just to show how they are done" "gst-launch filesrc location=test1.ogg !! oggdemux name=demux demux. !! vorbisdec !! audioconvert !! SqueakAudioSink demux. !! queue !! theoradec !! ffmpegcolorspace !! SqueakVideoSink" "Note QUEUES are needed, otherwise the video/sound will not play" file := GStreamerElement elementFactoryMake: 'filesrc' name: 'filesrc'. file setKey: 'location' toStringValue: self filesrc. oggdemux := GStreamerElement elementFactoryMake: 'oggdemux' name: 'oggdemux'. theoradec := GStreamerElement elementFactoryMake: 'theoradec' name: 'theoradec'. ffmpegcolorspace := GStreamerElement elementFactoryMake: 'ffmpegcolorspace' name: 'ffmpegcolorspace'. caps := Display depth = 32 ifTrue: [GStreamerPipelineSqueakSink videoCapsBig32] ifFalse: [GStreamerPipelineSqueakSink videoCapsBig16]. capsfilterVideo := GStreamerElement elementFactoryMake: 'capsfilter' name: 'capsfilterVideo'. capsfilterVideo setKey: 'caps' toPointerValue: caps handle. ximagesink := GstElemSqueakVideoSink elementFactoryMake: 'fakesink' name: 'fakesinkVideo'. ximagesink setKey: 'sync' toBooleanValue: true. queueVideo := GStreamerElement elementFactoryMake: 'queue' name: 'queueVideo'. volumePlayer := GStreamerElement elementFactoryMake: 'volume' name: 'volume'. "Setup the pipeline" pipeLine := GStreamerPipelineSqueakVideoSink name: 'my-pipeline'. result := pipeLine addElement: oggdemux. result := pipeLine addElement: file. result := pipeLine addElement: capsfilterVideo. result := pipeLine addElement: theoradec. result := pipeLine addElement: ffmpegcolorspace. result := pipeLine addElement: ximagesink. result := pipeLine addElement: queueVideo. result := pipeLine addElement: volumePlayer. " NOTE SETUP OF SEMAPHORE AND REGISTER STEP" pipeLine setupSemaphore. pipeLine register. result := GStreamer default linkElementSrc: queueVideo toDest: theoradec. result := GStreamer default linkElementSrc: theoradec toDest: ffmpegcolorspace. result := GStreamer default linkElementSrc: ffmpegcolorspace toDest: capsfilterVideo. result := GStreamer default linkElementSrc: capsfilterVideo toDest: ximagesink. "Ok here we get the demux sink pad and hook to the filesrc we could just hook the elements together but let's explore hooking pad to pad" theoradecSinkPad := queueVideo requestStaticPadByName: 'sink'. oggdemuxSinkPad := oggdemux requestStaticPadByName: 'sink'. fileSrcPad := file requestPadThatIsCompatibleTo: oggdemuxSinkPad capsFilter: oggdemuxSinkPad getCaps. GStreamer default linkPadSrc: fileSrcPad toDest: oggdemuxSinkPad. "Now lets setup the dynamic pad" oggdemux requestCallBackForSignal: 'pad-added' useArray: (Array with: theoradecSinkPad). hasVideo := true. hasAudio := false.! ! !GStreamerPlayer methodsFor: 'initialize-release' stamp: 'JMM 8/5/2008 16:08'! oggHookupToTypeFind | file result typeFind | file := GStreamerElement elementFactoryMake: 'filesrc' name: 'filesrc'. file setKey: 'location' toStringValue: self filesrc. typeFind := GStreamerElement elementFactoryMake: 'typefind' name: 'typefind'. "Setup the pipeline" pipeLine := GStreamerPipeline name: 'my-pipeline'. pipeLine addElement: file. pipeLine addElement: typeFind. result := GStreamerSystem default linkElementSrc: file toDest: typeFind. ! ! !GStreamerPlayer methodsFor: 'initialize-release' stamp: 'JMM 11/29/2008 21:47'! tryReopen | | self pipeLineIsSane ifTrue: [^ true]. (filesrc isString and: [FileDirectory default fileExists: filesrc]) ifTrue: [self oggHookupToSqueakAudioAndVideo. self pipeLine ifNil: [self closeFile. hasAudio ifTrue: [self oggHookupToSqueakAudio]. hasVideo ifTrue: [self oggHookupToSqueakVideo]. self setStateToThisValue: #paused]. ^ true]. ^ false! ! !GStreamerPlayer methodsFor: 'stepping' stamp: 'yo 8/13/2008 10:59'! processVideoGiveTo: player self pipeLineIsSane ifFalse:[^ false]. ^self pipeLine getVideodataIfFoundGiveTo: player! ! !GStreamerPlayer class methodsFor: 'file list services' stamp: 'JMM 11/29/2008 21:50'! openFile: aFileName | player | player := self new. player filesrc: aFileName. player tryReopen. ^player! ! GStreamerMoviePlayerMorph initialize!