Mercurial > cortex
comparison org/capture-video.org @ 573:ebdedb039cbb tip
add release.
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sun, 19 Apr 2015 04:01:53 -0700 |
parents | 7e7f8d6d9ec5 |
children |
comparison
equal
deleted
inserted
replaced
572:202c6d19acad | 573:ebdedb039cbb |
---|---|
23 smooth video output at a constant framerate. | 23 smooth video output at a constant framerate. |
24 | 24 |
25 | 25 |
26 * Video recording requires a steady framerate | 26 * Video recording requires a steady framerate |
27 ** The built-in =Timer= rushes to keep up. | 27 ** The built-in =Timer= rushes to keep up. |
28 #* Game-time vs. User-time vs. Video-time | 28 # * Game-time vs. User-time vs. Video-time |
29 | 29 |
30 Standard JME3 applications use a =Timer= object to manage time in the | 30 Standard JME3 applications use a =Timer= object to manage time in the |
31 simulated world. Because most JME3 applications (e.g. games) are | 31 simulated world. Because most JME3 applications (e.g. games) are |
32 supposed to happen \ldquo{}live\rdquo{}, the built-in =Timer= requires | 32 supposed to happen \ldquo{}live\rdquo{}, the built-in =Timer= requires |
33 simulated time to match real time. This means that the application | 33 simulated time to match real time. This means that the application |
57 # cut corners, giving fast, approximate answers instead of careful, | 57 # cut corners, giving fast, approximate answers instead of careful, |
58 # accurate ones. Although physical accuracy sometimes suffers as a | 58 # accurate ones. Although physical accuracy sometimes suffers as a |
59 # result, this policy ensures that the user will never be kept waiting | 59 # result, this policy ensures that the user will never be kept waiting |
60 # while the computer stops to make a complicated calculation. | 60 # while the computer stops to make a complicated calculation. |
61 | 61 |
62 #fast answers are more important than accurate ones. | 62 # fast answers are more important than accurate ones. |
63 | 63 |
64 # A standard JME3 application that extends =SimpleApplication= or | 64 # A standard JME3 application that extends =SimpleApplication= or |
65 # =Application= tries as hard as it can to keep in sync with | 65 # =Application= tries as hard as it can to keep in sync with |
66 # /user-time/. If a ball is rolling at 1 game-mile per game-hour in | 66 # /user-time/. If a ball is rolling at 1 game-mile per game-hour in |
67 # the game, and you wait for one user-hour as measured by the clock on | 67 # the game, and you wait for one user-hour as measured by the clock on |
176 timer that always reports the same framerate to JME3 every time it is | 176 timer that always reports the same framerate to JME3 every time it is |
177 called. | 177 called. |
178 | 178 |
179 | 179 |
180 =./src/com/aurellem/capture/IsoTimer.java= | 180 =./src/com/aurellem/capture/IsoTimer.java= |
181 #+include ../../jmeCapture/src/com/aurellem/capture/IsoTimer.java src java | 181 #+INCLUDE: "../../jmeCapture/src/com/aurellem/capture/IsoTimer.java" src java |
182 | 182 |
183 If an Application uses this =IsoTimer= instead of the normal one, we | 183 If an Application uses this =IsoTimer= instead of the normal one, we |
184 can be sure that every call to =simpleUpdate=, for example, | 184 can be sure that every call to =simpleUpdate=, for example, |
185 corresponds to exactly $(\frac{1}{fps})$ seconds of game-time. | 185 corresponds to exactly $(\frac{1}{fps})$ seconds of game-time. |
186 | 186 |
200 | 200 |
201 An appropriate interface describing this behavior could look like | 201 An appropriate interface describing this behavior could look like |
202 this: | 202 this: |
203 | 203 |
204 =./src/com/aurellem/capture/video/VideoRecorder.java= | 204 =./src/com/aurellem/capture/video/VideoRecorder.java= |
205 #+include ../../jmeCapture/src/com/aurellem/capture/video/VideoRecorder.java src java | 205 #+include: "../../jmeCapture/src/com/aurellem/capture/video/VideoRecorder.java" src java |
206 | |
207 | 206 |
208 JME3 already provides exactly the class we need: the =SceneProcessor= | 207 JME3 already provides exactly the class we need: the =SceneProcessor= |
209 class can be attached to any viewport and the methods defined therein | 208 class can be attached to any viewport and the methods defined therein |
210 will be called at the appropriate points in the rendering process. | 209 will be called at the appropriate points in the rendering process. |
211 | 210 |
219 | 218 |
220 Here is an AbstractVideoRecorder class that takes care of the details | 219 Here is an AbstractVideoRecorder class that takes care of the details |
221 of setup and teardown. | 220 of setup and teardown. |
222 | 221 |
223 =./src/com/aurellem/capture/video/AbstractVideoRecorder.java= | 222 =./src/com/aurellem/capture/video/AbstractVideoRecorder.java= |
224 #+include ../../jmeCapture/src/com/aurellem/capture/video/AbstractVideoRecorder.java src java | 223 #+include: ../../jmeCapture/src/com/aurellem/capture/video/AbstractVideoRecorder.java src java |
225 | 224 |
226 | 225 |
227 ** There are many options for handling video files in Java | 226 ** There are many options for handling video files in Java |
228 | 227 |
229 If you want to generate video from Java, a great option is [[http://www.xuggle.com/][Xuggle]]. It | 228 If you want to generate video from Java, a great option is [[http://www.xuggle.com/][Xuggle]]. It |
233 | 232 |
234 Here is a =VideoRecorder= that uses [[http://www.xuggle.com/][Xuggle]] to write each frame to a | 233 Here is a =VideoRecorder= that uses [[http://www.xuggle.com/][Xuggle]] to write each frame to a |
235 video file. | 234 video file. |
236 | 235 |
237 =./src/com/aurellem/capture/video/XuggleVideoRecorder.java= | 236 =./src/com/aurellem/capture/video/XuggleVideoRecorder.java= |
238 #+include ../../jmeCapture/src/com/aurellem/capture/video/XuggleVideoRecorder.java src java | 237 #+include: ../../jmeCapture/src/com/aurellem/capture/video/XuggleVideoRecorder.java src java |
239 | 238 |
240 With this, we are able to record video! | 239 With this, we are able to record video! |
241 | 240 |
242 However, it can be hard to properly install Xuggle. If you would | 241 However, it can be hard to properly install Xuggle. If you would |
243 rather not use Xuggle, here is an alternate class that uses [[http://www.randelshofer.ch/blog/2008/08/writing-avi-videos-in-pure-java/][Werner | 242 rather not use Xuggle, here is an alternate class that uses [[http://www.randelshofer.ch/blog/2008/08/writing-avi-videos-in-pure-java/][Werner |
244 Randelshofer's]] excellent pure Java AVI file writer. | 243 Randelshofer's]] excellent pure Java AVI file writer. |
245 | 244 |
246 =./src/com/aurellem/capture/video/AVIVideoRecorder.java= | 245 =./src/com/aurellem/capture/video/AVIVideoRecorder.java= |
247 #+include ../../jmeCapture/src/com/aurellem/capture/video/AVIVideoRecorder.java src java | 246 #+include: ../../jmeCapture/src/com/aurellem/capture/video/AVIVideoRecorder.java src java |
248 | 247 |
249 This =AVIVideoRecorder= is more limited than the | 248 This =AVIVideoRecorder= is more limited than the |
250 =XuggleVideoRecorder=, but requires less external dependencies. | 249 =XuggleVideoRecorder=, but requires less external dependencies. |
251 | 250 |
252 Finally, for those of you who prefer to create the final video from a | 251 Finally, for those of you who prefer to create the final video from a |
254 each frame to a folder as a sequentially numbered image file. Note | 253 each frame to a folder as a sequentially numbered image file. Note |
255 that you have to remember the FPS at which you recorded the video, as | 254 that you have to remember the FPS at which you recorded the video, as |
256 this information is lost when saving each frame to a file. | 255 this information is lost when saving each frame to a file. |
257 | 256 |
258 =./src/com/aurellem/capture/video/FileVideoRecorder.java= | 257 =./src/com/aurellem/capture/video/FileVideoRecorder.java= |
259 #+include ../../jmeCapture/src/com/aurellem/capture/video/FileVideoRecorder.java src java | 258 #+include: ../../jmeCapture/src/com/aurellem/capture/video/FileVideoRecorder.java src java |
260 | |
261 | |
262 | |
263 | 259 |
264 * How to record videos yourself | 260 * How to record videos yourself |
265 | 261 |
266 ** Include this code. | 262 ** Include this code. |
267 | 263 |
341 | 337 |
342 | 338 |
343 I've added support for this under a class called | 339 I've added support for this under a class called |
344 =com.aurellem.capture.Capture=. You can get it [[http://hg.bortreb.com/jmeCapture/][here]]. | 340 =com.aurellem.capture.Capture=. You can get it [[http://hg.bortreb.com/jmeCapture/][here]]. |
345 | 341 |
346 | |
347 ** Hello Video! example | 342 ** Hello Video! example |
348 | 343 |
349 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 | 344 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 |
350 augmented it with video output as follows: | 345 augmented it with video output as follows: |
351 | 346 |
352 =./src/com/aurellem/capture/examples/HelloVideo.java= | 347 =./src/com/aurellem/capture/examples/HelloVideoRecording.java= |
353 #+include ../../src/com/aurellem/capture/examples/HelloVideo.java src java | 348 #+include: ../../jmeCapture/src/com/aurellem/capture/examples/HelloVideoRecording.java src java |
354 | 349 |
355 The videos are created in the =hello-video= directory | 350 The videos are created in the =hello-video= directory |
356 | 351 |
357 #+begin_src sh :results verbatim :exports both | 352 #+begin_src sh :results verbatim :exports both |
358 du -h hello-video/* | 353 du -h hello-video/* |
364 | 359 |
365 And can be immediately uploaded to YouTube | 360 And can be immediately uploaded to YouTube |
366 | 361 |
367 - [[http://www.youtube.com/watch?v=C8gxVAySaPg][hello-video-moving.flv]] | 362 - [[http://www.youtube.com/watch?v=C8gxVAySaPg][hello-video-moving.flv]] |
368 #+BEGIN_HTML | 363 #+BEGIN_HTML |
369 <iframe width="425" height="349" | 364 <iframe width="1062" height="872" |
370 src="http://www.youtube.com/embed/C8gxVAySaPg" | 365 src="http://www.youtube.com/embed/C8gxVAySaPg" |
371 frameborder="0" allowfullscreen> | 366 frameborder="0" allowfullscreen> |
372 </iframe> | 367 </iframe> |
373 #+END_HTML | 368 #+END_HTML |
374 - [[http://www.youtube.com/watch?v=pHcFOtIS07Q][hello-video-static.flv]] | 369 - [[http://www.youtube.com/watch?v=pHcFOtIS07Q][hello-video-static.flv]] |
375 #+BEGIN_HTML | 370 #+BEGIN_HTML |
376 <iframe width="425" height="349" | 371 <iframe width="1062" height="872" |
377 src="http://www.youtube.com/embed/pHcFOtIS07Q" | 372 src="http://www.youtube.com/embed/pHcFOtIS07Q" |
378 frameborder="0" allowfullscreen> | 373 frameborder="0" allowfullscreen> |
379 </iframe> | 374 </iframe> |
380 | |
381 #+END_HTML | 375 #+END_HTML |
382 | 376 |
383 | 377 |
384 * COMMENT More Examples | 378 * COMMENT More Examples |
385 ** COMMENT Hello Physics | 379 ** COMMENT Hello Physics |
389 | 383 |
390 This example is a modified version of =HelloPhysics= that creates four | 384 This example is a modified version of =HelloPhysics= that creates four |
391 simultaneous views of the same scene of cannonballs careening into a | 385 simultaneous views of the same scene of cannonballs careening into a |
392 brick wall. | 386 brick wall. |
393 | 387 |
394 =./jme3/src/test/jme3test/helloworld/HelloPhysicsWithVideo.java= | 388 # =./jme3/src/test/jme3test/helloworld/HelloPhysicsWithVideo.java= |
395 #+include ./jme3/src/test/jme3test/helloworld/HelloPhysicsWithVideo.java src java | 389 # #+include: ./jme3/src/test/jme3test/helloworld/HelloPhysicsWithVideo.java src java |
396 | 390 |
397 Running the program outputs four videos into the =./physics-videos= | 391 Running the program outputs four videos into the =./physics-videos= |
398 directory. | 392 directory. |
399 | 393 |
400 #+begin_src sh :exports both :results verbatim | 394 #+begin_src sh :exports both :results verbatim |
588 | 582 |
589 ** HelloTerrain | 583 ** HelloTerrain |
590 [[http://youtu.be/5_4wyDFwrVQ][HelloTerrain.avi]] | 584 [[http://youtu.be/5_4wyDFwrVQ][HelloTerrain.avi]] |
591 | 585 |
592 #+begin_html | 586 #+begin_html |
593 <iframe width="425" height="349" | 587 <iframe width="1062" height="872" |
594 src="http://www.youtube.com/embed/5_4wyDFwrVQ" | 588 src="http://www.youtube.com/embed/5_4wyDFwrVQ" |
595 frameborder="0" allowfullscreen> | 589 frameborder="0" allowfullscreen> |
596 </iframe> | 590 </iframe> |
597 #+end_html | 591 #+end_html |
598 | 592 |
599 ** HelloAssets | 593 ** HelloAssets |
600 [[http://www.youtube.com/watch?v=oGg-Q6k1BM4][HelloAssets.avi]] | 594 [[http://www.youtube.com/watch?v=oGg-Q6k1BM4][HelloAssets.avi]] |
601 | 595 |
602 #+begin_html | 596 #+begin_html |
603 <iframe width="425" height="349" | 597 <iframe width="1062" height="872" |
604 src="http://www.youtube.com/embed/oGg-Q6k1BM4?hl=en&fs=1" | 598 src="http://www.youtube.com/embed/oGg-Q6k1BM4?hl=en&fs=1" |
605 frameborder="0" allowfullscreen> | 599 frameborder="0" allowfullscreen> |
606 </iframe> | 600 </iframe> |
607 #+end_html | 601 #+end_html |
608 | 602 |
609 ** HelloEffects | 603 ** HelloEffects |
610 [[http://www.youtube.com/watch?v=TuxlLMe53hA][HelloEffects]] | 604 [[http://www.youtube.com/watch?v=TuxlLMe53hA][HelloEffects]] |
611 | 605 |
612 #+begin_html | 606 #+begin_html |
613 <iframe width="425" height="349" | 607 <iframe width="1062" height="872" |
614 src="http://www.youtube.com/embed/TuxlLMe53hA?hl=en&fs=1" | 608 src="http://www.youtube.com/embed/TuxlLMe53hA?hl=en&fs=1" |
615 frameborder="0" allowfullscreen> | 609 frameborder="0" allowfullscreen> |
616 </iframe> | 610 </iframe> |
617 #+end_html | 611 #+end_html |
618 | 612 |
619 ** HelloCollision | 613 ** HelloCollision |
620 [[http://www.youtube.com/watch?v=GPlvJkiZfFw][HelloCollision.avi]] | 614 [[http://www.youtube.com/watch?v=GPlvJkiZfFw][HelloCollision.avi]] |
621 | 615 |
622 #+begin_html | 616 #+begin_html |
623 <iframe width="425" height="349" | 617 <iframe width="1062" height="872" |
624 src="http://www.youtube.com/embed/GPlvJkiZfFw?hl=en&fs=1" | 618 src="http://www.youtube.com/embed/GPlvJkiZfFw?hl=en&fs=1" |
625 frameborder="0" allowfullscreen> | 619 frameborder="0" allowfullscreen> |
626 </iframe> | 620 </iframe> |
627 #+end_html | 621 #+end_html |
628 | 622 |
629 ** HelloAnimation | 623 ** HelloAnimation |
630 [[http://www.youtube.com/watch?v=SDCfOSPYUkg][HelloAnimation.avi]] | 624 [[http://www.youtube.com/watch?v=SDCfOSPYUkg][HelloAnimation.avi]] |
631 | 625 |
632 #+begin_html | 626 #+begin_html |
633 <iframe width="425" height="349" | 627 <iframe width="1062" height="872" |
634 src="http://www.youtube.com/embed/SDCfOSPYUkg?hl=en&fs=1" | 628 src="http://www.youtube.com/embed/SDCfOSPYUkg?hl=en&fs=1" |
635 frameborder="0" allowfullscreen> | |
636 </iframe> | |
637 #+end_html | |
638 | |
639 ** HelloNode | |
640 [[http://www.youtube.com/watch?v=pL-0fR0-ilQ][HelloNode.avi]] | |
641 | |
642 #+begin_html | |
643 <iframe width="425" height="349" | |
644 src="http://www.youtube.com/embed/pL-0fR0-ilQ?hl=en&fs=1" | |
645 frameborder="0" allowfullscreen> | 629 frameborder="0" allowfullscreen> |
646 </iframe> | 630 </iframe> |
647 #+end_html | 631 #+end_html |
648 | 632 |
649 ** HelloLoop | 633 ** HelloLoop |
650 [[http://www.youtube.com/watch?v=mosZzzcdE5w][HelloLoop.avi]] | 634 [[http://www.youtube.com/watch?v=mosZzzcdE5w][HelloLoop.avi]] |
651 | 635 |
652 #+begin_html | 636 #+begin_html |
653 <iframe width="425" height="349" | 637 <iframe width="1062" height="872" |
654 src="http://www.youtube.com/embed/mosZzzcdE5w?hl=en&fs=1" | 638 src="http://www.youtube.com/embed/mosZzzcdE5w?hl=en&fs=1" |
655 frameborder="0" allowfullscreen> | 639 frameborder="0" allowfullscreen> |
656 </iframe> | 640 </iframe> |
657 #+end_html | 641 #+end_html |
658 | 642 |