Skip to content

Commit

Permalink
Switch scenes on the fly
Browse files Browse the repository at this point in the history
  • Loading branch information
mwunsch committed May 18, 2017
1 parent bc16483 commit b82c036
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 35 deletions.
12 changes: 11 additions & 1 deletion gstreamer/main.rkt
Expand Up @@ -10,17 +10,22 @@
element-factory%
element%
pipeline%
pad%
bin%
caps%
event%
bin-add-many
ghost-pad%
seconds
element-link-many)
element-link-many
_input-selector-sync-mode)

(define element-factory% (gst 'ElementFactory))

(define pipeline% (gst 'Pipeline))

(define pad% (gst 'Pad))

(define bin% (gst 'Bin))

(define caps% (gst 'Caps))
Expand All @@ -31,6 +36,8 @@

(define second ((gst 'SECOND)))

(define ghost-pad% (gst 'GhostPad))

(define (seconds num)
(* num second))

Expand All @@ -45,3 +52,6 @@
(and (send head link (car tail))
(link (car tail) (cdr tail)))
#t)))

(define _input-selector-sync-mode (_enum '(active-segment clock)))

112 changes: 78 additions & 34 deletions overscan/main.rkt
Expand Up @@ -72,49 +72,59 @@

(define current-broadcast (box #f))

(define video-preview (element-factory% 'make "osxvideosink" "sink:preview"))

(define false-preview (element-factory% 'make "fakesink" "sink:fakepreview"))

(define filter-video (caps% 'from_string "video/x-raw,width=1280,height=720")) ; 720p

(define h264-encoder
(let ([encoder (element-factory% 'make "vtenc_h264" "encode:h264")])
(gobject-set! encoder "bitrate" 3500 _uint)
(gobject-set! encoder "max-keyframe-interval-duration" (seconds 2) _int64) ; 2 second keyframe interval
encoder))

(define aac-encoder
(element-factory% 'make "faac" "encode:aac"))

(define flvmuxer
(let ([muxer (element-factory% 'make "flvmux" "mux:flv")])
(gobject-set! muxer "streamable" #t _bool)
muxer))

(define false-recording (element-factory% 'make "fakesink" "sink:fakerecording"))

(define debug:fps
(let ([debug (element-factory% 'make "fpsdisplaysink" "debug:fps")])
(define video-720p (caps% 'from_string "video/x-raw,width=1280,height=720"))

(define video-480p (caps% 'from_string "video/x-raw,width=854,height=480"))

(define (debug:preview)
(let* ([bin (bin% 'new "sink:preview")]
[scaler (element-factory% 'make "videoscale" "scale:video")]
[preview (element-factory% 'make "osxvideosink" "sink:preview")]
[sink-pad (send scaler get-static-pad "sink")])
(and (bin-add-many bin scaler preview)
(send scaler link-filtered preview video-480p)
(send bin add-pad (ghost-pad% 'new "sink" sink-pad))
bin)
))

(define (debug:fps)
(let ([debug (element-factory% 'make "fpsdisplaysink" "debug:fps")]
[video-preview (debug:preview)])
(gobject-set! debug "video-sink" video-preview (_gi-object element%))
debug))

(define (broadcast scene
#:preview [preview debug:fps]
(define (broadcast scenes
#:preview [preview (debug:fps)]
#:record [record #f])
(let ([pipeline (pipeline% 'new "broadcast")]
[video-selector (element-factory% 'make "input-selector" "selector:video")]
[audio-selector (element-factory% 'make "input-selector" "selector:audio")]
[tee (element-factory% 'make "tee" #f)]
[queue (element-factory% 'make "queue" #f)]
[h264-encoder (let ([encoder (element-factory% 'make "vtenc_h264" "encode:h264")])
(gobject-set! encoder "bitrate" 3500 _uint)
(gobject-set! encoder "max-keyframe-interval-duration" (seconds 2) _int64) ; 2 second keyframe interval
encoder)]
[flvmuxer (let ([muxer (element-factory% 'make "flvmux" "mux:flv")])
(gobject-set! muxer "streamable" #t _bool)
muxer)]
[aac-encoder (element-factory% 'make "faac" "encode:aac")]
[record-sink (if record
(recording record)
false-recording)]
(element-factory% 'make "fakesink" "sink:fake-recording"))]
[preview (or preview
false-preview)])
(or (and (bin-add-many pipeline scene tee queue preview h264-encoder aac-encoder flvmuxer record-sink)
(send scene link-filtered tee filter-video)
(element-factory% 'make "fakesink" "sink:fake-preview"))])
(gobject-set! video-selector "sync-mode" 'clock _input-selector-sync-mode)
(gobject-set! audio-selector "sync-mode" 'clock _input-selector-sync-mode)
(or (and (bin-add-many pipeline video-selector tee queue preview h264-encoder audio-selector aac-encoder flvmuxer record-sink)
(for/and ([scene scenes])
(and (send pipeline add scene)
(send scene link-pads "video" video-selector #f)
(send scene link-pads "audio" audio-selector #f)))
(send video-selector link-filtered tee video-720p)
(element-link-many tee queue preview)
(element-link-many tee h264-encoder flvmuxer)
(element-link-many scene aac-encoder flvmuxer)
(element-link-many audio-selector aac-encoder flvmuxer)
(send flvmuxer link record-sink)
(send pipeline set-state 'playing)
(set-box! current-broadcast pipeline))
Expand All @@ -130,18 +140,52 @@
(define (graphviz [broadcast (unbox current-broadcast)])
((gst 'debug_bin_to_dot_data) broadcast 'all))

(define (scene videosrc audiosrc)
(define (scene videosrc audiosrc [broadcast (unbox current-broadcast)])
(let ([bin (bin% 'new #f)])
(or (and (bin-add-many bin videosrc audiosrc)
(let* ([video-pad (send videosrc get-static-pad "src")]
[ghost ((gst 'GhostPad) 'new "video" video-pad)])
[ghost (ghost-pad% 'new "video" video-pad)])
(send bin add-pad ghost))
(let* ([audio-pad (send audiosrc get-static-pad "src")]
[ghost ((gst 'GhostPad) 'new "audio" audio-pad)])
[ghost (ghost-pad% 'new "audio" audio-pad)])
(send bin add-pad ghost))
(if broadcast
(let ([video-selector (send broadcast get-by-name "selector:video")]
[audio-selector (send broadcast get-by-name "selector:audio")])
(and (send broadcast add bin)
video-selector
(send bin link-pads "video" video-selector #f)
audio-selector
(send bin link-pads "audio" audio-selector #f)))
#t)
bin)
(error "could not create scene"))))

(define (switch scene-or-id [broadcast (unbox current-broadcast)])
(unless broadcast
(error "there is no current broadcast"))
(define scene-name (if (string? scene-or-id)
scene-or-id
(send scene-or-id get-name)))
(cond
[(send broadcast get-by-name scene-name) =>
(lambda (scene)
(let* ([video-pad (send scene get-static-pad "video")]
[audio-pad (send scene get-static-pad "audio")]
[video-selector (send broadcast get-by-name "selector:video")]
[audio-selector (send broadcast get-by-name "selector:audio")]
[active-video (gobject-get video-selector "active-pad" (_gi-object pad%))]
[old-video (send active-video get-parent-element)]
[active-audio (gobject-get audio-selector "active-pad" (_gi-object pad%))]
[old-audio (send active-audio get-parent-element)]
[video-peer-pad (send video-pad get-peer)]
[audio-peer-pad (send audio-pad get-peer)]
[state-status (send scene set-state 'playing)])
(and (gobject-set! video-selector "active-pad" video-peer-pad (_gi-object pad%))
(gobject-set! audio-selector "active-pad" audio-peer-pad (_gi-object pad%))
state-status)))]
[else (error (format "scene ~a is not part of the broadcast" scene-name))]))

(define (recording location)
(let ([bin (bin% 'new "recording")]
[filesink (element-factory% 'make "filesink" #f)])
Expand Down

0 comments on commit b82c036

Please sign in to comment.