Support multiple regeneratable footage analyses
This commit is contained in:
parent
5bcf22e458
commit
15deaea19e
20 changed files with 333 additions and 168 deletions
|
|
@ -26,3 +26,34 @@
|
|||
(vals (get-in clip [:symbols :take :nodes]))))))
|
||||
"and the copy's instance follows its renamed symbol")
|
||||
(is (empty? (clip/problems clip)))))
|
||||
|
||||
(defn- tracked-take [analysis-id]
|
||||
{:analyses {analysis-id {:id analysis-id :detector "test" :version "1"}}
|
||||
:subjects {:face-1 {:id :face-1 :analysis analysis-id
|
||||
:source-subject :face-1 :params {}}}
|
||||
:features {:face-1/mouth {:id :face-1/mouth :subject :face-1
|
||||
:symbol :face-1 :area :mouth :nodes [:mouth] :params {}}}
|
||||
:groups {}
|
||||
:symbols {:main {:id :main :fps 30 :frames 10
|
||||
:nodes {:face-1 {:id :face-1 :kind :instance :z "a1"
|
||||
:source {:symbol :face-1}}}}
|
||||
:face-1 {:id :face-1 :fps 30 :frames 10
|
||||
:nodes {:head {:id :head :kind :group :z "a1"
|
||||
:measured {[:xform :pos]
|
||||
{:animated? false :value [0 0]}}}
|
||||
:mouth {:id :mouth :kind :poly :z "a2"}}}}})
|
||||
|
||||
(deftest every-import-is-tracked-under-its-unique-symbol-scope
|
||||
(let [first (bring/take (clip/blank) (tracked-take "analysis-a")
|
||||
"close up" "footage-a" [0 10])
|
||||
second (bring/take (:clip first) (tracked-take "analysis-b")
|
||||
"close up" "footage-b" [0 10])
|
||||
c (:clip second)]
|
||||
(is (= #{:close-up.face-1 :close-up-2.face-1} (set (keys (:subjects c)))))
|
||||
(is (= #{"analysis-a" "analysis-b"} (set (keys (:analyses c)))))
|
||||
(is (= "analysis-a" (get-in c [:subjects :close-up.face-1 :analysis])))
|
||||
(is (= "analysis-b" (get-in c [:subjects :close-up-2.face-1 :analysis])))
|
||||
(is (= :face-1 (get-in c [:subjects :close-up-2.face-1 :source-subject])))
|
||||
(is (= #{:close-up.face-1/mouth :close-up-2.face-1/mouth}
|
||||
(set (keys (:features c)))))
|
||||
(is (empty? (clip/problems c)))))
|
||||
|
|
|
|||
|
|
@ -90,8 +90,17 @@
|
|||
(is (or (zero? f) (< (clip/shown-frame doc :main (dec f)) n))))))))
|
||||
|
||||
(deftest imported-footage-uses-selection-for-picture-and-real-speed-for-audio
|
||||
(let [{doc :clip sid :sid} (bring/take (clip/set-fps (clip/blank) 12)
|
||||
footage "take" "video" [15 75])
|
||||
(let [tracked (-> footage
|
||||
(assoc :analyses {"a" {:id "a"}}
|
||||
:subjects {:face-1 {:id :face-1 :analysis "a"
|
||||
:source-subject :face-1}}
|
||||
:features {} :groups {}
|
||||
:symbols {:main {:id :main :fps 30 :frames 60
|
||||
:nodes {:face-1 {:id :face-1 :kind :instance
|
||||
:z "a" :source {:symbol :face-1}}}}
|
||||
:face-1 (get-in footage [:symbols :main])}))
|
||||
{doc :clip sid :sid} (bring/take (clip/set-fps (clip/blank) 12)
|
||||
tracked "take" "video" [15 75])
|
||||
;; A host authored at 12, with a 30fps source starting half a second in.
|
||||
doc (-> doc (assoc-in [:symbols :main :fps] 12)
|
||||
(clip/place-symbol store :main sid 6 :insert nil))
|
||||
|
|
@ -99,21 +108,16 @@
|
|||
draw (clip/resolver doc :main store pal/index-of nil)
|
||||
[sound] (nest/audio-tracks doc :main)]
|
||||
(is (= 60 (clip/frames doc sid)))
|
||||
(is (= 1 (get-in doc [:symbols sid :nodes :sound :time :rate])))
|
||||
(is (= 1 (get-in doc [:symbols :take.face-1 :nodes :sound :time :rate])))
|
||||
(is (= [0 24] (:span n)))
|
||||
(is (empty? (draw 5)))
|
||||
(is (= 8 (:size (first (draw 9)))))
|
||||
(is (= 7 (:frame (nest/inside doc store :main [:insert :mark] 9))))
|
||||
(is (= 7 (:frame (nest/inside doc store :main [:insert :face-1 :mark] 9))))
|
||||
(is (= [-4 -4 4 4] ((pick/bounds-of doc store :main n) 3)))
|
||||
(is (= [6 30] (node/placed-span sound)))
|
||||
(is (= 15 (node/local-frame sound 6)))
|
||||
(is (= 1 (* (get-in sound [:time :rate]) (/ (:fps doc) (:fps sound)))))
|
||||
(is (= [6 30] (:span (first (timeline/rows doc :main #{[:insert]})))))
|
||||
(testing "an off-grid closed mouth can win without modifying the dense source"
|
||||
(let [pinned (pose/put-cut doc :main :insert :mouth 7 6)
|
||||
r (clip/resolver pinned :main store pal/index-of nil)]
|
||||
(is (= 7 (:size (first (r 9)))))
|
||||
(is (= (get-in doc [:symbols sid]) (get-in pinned [:symbols sid])))))
|
||||
(testing "a deliberate half speed still retimes audio"
|
||||
(let [slow (assoc-in doc [:symbols :main :nodes :insert :playback :speed] 0.5)
|
||||
[track] (nest/audio-tracks slow :main)]
|
||||
|
|
@ -121,7 +125,9 @@
|
|||
|
||||
(deftest generated-faces-own-their-footage-sound
|
||||
(let [face (fn [id] {:id id :fps 30 :frames 20 :nodes {}})
|
||||
frozen {:fps 30 :subjects {:face-1 {} :face-2 {}}
|
||||
frozen {:fps 30 :analyses {"a" {:id "a"}}
|
||||
:subjects {:face-1 {:id :face-1 :analysis "a" :source-subject :face-1}
|
||||
:face-2 {:id :face-2 :analysis "a" :source-subject :face-2}}
|
||||
:symbols {:main {:id :main :fps 30 :frames 20
|
||||
:nodes {:face-1 {:id :face-1 :kind :instance :z "a1"
|
||||
:source {:symbol :face-1}}
|
||||
|
|
@ -130,11 +136,11 @@
|
|||
:face-1 (face :face-1)
|
||||
:face-2 (face :face-2)}}
|
||||
{doc :clip take :sid} (bring/take (clip/blank) frozen "take" "video" [3 13])
|
||||
alone (clip/place-symbol doc nil :main :face-1 4 :placed-face nil)]
|
||||
alone (clip/place-symbol doc nil :main :take.face-1 4 :placed-face nil)]
|
||||
(is (nil? (get-in doc [:symbols take :nodes :sound]))
|
||||
"the wrapper does not own a sound the face would lose")
|
||||
(is (= {:footage "video"}
|
||||
(get-in doc [:symbols :face-1 :nodes :sound :source])))
|
||||
(get-in doc [:symbols :take.face-1 :nodes :sound :source])))
|
||||
(is (= 1 (count (nest/audio-tracks doc take)))
|
||||
"the same take recording is not mixed once per detected face")
|
||||
(is (= 1 (count (nest/audio-tracks alone :main)))
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
(let [ls (leaf/leaves :c7 @take/clip)]
|
||||
(is (contains? ls "clip/c7/timing"))
|
||||
(is (contains? ls "clip/c7/stage"))
|
||||
(is (contains? ls "clip/c7/source"))
|
||||
(is (contains? ls "clip/c7/analyses"))
|
||||
;; A TIMELINE ID IS A SEGMENT, which is what lets a symbol's nodes be
|
||||
;; addressed by the same path shape as the clip's own. `main` is the root.
|
||||
(is (contains? ls "clip/c7/symbol/main"))
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
(:require [cljs.test :refer [deftest is testing]]
|
||||
[clojure.walk :as walk]
|
||||
[arthur.demo.stage :as stage]
|
||||
[arthur.domain.bring :as bring]
|
||||
[arthur.domain.channel :as ch]
|
||||
[arthur.domain.clip :as clip]
|
||||
[arthur.domain.params :as params]
|
||||
|
|
@ -29,13 +30,41 @@
|
|||
(merge take/knobs
|
||||
{:name "regen" :fps 30 :aspect 1 :stage [320 200]
|
||||
:expose 1 :head :free
|
||||
:analysis (get-in @initial [:clip :analysis])}
|
||||
:analysis (-> @initial :clip :analyses vals first)}
|
||||
change)
|
||||
{:face-1 @inputs}))
|
||||
|
||||
(defn- channel [entry node path]
|
||||
(get-in entry [:clip :symbols :face-1 :nodes node :channels path]))
|
||||
|
||||
(deftest a-second-import-regenerates-through-its-own-analysis
|
||||
(let [built (fn [seed]
|
||||
(let [input {:dense (synth/synth-dense frames {:seed seed})}
|
||||
analysis (address/analysis
|
||||
{:detector "synth" :version "mulberry32"
|
||||
:seed seed :frames frames :fps 30 :aspect 1})]
|
||||
[(take/build (merge take/knobs
|
||||
{:name "take" :fps 30 :aspect 1 :stage [320 200]
|
||||
:expose 1 :head :free :analysis analysis})
|
||||
{:face-1 input})
|
||||
input]))
|
||||
[a input-a] (built 3)
|
||||
[b input-b] (built 7)
|
||||
first (bring/take (clip/blank) (:clip a) "shot" "footage-a" [0 frames])
|
||||
second (bring/take (:clip first) (:clip b) "shot" "footage-b" [0 frames])
|
||||
entry {:clip (:clip second) :store (merge (:store a) (:store b))
|
||||
:source-inputs {:subjects {:shot.face-1 input-a
|
||||
:shot-2.face-1 input-b}}}
|
||||
fid :shot-2.face-1/mouth
|
||||
changed (regenerate/change entry
|
||||
{:scope :feature :id fid :knob :verts :value 10})
|
||||
analysis-id (get-in changed [:clip :subjects :shot-2.face-1 :analysis])
|
||||
generated (get-in changed [:clip :symbols :shot-2.face-1 :nodes :mouth
|
||||
:channels [:geom :pts] :generated])]
|
||||
(is (= (get-in b [:clip :subjects :face-1 :analysis]) analysis-id))
|
||||
(is (= analysis-id (:analysis generated)))
|
||||
(is (= 10 (get-in generated [:params :verts])))))
|
||||
|
||||
(deftest eye-rebuild-is-confined-to-the-edited-feature
|
||||
(let [before @initial
|
||||
after (regenerate/change before
|
||||
|
|
@ -170,7 +199,7 @@
|
|||
|
||||
(defn- part-at [area overrides]
|
||||
(let [p (merge take/knobs
|
||||
{:fps 30 :aspect 1 :analysis (get-in @initial [:clip :analysis])}
|
||||
{:fps 30 :aspect 1 :analysis (-> @initial :clip :analyses vals first)}
|
||||
overrides)
|
||||
inputs (assoc @inputs :interior @interior-track)]
|
||||
(freeze/part :face-1 area p (take/measure-part area p inputs (take/anchor-base p inputs)))))
|
||||
|
|
@ -212,8 +241,8 @@
|
|||
;; document that cannot be previewed fails in the suite rather than as a slider
|
||||
;; that silently does nothing in the browser.
|
||||
(let [entry (staged)]
|
||||
(is (some? (:analysis (:clip entry)))
|
||||
"the composed stage keeps the analysis the edit needs")
|
||||
(is (seq (:analyses (:clip entry)))
|
||||
"the composed stage keeps the analyses its edits need")
|
||||
(is (some? (:source-inputs entry)))
|
||||
(testing "and the features still say which timeline they live in"
|
||||
(is (every? #(= :face-1 (:symbol %))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue