-
Notifications
You must be signed in to change notification settings - Fork 0
/
man.scrbl
285 lines (224 loc) · 8.36 KB
/
man.scrbl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#lang scribble/base
@(require scribble/manual
(for-label racket/base
video/base))
@title{Video Language Overview}
Racket's @racket[video] package is a DSL for Non-linear
video editing. Similarly to @racket[scribble] and
@racket[slideshow], you can create videos while taking
advantage of the full Racket language.
@section{Hello Green}
Create a file @tt{"green.vid"} with this content:
@codeblock{
#lang video
(color "green")}
The first line, @code{#lang video}, indicates that the file
implements a video. The content of the file, @code{(color
"green")} indicates that the video should be a solid green screen.
You can use the @exec{raco video} program to render the video:
@itemlist[
@item{Run:
@commandline{raco video green.vid}
to see a preview of the video. This includes playback
controls and the rendered video. In this case the
preview will be a solid green frame.}
@item{Run:
@commandline{raco video -o green.mp4 green.vid}
to render the video to an MP4 file.}
@item{Run:
@commandline{raco video -t xml -o green.xml green.vid}
to render the video to a plain text XML file.}]
@section{Multiple clips}
A video is formed by creating a
playlist of clips. All top-level video clips in a file are
placed in a single playlist. For example:
@codeblock{
#lang video
(color "blue" #:length 50)
(color "green" #:length 50)}
Creates a movie with 50 frames of blue (about 1 second),
followed by 50 frames of green.
You can even constructs native to, such as lists, to create a playlist:
@codeblock{
#lang video
(for/list ([i (in-range 255)])
(color (list 0 i 0)))}
Creates a clip that slowly fades from black to green. We
could use @racket[playlist] to convert the playlist to a
clip, but this is not needed, because playlists are clips.
You can even include clips generated by other video language
programs:
@codeblock{
#lang video
(include-video "green.vid")
(include-video "blue.vid")
}
This play the @tt{"green.vid"} program from above, followed
by a similar @tt{"blue.vid"} program.
@section{Creating pictures}
Using the @racket[picture] function, images created with the
@racketmodname[pict] and @racketmodname[racket/draw]
libraries can be placed in videos. For example, the
following program creates a video of the standard fish:
@codeblock{
#lang video
(require pict)
(picture (standard-fish 500 500))
}
Notice that @racket[(require pict)] was placed in the file
without adding a clip to the video. Only top level
expressions add clips to the video, definitions and require
forms do not. We could further extend this idea to create a
movie of a standard fish swimming in progressively contaminated water:
@codeblock{
#lang video
(require pict racket/draw)
(define fishy (standard-fish #:color "chocolate"
#:width 500
#:height 255))
(for/list ([i (in-list 255)])
(picture (cc-superimpose (filled-rectangle #:color (make-object color% 0 i (- 255 i))
#:width 600
#:height 600
fishy))))
}
@section{Importing camera videos}
While creating videos from clips is fun, we need to be able
to import videos from other sources, such as a camera. This
is be done with @racket[clip]:
@codeblock{
#lang video
(clip "step.mp4")
}
Here, @tt{"step.mp4"} is a video of a person walking. We can
use @racket[clip]'s optional arguments to keep only a slice
of the clip, play it slower, and even backwards. Here, we
make this person take the step several times before letting her continue on:
@codeblock{
#lang video
(define step "step.mp4")
(clip step #:out 100)
(for/list ([i (in-range 50)])
(clip step
#:in 100
#:out 200
#:speed (if (even? i) 1 -1)))
(clip step #:in 100)
}
@section{Applying Filters}
Every clip in @racket[video] can have a filter attached to
it, using @racket[attach-filter]. Filiters alter the
behavior of a clip such as turning it to grayscale,
inverting the colors, or even adding a watermark. As an
example, we can create a grayscale version of the girl
walking using the @racket[grayscale-filter]:
@codeblock{
#lang video
(define walking (include-video "walking.vid"))
(attach-filter walking (grayscale-filter))
}
@section{Clip Properties}
Let's say we want to add a watermark to our walking video.
However, we want to add it to the first 10% of the video,
and then we want the watermark to go away. Every clip has a
set of properties attached to it. The relevant one here is
@racket['length], which stores the clip's length. We can use
@racket[properties-ref] to get the property:
@codeblock{
#lang video
(define walking (include-video "walking.vid"))
(define walking-length (properties-ref walking 'length))
(attach-filter walking (watermark-filter 0 0 1/8 1/8
#:in 0 #:out (/ walking-length 10)))
}
@section{Using Multitracks}
While playlists are powerful for laying out clips
horizontally---playing clips in succession. Videos also need
an abstraction for laying out clips vertically---playing
clips at the same time. For example, we may want to play a song with our walking clip:
@codeblock{
#lang video
(multitrack
(include-video "walking.vid")
(audio "music.wav"))
}
The @racket[audio] function is similar to @racket[clip], but
the created clip only contains audio. @racket[multitrack]
superimposes a list of clips on top of each other. Like
@racket[playlist], a @racket[multitrack] is also itself a
clip. In the top clip only plays audio, the walking
clip plays in lockstep with the music.
This example works only because @tt{"music.wav"} does not
contain any video. If it did, @tt{ "walking.vid"} would be
completely overshadowed. We can tell @racket[multitrack] how
we would like the videos to be mixed by taking advantage
that each clip is @racket[eq?] with itself. The following
clip plays the walking clip and the toxic fish clip in lockstep,
with the fish clip taking up the top-left corner of the screen:
@codeblock{
#lang video
(define walking (include-video "walking.vid"))
(define polluted-fish (include-video "polluted-fish.vid"))
(multitrack
walking polluted-fish (audio "music.wav")
#:effects (list (composite walking polluted-fish 0 0 1/4 1/4)))
}
Another, more concise way, to express this is:
@codeblock{
#lang video
(define walking (include-video "walking.vid"))
(define polluted-fish (include-video "polluted-fish.vid"))
(multitrack
walking
(composite 0 0 1/4 1/4)
polluted-fish
(audio "music.wav"))
}
Here, @racket[composite] pulls the top and bottom tracks
from the ones above and below it in the multitrack.
@section{Transitions}
Jumping from one clip to the next can sometimes be jarring.
Because of this, @racket[video] also includes transitions
which can combine two clips together.
For example, we can make a transition of a clip of a person
walking, with an equivalent one that is grayscale:
@codeblock{
(define walking (include-video "walking.vid"))
(cut-clip walking #:out 100)
(fade-transition 50)
(attach-filter (cut-clip walking #:in 100)
(grayscale-filter))
}
Here, @racket[fade-transition] takes 50 frames from the
first clip, and 50 frames from the second clip, and inserts
a new clip that lasts 50 frames that fades from the first
clip to the second. Note here that the resulting playlist
will now have three rather than two clips, and will be 50
frames shorter.
We also introduce @racket[cut-clip], which takes itself a
clip, and returns the same clip, except cut between
@racket[#:in] and @racket[#:out].
@section{Abstractions}
So far, all of our programs have used @code{#lang video}
directly. But remember that each of these primitives produce
videos themselves. We can use the linguistic constructs in
Racket to build new videos, similarly to the
@racketmodname[pict] library. We can get all of these
primitives @code{#lang video} provides with
@racketmodname[video/base].
As an example, we create a function that takes an arbitrary
video, and places a watermark on the first 5% of the video frames.
@racketblock[
(code:comment "; utils.rkt")
(require video/base)
(define (add-watermark vid)
(attach-filter
vid
(watermark-filter 0 0 1/8 1/8
#:in 0 #:out (/ (properties-ref vid 'length) 10))))]
And a video that uses this file:
@codeblock{
#lang video
(require "utils.rkt")
(add-watermark (include-video "walk.vid"))
}