videocapture.videocapture - Videocapture
Table of Contents
1 Namespace: videocapture.videocapture
This namespace manages the GStreamer pipeline separated from the GUI.
2 Types
| Name | Format | Description | Generate? |
|---|---|---|---|
| ::state | any? | x | |
| ::imagecontainer | (partial instance? ImageContainer) | x | |
| :gstreamer/pipeline | |||
| :videocapture.pipeparser/appcaps |
3 Helper functions
(defn- connect-source "Connects the source configured in settings.edn to the provided GStreamer pad."
[[pad index]]
{:pre [(s/valid? :gstreamer/element pad) (number? index)]}
(let [camera (nth (settings/get-setting :camera) index)
src-type (:type camera) ;;(settings/get-setting :camera :type)
src-address (:address camera) ;;(settings/get-setting :camera :address)
src-username (:username camera) ;;(settings/get-setting :camera :username)
src-password (:password camera) ;;(settings/get-setting :camera :password)
]
(debug "Connecting to device" src-address)
(case src-type
:rtsp (do (debug "Connecting to" (str "rtsp://" src-username ":" src-password "@" src-address))
(.set ^Element pad "location" (str "rtsp://" src-address))
(.set ^Element pad "user-id" src-username)
(.set ^Element pad "user-pw" src-password))
:device (do (debug "Connecting to" src-address)
(.set ^Element pad "device" src-address)))))
4 Recording
(defn record [filename]
(let [pipe (:pipeline @vcapture)
appcaps (:appcaps @vcapture)
endpoint (second (first (:endpoint appcaps)))
fileout (ElementFactory/make "filesink" "fileout")
valves (map second (:storage-valve appcaps))
extension (settings/get-setting :C :file-extension)]
(.set fileout "location" (str filename extension))
(.addMany pipe (into-array Element [fileout]))
(Element/linkMany (into-array Element [endpoint fileout]))
(doall (map #(.set % "drop" false) valves))
(async/thread (try (.play pipe)
(catch Exception e (error e))))
(reset! (:state @vcapture) :recording)
(reset! (:target-file @vcapture) (str filename extension))))
(defn fpath [filename]
(.toPath (io/file filename)))
(defn recording-stop [filename]
(let [tempfile (str (settings/get-setting :xdg :home) "tmp" (settings/get-setting :C :file-extension))]
(debug "Moving" filename "to" tempfile "...")
(Files/move (fpath filename) (fpath tempfile) (into-array java.nio.file.StandardCopyOption [java.nio.file.StandardCopyOption/ATOMIC_MOVE]))
(debug "Setting correcting timestamps...")
(sh/sh "ffmpeg" "-i" tempfile "-c" "copy" "-fflags" "+genpts" filename)
(debug "Cleaning up.")
(Files/deleteIfExists (fpath tempfile))
))
5 Pipeline state
(defn- start-pipeline []
(let [gst-listener (new AppSinkListener)
image-container (.getImageContainer gst-listener)
[^Pipeline pipe appcaps] (pipeparser/build-pipeline :recording)
sourcepad (s/conform (s/coll-of :gstreamer/element) (map second (:source appcaps)))
videosink (s/conform :gstreamer/element (.getElementByName pipe "displaysink"))]
(debug "Camera:" (settings/get-setting :camera))
(debug "Appcaps:" appcaps)
(debug "Sourcepad:" (pr-str sourcepad))
(doall (map connect-source (apply assoc {} (interleave sourcepad (range)))))
(.connect videosink gst-listener)
(async/thread (.play pipe))
{:pipeline pipe
:appcaps appcaps
:image-container image-container
:target-file (atom "")
:state (atom :preview)}))
(defn- stop-pipeline [vcapture]
(let [pipe (:pipeline @vcapture)
state @(:state @vcapture)
filename @(:target-file @vcapture)
eosreceiver (map second (:storage-valve (:appcaps @vcapture)))
]
(debug "Stopping pipeline" pipe)
(debug "Recording state was" state)
(.set pipe "message-forward" true)
(.connect (.getBus pipe) (fx/fi org.freedesktop.gstreamer.Bus$EOS
[src]
(debug "Stopping preview player...")
(.stop pipe)
(try
(recording-stop filename)
(info "Preview player stopped")
(catch Exception e (error e)))
))
(debug "Sending EOS to" (pr-str eosreceiver))
(async/thread (doall (map #(.sendEvent % (new org.freedesktop.gstreamer.event.EOSEvent)) eosreceiver)))
(.sendEvent pipe (new org.freedesktop.gstreamer.event.EOSEvent))
))
(defstate vcapture
:start (start-pipeline)
:stop (stop-pipeline vcapture))
6 Complete namespace definition
(ns videocapture.videocapture "Manages the GStreamer pipeline separated from the GUI." (:require [mount.core :as mount :refer [defstate]] [clojurefx.clojurefx :as fx] [videocapture.pipeparser :as pipeparser] [videocapture.settings :as settings] [clojure.java.shell :as sh] [clojure.java.io :as io] [clojure.core.async :as async :refer [chan]] [clojure.spec.alpha :as s] [taoensso.timbre :as timbre :refer [log trace debug info warn error fatal report logf tracef debugf infof warnf errorf fatalf reportf spy get-env]]) (:import (org.freedesktop.gstreamer ElementFactory Element Pipeline) (videocapture AppSinkListener ImageContainer) (clojure.lang Atom) (java.nio.file Files))) (declare vcapture) <<types>> <<helper-fns>> <<recording>> <<recording-stop>> <<pipeline-state>>