annotate org/capture-video.org @ 0:92f8d83b5d0b

initial import: I've made hearing and vision, and am working on touch.
author Robert McIntyre <rlm@mit.edu>
date Sun, 16 Oct 2011 05:12:19 -0700
parents
children 50c92af2018e
rev   line source
rlm@0 1 #+title: Capture Live Video Feeds from JMonkeyEngine
rlm@0 2 #+author: Robert McIntyre
rlm@0 3 #+email: rlm@mit.edu
rlm@0 4 #+MATHJAX: align:"left" mathml:t path:"../aurellem/src/MathJax/MathJax.js"
rlm@0 5 #+STYLE: <link rel="stylesheet" type="text/css" href="../aurellem/src/css/aurellem.css"/>
rlm@0 6 #+OPTIONS: H:3 num:t toc:t \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t
rlm@0 7 #+BABEL: :exports both :noweb yes :cache no :mkdirp yes
rlm@0 8 #+description: Capture video from a JMonkeyEngine3 Application with Xuggle, and use gstreamer to compress the video to upload to YouTube.
rlm@0 9 #+keywords: JME3, video, Xuggle, JMonkeyEngine, youtube, capture video, Java
rlm@0 10 #+INCLUDE: ../aurellem/src/templates/level-0.org
rlm@0 11 :PROPERTIES:
rlm@0 12 :EXPORT_FILE_NAME: ../whatever.html
rlm@0 13 :END:
rlm@0 14
rlm@0 15
rlm@0 16 * The Problem
rlm@0 17 So you've made your cool new JMonkeyEngine3 game and you want to
rlm@0 18 create a demo video to show off your hard work. Screen capturing is
rlm@0 19 the most straightforward way to do this, but it can slow down your
rlm@0 20 game and produce low-quality video as a result. A better way is to
rlm@0 21 record a video feed directly from the game while it is
rlm@0 22 running.
rlm@0 23
rlm@0 24 In this post, I'll explain how you can alter your JMonkeyEngine3 game
rlm@0 25 to output video while it is running. The main trick is to alter the
rlm@0 26 pace of JMonkeyEngine3's in-game time: we allow the engine as much
rlm@0 27 time as it needs to compute complicated in-game events and to encode
rlm@0 28 video frames. As a result, the game appears to speed up and slow down
rlm@0 29 as the computational demands shift, but the end result is perfectly
rlm@0 30 smooth video output at a constant framerate.
rlm@0 31
rlm@0 32
rlm@0 33 * Game-time vs. User-time vs. Video-time
rlm@0 34
rlm@0 35 A standard JME3 application that extends =SimpleApplication= or
rlm@0 36 =Application= tries as hard as it can to keep in sync with
rlm@0 37 /user-time/. If a ball is rolling at 1 game-mile per game-hour in the
rlm@0 38 game, and you wait for one user-hour as measured by the clock on your
rlm@0 39 wall, then the ball should have traveled exactly one game-mile. In
rlm@0 40 order to keep sync with the real world, the game throttles its physics
rlm@0 41 engine and graphics display. If the computations involved in running
rlm@0 42 the game are too intense, then the game will first skip frames, then
rlm@0 43 sacrifice physics accuracy. If there are particuraly demanding
rlm@0 44 computations, then you may only get 1 fps, and the ball may tunnel
rlm@0 45 through the floor or obstacles due to inaccurate physics simulation,
rlm@0 46 but after the end of one user-hour, that ball will have traveled one
rlm@0 47 game-mile.
rlm@0 48
rlm@0 49 When we're recording video, we don't care if the game-time syncs with
rlm@0 50 user-time, but instead whether the time in the recorded video
rlm@0 51 (video-time) syncs with user-time. To continue the analogy, if we
rlm@0 52 recorded the ball rolling at 1 game-mile per game-hour and watched the
rlm@0 53 video later, we would want to see 30 fps video of the ball rolling at
rlm@0 54 1 video-mile per /user-hour/. It doesn't matter how much user-time it
rlm@0 55 took to simulate that hour of game-time to make the high-quality
rlm@0 56 recording.
rlm@0 57
rlm@0 58 * COMMENT Two examples to clarify the point:
rlm@0 59 ** Recording from a Simple Simulation
rlm@0 60
rlm@0 61 *** Without a Special Timer
rlm@0 62 You have a simulation of a ball rolling on an infinite empty plane at
rlm@0 63 one game-mile per game-hour, and a really good computer. Normally,
rlm@0 64 JME3 will throttle the physics engine and graphics display to sync the
rlm@0 65 game-time with user-time. If it takes one-thousandth of a second
rlm@0 66 user-time to simulate one-sixtieth of a second game time and another
rlm@0 67 one-thousandth of a second to draw to the screen, then JME3 will just
rlm@0 68 sit around for the remainder of $\frac{1}{60} - \frac{2}{1000}$
rlm@0 69 user-seconds, then calculate the next frame in $\frac{2}{1000}$
rlm@0 70 user-seconds, then wait, and so on. For every second of user time that
rlm@0 71 passes, one second of game-time passes, and the game will run at 60
rlm@0 72 frames per user-second.
rlm@0 73
rlm@0 74
rlm@0 75 *** With a Special Timer
rlm@0 76 Then, you change the game's timer so that user-time will be synced to
rlm@0 77 video-time. Assume that encoding a single frame takes 0 seconds
rlm@0 78 user-time to complete.
rlm@0 79
rlm@0 80 Now, JME3 takes advantage of all available resources. It still takes
rlm@0 81 one-thousandth of a second to calculate a physics tick, and another
rlm@0 82 one-thousandth to render to the screen. Then it takes 0 seconds to
rlm@0 83 write the video frame to disk and encode the video. In only one second
rlm@0 84 of user time, JME3 will complete 500 physics-tick/render/encode-video
rlm@0 85 cycles, and $\frac{500}{60}=8\frac{1}{3}$ seconds of game-time will
rlm@0 86 have passed. Game-time appears to dilate $8\frac{1}{3}\times$ with
rlm@0 87 respect to user-time, and in only 7.2 minutes user-time, one hour of
rlm@0 88 video will have been recorded. The game itself will run at 500 fps.
rlm@0 89 When someone watches the video, they will see 60 frames per
rlm@0 90 user-second, and $\frac{1}{60}$ video-seconds will pass each frame. It
rlm@0 91 will take exactly one hour user-time (and one hour video-time) for the
rlm@0 92 ball in the video to travel one video-mile.
rlm@0 93
rlm@0 94 ** Recording from a Complex Simulation
rlm@0 95
rlm@0 96 *** Without a Special Timer
rlm@0 97 You have a simulation of a ball rolling on an infinite empty plane at
rlm@0 98 one game-mile per game-hour accompanied by multiple explosions
rlm@0 99 involving thousands of nodes, particle effects, and complicated shadow
rlm@0 100 shaders to create realistic shadows. You also have a slow
rlm@0 101 laptop. Normally, JME3 must sacrifice rendering and physics simulation
rlm@0 102 to try to keep up. If it takes $\frac{1}{120}$ of a user-second to
rlm@0 103 calculate $\frac{1}{60}$ game-seconds, and an additional
rlm@0 104 $\frac{1}{60}$ of a user-second to render to screen, then JME3 has
rlm@0 105 it's work cut out for it. In order to render to the screen, it will
rlm@0 106 first step the game forward by up to four physics ticks before
rlm@0 107 rendering to the screen. If it still isn't fast enough then it will
rlm@0 108 decrease the accuracy of the physics engine until game-time and user
rlm@0 109 time are synched or a certain threshold is reached, at which point the
rlm@0 110 game visibly slows down. In this case, JME3 continuously repeat a
rlm@0 111 cycle of two physics ticks, and one screen render. For every
rlm@0 112 user-second that passes, one game-second will pass, but the game will
rlm@0 113 run at 30 fps instead of 60 fps like before.
rlm@0 114
rlm@0 115 *** With a Special Timer
rlm@0 116 Then, you change the game's timer so that user-time will be synced to
rlm@0 117 video-time. Once again, assume video encoding takes $\frac{1}{60}$ of
rlm@0 118 a user-second.
rlm@0 119
rlm@0 120 Now, JME3 will spend $\frac{1}{120}$ of a user-second to step the
rlm@0 121 physics tick $\frac{1}{60}$ game-seconds, $\frac{1}{60}$ to draw to
rlm@0 122 the screen, and an additional $\frac{1}{60}$ to encode the video and
rlm@0 123 write the frame to disk. This is a total of $\frac{1}{24}$
rlm@0 124 user-seconds for each $\frac{1}{60}$ game-seconds. It will take
rlm@0 125 $(\frac{60}{24} = 2.5)$ user-hours to record one game-hour and game-time
rlm@0 126 will appear to flow two-fifths as fast as user time while the game is
rlm@0 127 running. However, just as in example one, when all is said and done we
rlm@0 128 will have an hour long video at 60 fps.
rlm@0 129
rlm@0 130
rlm@0 131 * COMMENT proposed names for the new timer
rlm@0 132 # METRONOME
rlm@0 133 # IsoTimer
rlm@0 134 # EvenTimer
rlm@0 135 # PulseTimer
rlm@0 136 # FixedTimer
rlm@0 137 # RigidTimer
rlm@0 138 # FixedTempo
rlm@0 139 # RegularTimer
rlm@0 140 # MetronomeTimer
rlm@0 141 # ConstantTimer
rlm@0 142 # SteadyTimer
rlm@0 143
rlm@0 144
rlm@0 145 * =IsoTimer= records time like a metronome
rlm@0 146
rlm@0 147 The easiest way to achieve this special timing is to create a new
rlm@0 148 timer that always reports the same framerate to JME3 every time it is
rlm@0 149 called.
rlm@0 150
rlm@0 151
rlm@0 152 =./jme3/src/core/com/jme3/system/IsoTimer.java=
rlm@0 153 #+include ./jme3/src/core/com/jme3/system/IsoTimer.java src java
rlm@0 154
rlm@0 155 If an Application uses this =IsoTimer= instead of the normal one, we
rlm@0 156 can be sure that every call to =simpleUpdate=, for example, corresponds
rlm@0 157 to exactly $(\frac{1}{fps})$ seconds of game-time.
rlm@0 158
rlm@0 159 In order to facilitate setting the =Timer= in user code, I added
rlm@0 160 getter and setter methods to =Application.java=.
rlm@0 161
rlm@0 162 In =./jme3/src/core/com/jme3/app/Application.java= I added:
rlm@0 163 #+include ./jme3/src/core/com/jme3/app/Application.java src java :lines "340-356"
rlm@0 164
rlm@0 165 * Encoding to Video
rlm@0 166
rlm@0 167 Now that the issue of time is solved, we just need a function that
rlm@0 168 writes each frame to a video. We can put this function somewhere
rlm@0 169 where it will be called exactly one per frame.
rlm@0 170
rlm@0 171 JME3 already provides exactly the class we need: the =SceneProcessor=
rlm@0 172 class can be attached to any viewport and the methods defined therein
rlm@0 173 will be called at the appropriate points in the rendering process.
rlm@0 174
rlm@0 175 If you want to generate video from Java, a great option is [[http://www.xuggle.com/][Xuggle]]. It
rlm@0 176 takes care of everything related to video encoding and decoding and
rlm@0 177 runs on Windows, Linux and Mac. Out of all the video frameworks for
rlm@0 178 Java I personally like this one the best.
rlm@0 179
rlm@0 180 Here is a =SceneProcessor= that uses [[http://www.xuggle.com/][Xuggle]] to write each frame to a
rlm@0 181 video file.
rlm@0 182
rlm@0 183 =./jme3/src/core/com/jme3/app/VideoProcessor.java=
rlm@0 184 #+include ./jme3/src/core/com/jme3/app/VideoProcessor.java src java
rlm@0 185
rlm@0 186 With this, we are able to record video!
rlm@0 187
rlm@0 188 * Hello Video!
rlm@0 189
rlm@0 190 I've taken [[http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/helloworld/HelloLoop.java][=./jme3/src/test/jme3test/helloworld/HelloLoop.java=]] and
rlm@0 191 augmented it with video output as follows:
rlm@0 192
rlm@0 193 =./jme3/src/test/jme3test/helloworld/HelloVideo.java=
rlm@0 194 #+include ./jme3/src/test/jme3test/helloworld/HelloVideo.java src java
rlm@0 195
rlm@0 196 The videos are created in the =hello-video= directory
rlm@0 197
rlm@0 198 #+begin_src sh :results verbatim
rlm@0 199 du -h hello-video/*
rlm@0 200 #+end_src
rlm@0 201
rlm@0 202 #+results:
rlm@0 203 : 932K hello-video/hello-video-moving.flv
rlm@0 204 : 640K hello-video/hello-video-static.flv
rlm@0 205
rlm@0 206 And can be immediately uploaded to youtube
rlm@0 207
rlm@0 208 - [[http://www.youtube.com/watch?v=C8gxVAySaPg][hello-video-moving.flv]]
rlm@0 209 #+BEGIN_HTML
rlm@0 210 <iframe width="425" height="349"
rlm@0 211 src="http://www.youtube.com/embed/C8gxVAySaPg"
rlm@0 212 frameborder="0" allowfullscreen>
rlm@0 213 </iframe>
rlm@0 214 #+END_HTML
rlm@0 215 - [[http://www.youtube.com/watch?v=pHcFOtIS07Q][hello-video-static.flv]]
rlm@0 216 #+BEGIN_HTML
rlm@0 217 <iframe width="425" height="349"
rlm@0 218 src="http://www.youtube.com/embed/pHcFOtIS07Q"
rlm@0 219 frameborder="0" allowfullscreen>
rlm@0 220 </iframe>
rlm@0 221
rlm@0 222 #+END_HTML
rlm@0 223
rlm@0 224
rlm@0 225
rlm@0 226 * Summary
rlm@0 227 It's quite easy to augment your own application to record video,
rlm@0 228 almost regardless of how complicated the actual application is. You
rlm@0 229 can also record from multiple ViewPorts as the above example shows.
rlm@0 230
rlm@0 231 The process for adding video recording to your application is as
rlm@0 232 follows:
rlm@0 233
rlm@0 234 Assuming you want to record at 30 fps, add:
rlm@0 235
rlm@0 236 #+begin_src java :exports code
rlm@0 237 this.setTimer(new IsoTimer(30));
rlm@0 238 #+end_src
rlm@0 239
rlm@0 240 Somewhere in the initialization of your Application. Right now, you
rlm@0 241 will have to add the =setTimer= method to =Application=, but hopefully
rlm@0 242 this method will be included soon by the JMonkeyEngine3 team.
rlm@0 243
rlm@0 244 Then, you create a =VideoProcessor= object and attach it to the
rlm@0 245 =ViewPort= from which you want to record.
rlm@0 246
rlm@0 247 If you want to record from the game's main =ViewPort= to a file called
rlm@0 248 =/home/r/record.flv=, then add:
rlm@0 249
rlm@0 250 #+begin_src java :exports code
rlm@0 251 viewPort.addProcessor(new VideoProcessor(new File("/home/r/record.flv")));
rlm@0 252 #+end_src
rlm@0 253
rlm@0 254 Do this for each =ViewPort= from which you want to record. The more
rlm@0 255 ViewPorts from which you record, the slower the game will run, but
rlm@0 256 this slowness will not affect the final video output.
rlm@0 257
rlm@0 258 * More Examples
rlm@0 259 ** Hello Physics
rlm@0 260 =HelloVideo= is boring. Let's add some video capturing to =HelloPhysics=
rlm@0 261 and create something fun!
rlm@0 262
rlm@0 263 This example is a modified version of =HelloPhysics= that creates four
rlm@0 264 simultaneous views of the same scene of cannonballs careening into a
rlm@0 265 brick wall.
rlm@0 266
rlm@0 267 =./jme3/src/test/jme3test/helloworld/HelloPhysicsWithVideo.java=
rlm@0 268 #+include ./jme3/src/test/jme3test/helloworld/HelloPhysicsWithVideo.java src java
rlm@0 269
rlm@0 270 Running the program outputs four videos into the =./physics-videos=
rlm@0 271 directory.
rlm@0 272
rlm@0 273 #+begin_src sh :exports both :results verbatim
rlm@0 274 ls ./physics-videos | grep -
rlm@0 275 #+end_src
rlm@0 276
rlm@0 277 #+results:
rlm@0 278 : lower-left.flv
rlm@0 279 : lower-right.flv
rlm@0 280 : upper-left.flv
rlm@0 281 : upper-right.flv
rlm@0 282
rlm@0 283 The videos are fused together with the following =gstreamer= commands:
rlm@0 284
rlm@0 285 #+begin_src sh :results silent
rlm@0 286 cd physics-videos
rlm@0 287
rlm@0 288 gst-launch-0.10 \
rlm@0 289 filesrc location=./upper-right.flv ! decodebin ! \
rlm@0 290 videoscale ! ffmpegcolorspace ! \
rlm@0 291 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 292 videobox border-alpha=0 left=-640 ! \
rlm@0 293 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
rlm@0 294 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
rlm@0 295 jpegenc ! avimux ! filesink location=upper.flv \
rlm@0 296 \
rlm@0 297 filesrc location=./upper-left.flv ! decodebin ! \
rlm@0 298 videoscale ! ffmpegcolorspace ! \
rlm@0 299 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 300 videobox right=-640 ! mix.
rlm@0 301 #+end_src
rlm@0 302
rlm@0 303 #+begin_src sh :results silent
rlm@0 304 cd physics-videos
rlm@0 305
rlm@0 306 gst-launch-0.10 \
rlm@0 307 filesrc location=./lower-left.flv ! decodebin ! \
rlm@0 308 videoscale ! ffmpegcolorspace ! \
rlm@0 309 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 310 videobox border-alpha=0 left=-640 ! \
rlm@0 311 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
rlm@0 312 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
rlm@0 313 jpegenc ! avimux ! filesink location=lower.flv \
rlm@0 314 \
rlm@0 315 filesrc location=./lower-right.flv ! decodebin ! \
rlm@0 316 videoscale ! ffmpegcolorspace ! \
rlm@0 317 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 318 videobox right=-640 ! mix.
rlm@0 319 #+end_src
rlm@0 320
rlm@0 321 #+begin_src sh :results silent
rlm@0 322 cd physics-videos
rlm@0 323
rlm@0 324 gst-launch-0.10 \
rlm@0 325 filesrc location=./upper.flv ! decodebin ! \
rlm@0 326 videoscale ! ffmpegcolorspace ! \
rlm@0 327 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
rlm@0 328 videobox border-alpha=0 bottom=-480 ! \
rlm@0 329 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
rlm@0 330 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
rlm@0 331 jpegenc ! avimux ! filesink location=../youtube/helloPhysics.flv \
rlm@0 332 \
rlm@0 333 filesrc location=./lower.flv ! decodebin ! \
rlm@0 334 videoscale ! ffmpegcolorspace ! \
rlm@0 335 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
rlm@0 336 videobox top=-480 ! mix.
rlm@0 337 #+end_src
rlm@0 338
rlm@0 339 #+begin_src sh :results verbatim
rlm@0 340 du -h youtube/helloPhysics.flv
rlm@0 341 #+end_src
rlm@0 342
rlm@0 343 #+results:
rlm@0 344 : 180M physics-videos/helloPhysics.flv
rlm@0 345
rlm@0 346
rlm@0 347 Thats a terribly large size!
rlm@0 348 Let's compress it:
rlm@0 349
rlm@0 350 ** Compressing the HelloPhysics Video
rlm@0 351 First, we'll scale the video, then, we'll decrease it's bitrate. The
rlm@0 352 end result will be perfect for upload to YouTube.
rlm@0 353
rlm@0 354 #+begin_src sh :results silent
rlm@0 355 cd youtube
rlm@0 356
rlm@0 357 gst-launch-0.10 \
rlm@0 358 filesrc location=./helloPhysics.flv ! decodebin ! \
rlm@0 359 videoscale ! ffmpegcolorspace ! \
rlm@0 360 `: # the original size is 1280 by 960` \
rlm@0 361 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
rlm@0 362 videoscale ! \
rlm@0 363 `: # here we scale the video down` \
rlm@0 364 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 365 `: # and here we limit the bitrate` \
rlm@0 366 theoraenc bitrate=1024 quality=30 ! \
rlm@0 367 oggmux ! progressreport update-freq=1 ! \
rlm@0 368 filesink location=./helloPhysics.ogg
rlm@0 369 #+end_src
rlm@0 370
rlm@0 371 #+begin_src sh :results verbatim
rlm@0 372 du -h youtube/helloPhysics.ogg
rlm@0 373 #+end_src
rlm@0 374
rlm@0 375 #+results:
rlm@0 376 : 13M youtube/helloPhysics.ogg
rlm@0 377
rlm@0 378 [[http://www.youtube.com/watch?v=WIJt9aRGusc][helloPhysics.ogg]]
rlm@0 379
rlm@0 380 #+begin_html
rlm@0 381 <iframe width="425" height="349"
rlm@0 382 src="http://www.youtube.com/embed/WIJt9aRGusc?hl=en&fs=1"
rlm@0 383 frameborder="0" allowfullscreen>
rlm@0 384 </iframe>
rlm@0 385 #+end_html
rlm@0 386
rlm@0 387
rlm@0 388 ** COMMENT failed attempts
rlm@0 389 Let's try the [[http://diracvideo.org/][Dirac]] video encoder.
rlm@0 390
rlm@0 391 #+begin_src sh :results verbatim
rlm@0 392 cd youtube
rlm@0 393 START=$(date +%s)
rlm@0 394 gst-launch-0.10 \
rlm@0 395 filesrc location=./helloPhysics.flv ! decodebin ! \
rlm@0 396 videoscale ! ffmpegcolorspace ! \
rlm@0 397 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
rlm@0 398 schroenc ! filesink location=./helloPhysics.drc > /dev/null
rlm@0 399 echo `expr $(( $(date +%s) - $START))`
rlm@0 400 #+end_src
rlm@0 401
rlm@0 402
rlm@0 403 #+results:
rlm@0 404 : 142
rlm@0 405
rlm@0 406 That took 142 seconds. Let's see how it does compression-wise:
rlm@0 407
rlm@0 408 #+begin_src sh :results verbatim
rlm@0 409 du -h ./youtube/helloPhysics.drc
rlm@0 410 #+end_src
rlm@0 411
rlm@0 412 #+results:
rlm@0 413 : 22M ./physics-videos/helloPhysics.drc
rlm@0 414
rlm@0 415
rlm@0 416 #+begin_src sh :results verbatim
rlm@0 417 cd youtube
rlm@0 418 START=$(date +%s)
rlm@0 419 gst-launch-0.10 \
rlm@0 420 filesrc location=./helloPhysics.flv ! decodebin ! \
rlm@0 421 videoscale ! ffmpegcolorspace ! \
rlm@0 422 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
rlm@0 423 theoraenc ! oggmux ! filesink location=./helloPhysics.ogg \
rlm@0 424 > /dev/null
rlm@0 425 echo `expr $(( $(date +%s) - $START))`
rlm@0 426 #+end_src
rlm@0 427
rlm@0 428 #+results:
rlm@0 429 : 123
rlm@0 430
rlm@0 431 #+begin_src sh :results verbatim
rlm@0 432 du -h youtube/helloPhysics.ogg
rlm@0 433 #+end_src
rlm@0 434
rlm@0 435 #+results:
rlm@0 436 : 59M physics-videos/helloPhysics.ogg
rlm@0 437
rlm@0 438
rlm@0 439 =*.drc= files can not be uploaded to YouTube, so I'll go for the
rlm@0 440 avi file.
rlm@0 441
rlm@0 442
rlm@0 443 ** COMMENT text for videos
rlm@0 444 Video output from JMonkeyEngine3 (www.jmonkeyengine.org/) using Xuggle
rlm@0 445 (www.xuggle.com/). Everything is explained at
rlm@0 446 http://aurellem.org/cortex/capture-video.html.
rlm@0 447
rlm@0 448
rlm@0 449 Video output from JMonkeyEngine3 (www.jmonkeyengine.org/) HelloPhysics
rlm@0 450 demo application using Xuggle (www.xuggle.com/). Everything is
rlm@0 451 explained at http://aurellem.org/cortex/capture-video.html. Here,
rlm@0 452 four points of view are simultaneously recorded and then glued
rlm@0 453 together later.
rlm@0 454
rlm@0 455 JME3 Xuggle Aurellem video capture
rlm@0 456
rlm@0 457
rlm@0 458 * Sample Videos
rlm@0 459 I encoded most of the original JME3 Hello demos for your viewing
rlm@0 460 pleasure, all using the =VideoProcessor= and =IsoTimer= classes.
rlm@0 461
rlm@0 462 ** HelloTerrain
rlm@0 463 [[http://youtu.be/5_4wyDFwrVQ][HelloTerrain.avi]]
rlm@0 464
rlm@0 465 #+begin_html
rlm@0 466 <iframe width="425" height="349"
rlm@0 467 src="http://www.youtube.com/embed/5_4wyDFwrVQ"
rlm@0 468 frameborder="0" allowfullscreen>
rlm@0 469 </iframe>
rlm@0 470 #+end_html
rlm@0 471
rlm@0 472 ** HelloAssets
rlm@0 473 [[http://www.youtube.com/watch?v=oGg-Q6k1BM4][HelloAssets.avi]]
rlm@0 474
rlm@0 475 #+begin_html
rlm@0 476 <iframe width="425" height="349"
rlm@0 477 src="http://www.youtube.com/embed/oGg-Q6k1BM4?hl=en&fs=1"
rlm@0 478 frameborder="0" allowfullscreen>
rlm@0 479 </iframe>
rlm@0 480 #+end_html
rlm@0 481
rlm@0 482 ** HelloEffects
rlm@0 483 [[http://www.youtube.com/watch?v=TuxlLMe53hA][HelloEffects]]
rlm@0 484
rlm@0 485 #+begin_html
rlm@0 486 <iframe width="425" height="349"
rlm@0 487 src="http://www.youtube.com/embed/TuxlLMe53hA?hl=en&fs=1"
rlm@0 488 frameborder="0" allowfullscreen>
rlm@0 489 </iframe>
rlm@0 490 #+end_html
rlm@0 491
rlm@0 492 ** HelloCollision
rlm@0 493 [[http://www.youtube.com/watch?v=GPlvJkiZfFw][HelloCollision.avi]]
rlm@0 494
rlm@0 495 #+begin_html
rlm@0 496 <iframe width="425" height="349"
rlm@0 497 src="http://www.youtube.com/embed/GPlvJkiZfFw?hl=en&fs=1"
rlm@0 498 frameborder="0" allowfullscreen>
rlm@0 499 </iframe>
rlm@0 500 #+end_html
rlm@0 501
rlm@0 502 ** HelloAnimation
rlm@0 503 [[http://www.youtube.com/watch?v=SDCfOSPYUkg][HelloAnimation.avi]]
rlm@0 504
rlm@0 505 #+begin_html
rlm@0 506 <iframe width="425" height="349"
rlm@0 507 src="http://www.youtube.com/embed/SDCfOSPYUkg?hl=en&fs=1"
rlm@0 508 frameborder="0" allowfullscreen>
rlm@0 509 </iframe>
rlm@0 510 #+end_html
rlm@0 511
rlm@0 512 ** HelloNode
rlm@0 513 [[http://www.youtube.com/watch?v=pL-0fR0-ilQ][HelloNode.avi]]
rlm@0 514
rlm@0 515 #+begin_html
rlm@0 516 <iframe width="425" height="349"
rlm@0 517 src="http://www.youtube.com/embed/pL-0fR0-ilQ?hl=en&fs=1"
rlm@0 518 frameborder="0" allowfullscreen>
rlm@0 519 </iframe>
rlm@0 520 #+end_html
rlm@0 521
rlm@0 522 ** HelloLoop
rlm@0 523 [[http://www.youtube.com/watch?v=mosZzzcdE5w][HelloLoop.avi]]
rlm@0 524
rlm@0 525 #+begin_html
rlm@0 526 <iframe width="425" height="349"
rlm@0 527 src="http://www.youtube.com/embed/mosZzzcdE5w?hl=en&fs=1"
rlm@0 528 frameborder="0" allowfullscreen>
rlm@0 529 </iframe>
rlm@0 530 #+end_html
rlm@0 531
rlm@0 532
rlm@0 533 *** COMMENT x-form the other stupid
rlm@0 534 progressreport update-freq=1
rlm@0 535
rlm@0 536 gst-launch-0.10 \
rlm@0 537 filesrc location=./helloPhy ! decodebin ! \
rlm@0 538 videoscale ! ffmpegcolorspace ! \
rlm@0 539 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
rlm@0 540 x264enc ! avimux ! filesink location=helloPhysics.avi \
rlm@0 541
rlm@0 542
rlm@0 543 gst-launch-0.10 \
rlm@0 544 filesrc location=./HelloAnimationStatic.flv ! decodebin ! \
rlm@0 545 videoscale ! ffmpegcolorspace ! \
rlm@0 546 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 547 videobox border-alpha=0 left=-640 ! \
rlm@0 548 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
rlm@0 549 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
rlm@0 550 x264enc ! avimux ! progressreport update-freq=1 ! \
rlm@0 551 filesink location=../youtube/HelloAnimation.avi \
rlm@0 552 \
rlm@0 553 filesrc location=./HelloAnimationMotion.flv ! decodebin ! \
rlm@0 554 videoscale ! ffmpegcolorspace ! \
rlm@0 555 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 556 videobox right=-640 ! mix.
rlm@0 557
rlm@0 558 gst-launch-0.10 \
rlm@0 559 filesrc location=./HelloCollisionMotion.flv ! decodebin ! \
rlm@0 560 videoscale ! ffmpegcolorspace ! \
rlm@0 561 video/x-raw-yuv, width=800, height=600, framerate=25/1 ! \
rlm@0 562 x264enc bitrate=1024 ! avimux ! \
rlm@0 563 filesink location=../youtube/HelloCollision.avi
rlm@0 564
rlm@0 565 gst-launch-0.10 \
rlm@0 566 filesrc location=./HelloEffectsStatic.flv ! decodebin ! \
rlm@0 567 videoscale ! ffmpegcolorspace ! \
rlm@0 568 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 569 videobox border-alpha=0 left=-640 ! \
rlm@0 570 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
rlm@0 571 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
rlm@0 572 x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \
rlm@0 573 filesink location=../youtube/HelloEffects.avi \
rlm@0 574 \
rlm@0 575 filesrc location=./HelloEffectsMotion.flv ! decodebin ! \
rlm@0 576 videoscale ! ffmpegcolorspace ! \
rlm@0 577 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 578 videobox right=-640 ! mix.
rlm@0 579
rlm@0 580 gst-launch-0.10 \
rlm@0 581 filesrc location=./HelloTerrainMotion.flv ! decodebin ! \
rlm@0 582 videoscale ! ffmpegcolorspace ! \
rlm@0 583 video/x-raw-yuv, width=800, height=600, framerate=25/1 ! \
rlm@0 584 x264enc bitrate=1024 ! avimux ! \
rlm@0 585 filesink location=../youtube/HelloTerrain.avi
rlm@0 586
rlm@0 587
rlm@0 588 gst-launch-0.10 \
rlm@0 589 filesrc location=./HelloAssetsStatic.flv ! decodebin ! \
rlm@0 590 videoscale ! ffmpegcolorspace ! \
rlm@0 591 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 592 videobox border-alpha=0 left=-640 ! \
rlm@0 593 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
rlm@0 594 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
rlm@0 595 x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \
rlm@0 596 filesink location=../youtube/HelloAssets.avi \
rlm@0 597 \
rlm@0 598 filesrc location=./HelloAssetsMotion.flv ! decodebin ! \
rlm@0 599 videoscale ! ffmpegcolorspace ! \
rlm@0 600 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 601 videobox right=-640 ! mix.
rlm@0 602
rlm@0 603
rlm@0 604 gst-launch-0.10 \
rlm@0 605 filesrc location=./HelloNodeStatic.flv ! decodebin ! \
rlm@0 606 videoscale ! ffmpegcolorspace ! \
rlm@0 607 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 608 videobox border-alpha=0 left=-640 ! \
rlm@0 609 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
rlm@0 610 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
rlm@0 611 x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \
rlm@0 612 filesink location=../youtube/HelloNode.avi \
rlm@0 613 \
rlm@0 614 filesrc location=./HelloNodeMotion.flv ! decodebin ! \
rlm@0 615 videoscale ! ffmpegcolorspace ! \
rlm@0 616 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 617 videobox right=-640 ! mix.
rlm@0 618
rlm@0 619 gst-launch-0.10 \
rlm@0 620 filesrc location=./HelloLoopStatic.flv ! decodebin ! \
rlm@0 621 videoscale ! ffmpegcolorspace ! \
rlm@0 622 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 623 videobox border-alpha=0 left=-640 ! \
rlm@0 624 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
rlm@0 625 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
rlm@0 626 x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \
rlm@0 627 filesink location=../youtube/HelloLoop.avi \
rlm@0 628 \
rlm@0 629 filesrc location=./HelloLoopMotion.flv ! decodebin ! \
rlm@0 630 videoscale ! ffmpegcolorspace ! \
rlm@0 631 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
rlm@0 632 videobox right=-640 ! mix.
rlm@0 633