Mercurial > cortex
view org/capture-video.org @ 302:7e3938f40c52
added winston letter, corrected source listing for integration
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Fri, 17 Feb 2012 13:03:58 -0700 |
parents | 7351c9c0c471 |
children | 7e7f8d6d9ec5 |
line wrap: on
line source
1 #+title: Capture Live Video Feeds from JMonkeyEngine2 #+author: Robert McIntyre3 #+email: rlm@mit.edu4 #+description: Capture video from a JMonkeyEngine3 Application with Xuggle, and use gstreamer to compress the video to upload to YouTube.5 #+keywords: JME3, video, Xuggle, JMonkeyEngine, youtube, capture video, Java6 #+SETUPFILE: ../../aurellem/org/setup.org7 #+INCLUDE: ../../aurellem/org/level-0.org10 * The Problem11 So you've made your cool new JMonkeyEngine3 game and you want to12 create a demo video to show off your hard work. Screen capturing is13 the most straightforward way to do this, but it can slow down your14 game and produce low-quality video as a result. A better way is to15 record a video feed directly from the game while it is running.17 In this post, I'll explain how you can alter your JMonkeyEngine3 game18 to output video while it is running. The main trick is to alter the19 pace of JMonkeyEngine3's in-game time: we allow the engine as much20 time as it needs to compute complicated in-game events and to encode21 video frames. As a result, the game appears to speed up and slow down22 as the computational demands shift, but the end result is perfectly23 smooth video output at a constant framerate.26 * Video recording requires a steady framerate27 ** The built-in =Timer= rushes to keep up.28 #* Game-time vs. User-time vs. Video-time30 Standard JME3 applications use a =Timer= object to manage time in the31 simulated world. Because most JME3 applications (e.g. games) are32 supposed to happen \ldquo{}live\rdquo{}, the built-in =Timer= requires33 simulated time to match real time. This means that the application34 must rush to finish all of its calculations on schedule: the more35 complicated the calculations, the more the application is obligated to36 rush. And if the workload becomes too much to handle on schedule,37 =Timer= forces the application to cut corners: it demands fast,38 approximate answers instead of careful, accurate ones. Although this39 policy sometimes causes physically impossible glitches and choppy40 framerates, it ensures that the user will never be kept waiting while41 the computer stops to make a complicated calculation.43 Now, the built-in =Timer= values speed over accuracy because real-time44 applications require it. On the other hand, if your goal is to record45 a glitch-free video, you need a =Timer= that will take its time to46 ensure that all calculations are accurate, even if they take a long47 time. In the next section, we will create a new kind of48 =Timer=\mdash{}called =IsoTimer=\mdash{}which slows down to let the49 computer finish all its calculations. The result is a perfectly steady50 framerate and a flawless physical simulation.52 # are supposed to happen \ldquo live \rdquo, this =Timer= requires the53 # application to update in real-time. In order to keep up with the54 # real world, JME applications cannot afford to take too much time on55 # expensive computations. Whenever the workload becomes too much for56 # the computer to handle on schedule, =Timer= forces the computer to57 # cut corners, giving fast, approximate answers instead of careful,58 # accurate ones. Although physical accuracy sometimes suffers as a59 # result, this policy ensures that the user will never be kept waiting60 # while the computer stops to make a complicated calculation.62 #fast answers are more important than accurate ones.64 # A standard JME3 application that extends =SimpleApplication= or65 # =Application= tries as hard as it can to keep in sync with66 # /user-time/. If a ball is rolling at 1 game-mile per game-hour in67 # the game, and you wait for one user-hour as measured by the clock on68 # your wall, then the ball should have traveled exactly one69 # game-mile. In order to keep sync with the real world, the game70 # throttles its physics engine and graphics display. If the71 # computations involved in running the game are too intense, then the72 # game will first skip frames, then sacrifice physics accuracy. If73 # there are particuraly demanding computations, then you may only get74 # 1 fps, and the ball may tunnel through the floor or obstacles due to75 # inaccurate physics simulation, but after the end of one user-hour,76 # that ball will have traveled one game-mile.78 # When we're recording video, we don't care if the game-time syncs79 # with user-time, but instead whether the time in the recorded video80 # (video-time) syncs with user-time. To continue the analogy, if we81 # recorded the ball rolling at 1 game-mile per game-hour and watched82 # the video later, we would want to see 30 fps video of the ball83 # rolling at 1 video-mile per /user-hour/. It doesn't matter how much84 # user-time it took to simulate that hour of game-time to make the85 # high-quality recording.86 ** COMMENT Two examples to clarify the point:87 *** Recording from a Simple Simulation89 **** Without a Special Timer90 You have a simulation of a ball rolling on an infinite empty plane at91 one game-mile per game-hour, and a really good computer. Normally,92 JME3 will throttle the physics engine and graphics display to sync the93 game-time with user-time. If it takes one-thousandth of a second94 user-time to simulate one-sixtieth of a second game time and another95 one-thousandth of a second to draw to the screen, then JME3 will just96 sit around for the remainder of $\frac{1}{60} - \frac{2}{1000}$97 user-seconds, then calculate the next frame in $\frac{2}{1000}$98 user-seconds, then wait, and so on. For every second of user time that99 passes, one second of game-time passes, and the game will run at 60100 frames per user-second.103 **** With a Special Timer104 Then, you change the game's timer so that user-time will be synced to105 video-time. Assume that encoding a single frame takes 0 seconds106 user-time to complete.108 Now, JME3 takes advantage of all available resources. It still takes109 one-thousandth of a second to calculate a physics tick, and another110 one-thousandth to render to the screen. Then it takes 0 seconds to111 write the video frame to disk and encode the video. In only one second112 of user time, JME3 will complete 500 physics-tick/render/encode-video113 cycles, and $\frac{500}{60}=8\frac{1}{3}$ seconds of game-time will114 have passed. Game-time appears to dilate $8\frac{1}{3}\times$ with115 respect to user-time, and in only 7.2 minutes user-time, one hour of116 video will have been recorded. The game itself will run at 500 fps.117 When someone watches the video, they will see 60 frames per118 user-second, and $\frac{1}{60}$ video-seconds will pass each frame. It119 will take exactly one hour user-time (and one hour video-time) for the120 ball in the video to travel one video-mile.122 *** Recording from a Complex Simulation124 *** Without a Special Timer125 You have a simulation of a ball rolling on an infinite empty plane at126 one game-mile per game-hour accompanied by multiple explosions127 involving thousands of nodes, particle effects, and complicated shadow128 shaders to create realistic shadows. You also have a slow129 laptop. Normally, JME3 must sacrifice rendering and physics simulation130 to try to keep up. If it takes $\frac{1}{120}$ of a user-second to131 calculate $\frac{1}{60}$ game-seconds, and an additional132 $\frac{1}{60}$ of a user-second to render to screen, then JME3 has133 it's work cut out for it. In order to render to the screen, it will134 first step the game forward by up to four physics ticks before135 rendering to the screen. If it still isn't fast enough then it will136 decrease the accuracy of the physics engine until game-time and user137 time are synched or a certain threshold is reached, at which point the138 game visibly slows down. In this case, JME3 continuously repeat a139 cycle of two physics ticks, and one screen render. For every140 user-second that passes, one game-second will pass, but the game will141 run at 30 fps instead of 60 fps like before.143 *** With a Special Timer144 Then, you change the game's timer so that user-time will be synced to145 video-time. Once again, assume video encoding takes $\frac{1}{60}$ of146 a user-second.148 Now, JME3 will spend $\frac{1}{120}$ of a user-second to step the149 physics tick $\frac{1}{60}$ game-seconds, $\frac{1}{60}$ to draw to150 the screen, and an additional $\frac{1}{60}$ to encode the video and151 write the frame to disk. This is a total of $\frac{1}{24}$152 user-seconds for each $\frac{1}{60}$ game-seconds. It will take153 $(\frac{60}{24} = 2.5)$ user-hours to record one game-hour and154 game-time will appear to flow two-fifths as fast as user time while155 the game is running. However, just as in example one, when all is said156 and done we will have an hour long video at 60 fps.159 ** COMMENT proposed names for the new timer160 # METRONOME161 # IsoTimer162 # EvenTimer163 # PulseTimer164 # FixedTimer165 # RigidTimer166 # FixedTempo167 # RegularTimer168 # MetronomeTimer169 # ConstantTimer170 # SteadyTimer173 ** =IsoTimer= records time like a metronome175 The easiest way to achieve this special timing is to create a new176 timer that always reports the same framerate to JME3 every time it is177 called.180 =./src/com/aurellem/capture/IsoTimer.java=181 #+include ../../jmeCapture/src/com/aurellem/capture/IsoTimer.java src java183 If an Application uses this =IsoTimer= instead of the normal one, we184 can be sure that every call to =simpleUpdate=, for example,185 corresponds to exactly $(\frac{1}{fps})$ seconds of game-time.187 * =VideoRecorder= manages video feeds in JMonkeyEngine.190 ** =AbstractVideoRecorder= provides a general framework for managing videos.192 Now that the issue of time is solved, we just need a function that193 writes each frame to a video. We can put this function somewhere194 where it will be called exactly once per frame.196 The basic functions that a =VideoRecorder= should support are197 recording, starting, stopping, and possibly a cleanup step198 where it finalizes the recording (e.g. by writing headers for a video199 file).201 An appropiate interface describing this behaviour could look like202 this:204 =./src/com/aurellem/capture/video/VideoRecorder.java=205 #+include ../../jmeCapture/src/com/aurellem/capture/video/VideoRecorder.java src java208 JME3 already provides exactly the class we need: the =SceneProcessor=209 class can be attached to any viewport and the methods defined therein210 will be called at the appropriate points in the rendering process.212 However, it is also important to properly close the video stream and213 write headers and such, and even though =SceneProcessor= has a214 =.cleanup()= method, it is only called when the =SceneProcessor= is215 removed from the =RenderManager=, not when the game is shutting down216 when the user pressed ESC, for example. To obtain reliable shutdown217 behaviour, we also have to implement =AppState=, which provides a218 =.cleanup()= method that /is/ called on shutdown.220 Here is an AbstractVideoRecorder class that takes care of the details221 of setup and teardown.223 =./src/com/aurellem/capture/video/AbstractVideoRecorder.java=224 #+include ../../jmeCapture/src/com/aurellem/capture/video/AbstractVideoRecorder.java src java227 ** There are many options for handling video files in Java229 If you want to generate video from Java, a great option is [[http://www.xuggle.com/][Xuggle]]. It230 takes care of everything related to video encoding and decoding and231 runs on Windows, Linux and Mac. Out of all the video frameworks for232 Java, I personally like this one the best.234 Here is a =VideoRecorder= that uses [[http://www.xuggle.com/][Xuggle]] to write each frame to a235 video file.237 =./src/com/aurellem/capture/video/XuggleVideoRecorder.java=238 #+include ../../jmeCapture/src/com/aurellem/capture/video/XuggleVideoRecorder.java src java240 With this, we are able to record video!242 However, it can be hard to properly install Xuggle. If you would243 rather not use Xuggle, here is an alternate class that uses [[http://www.randelshofer.ch/blog/2008/08/writing-avi-videos-in-pure-java/][Werner244 Randelshofer's]] excellent pure Java AVI file writer.246 =./src/com/aurellem/capture/video/AVIVideoRecorder.java=247 #+include ../../jmeCapture/src/com/aurellem/capture/video/AVIVideoRecorder.java src java249 This =AVIVideoRecorder= is more limited than the250 =XuggleVideoRecorder=, but requires less external dependencies.252 Finally, for those of you who prefer to create the final video from a253 sequence of images, there is the =FileVideoRecorder=, which records254 each frame to a folder as a sequentially numbered image file. Note255 that you have to remember the FPS at which you recorded the video, as256 this information is lost when saving each frame to a file.258 =./src/com/aurellem/capture/video/FileVideoRecorder.java=259 #+include ../../jmeCapture/src/com/aurellem/capture/video/FileVideoRecorder.java src java264 * How to record videos yourself266 ** Include this code.268 No matter how complicated your application is, it's easy to add269 support for video output with just a few lines of code.270 # You can also record from multiple ViewPorts as the above example shows.272 And although you can use =VideoRecorder= to record advanced273 split-screen videos with multiple views, in the simplest case, you274 want to capture a single view\mdash{} exactly what's on screen. In275 this case, the following simple =captureVideo= method will do the job:277 #+begin_src java278 public static void captureVideo(final Application app,279 final File file) throws IOException{280 final AbstractVideoRecorder videoRecorder;281 if (file.getCanonicalPath().endsWith(".avi")){282 videoRecorder = new AVIVideoRecorder(file);}283 else if (file.isDirectory()){284 videoRecorder = new FileVideoRecorder(file);}285 else { videoRecorder = new XuggleVideoRecorder(file);}287 Callable<Object> thunk = new Callable<Object>(){288 public Object call(){289 ViewPort viewPort =290 app.getRenderManager()291 .createPostView("aurellem record", app.getCamera());292 viewPort.setClearFlags(false, false, false);293 // get GUI node stuff294 for (Spatial s : app.getGuiViewPort().getScenes()){295 viewPort.attachScene(s);296 }297 app.getStateManager().attach(videoRecorder);298 viewPort.addProcessor(videoRecorder);299 return null;300 }301 };302 app.enqueue(thunk);303 }304 #+end_src306 This method selects the appropriate =VideoRecorder= class for the file307 type you specify, and instructs your application to record video to308 the file.310 Now that you have a =captureVideo= method, you use it like this:312 - Establish an =Isotimer= and set its framerate :: For example, if313 you want to record video with a framerate of 30 fps, include314 the following line of code somewhere in the initializtion of315 your application:316 #+begin_src java :exports code317 this.setTimer(new IsoTimer(30));318 #+end_src320 - Choose the output file :: If you want to record from the game's321 main =ViewPort= to a file called =/home/r/record.flv=, then322 include the following line of code somewhere before you call323 =app.start()=;325 #+begin_src java :exports code326 Capture.captureVideo(app, new File("/home/r/record.flv"));327 #+end_src330 ** Simple example333 This example will record video from the ocean scene from the334 JMonkeyEngine test suite.335 #+begin_src java336 File video = File.createTempFile("JME-water-video", ".avi");337 captureVideo(app, video);338 app.start();339 System.out.println(video.getCanonicalPath());340 #+end_src343 I've added support for this under a class called344 =com.aurellem.capture.Capture=. You can get it [[http://hg.bortreb.com/jmeCapture/][here]].347 ** Hello Video! example349 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=]] and350 augmented it with video output as follows:352 =./src/com/aurellem/capture/examples/HelloVideo.java=353 #+include ../../src/com/aurellem/capture/examples/HelloVideo.java src java355 The videos are created in the =hello-video= directory357 #+begin_src sh :results verbatim :exports both358 du -h hello-video/*359 #+end_src361 #+results:362 : 932K hello-video/hello-video-moving.flv363 : 640K hello-video/hello-video-static.flv365 And can be immediately uploaded to youtube367 - [[http://www.youtube.com/watch?v=C8gxVAySaPg][hello-video-moving.flv]]368 #+BEGIN_HTML369 <iframe width="425" height="349"370 src="http://www.youtube.com/embed/C8gxVAySaPg"371 frameborder="0" allowfullscreen>372 </iframe>373 #+END_HTML374 - [[http://www.youtube.com/watch?v=pHcFOtIS07Q][hello-video-static.flv]]375 #+BEGIN_HTML376 <iframe width="425" height="349"377 src="http://www.youtube.com/embed/pHcFOtIS07Q"378 frameborder="0" allowfullscreen>379 </iframe>381 #+END_HTML384 * COMMENT More Examples385 ** COMMENT Hello Physics387 =HelloVideo= is boring. Let's add some video capturing to388 =HelloPhysics= and create something fun!390 This example is a modified version of =HelloPhysics= that creates four391 simultaneous views of the same scene of cannonballs careening into a392 brick wall.394 =./jme3/src/test/jme3test/helloworld/HelloPhysicsWithVideo.java=395 #+include ./jme3/src/test/jme3test/helloworld/HelloPhysicsWithVideo.java src java397 Running the program outputs four videos into the =./physics-videos=398 directory.400 #+begin_src sh :exports both :results verbatim401 ls ./physics-videos | grep -402 #+end_src404 #+results:405 : lower-left.flv406 : lower-right.flv407 : upper-left.flv408 : upper-right.flv410 The videos are fused together with the following =gstreamer= commands:412 #+begin_src sh :results silent413 cd physics-videos415 gst-launch-0.10 \416 filesrc location=./upper-right.flv ! decodebin ! \417 videoscale ! ffmpegcolorspace ! \418 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \419 videobox border-alpha=0 left=-640 ! \420 videomixer name=mix ! ffmpegcolorspace ! videorate ! \421 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \422 jpegenc ! avimux ! filesink location=upper.flv \423 \424 filesrc location=./upper-left.flv ! decodebin ! \425 videoscale ! ffmpegcolorspace ! \426 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \427 videobox right=-640 ! mix.428 #+end_src430 #+begin_src sh :results silent431 cd physics-videos433 gst-launch-0.10 \434 filesrc location=./lower-left.flv ! decodebin ! \435 videoscale ! ffmpegcolorspace ! \436 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \437 videobox border-alpha=0 left=-640 ! \438 videomixer name=mix ! ffmpegcolorspace ! videorate ! \439 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \440 jpegenc ! avimux ! filesink location=lower.flv \441 \442 filesrc location=./lower-right.flv ! decodebin ! \443 videoscale ! ffmpegcolorspace ! \444 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \445 videobox right=-640 ! mix.446 #+end_src448 #+begin_src sh :results silent449 cd physics-videos451 gst-launch-0.10 \452 filesrc location=./upper.flv ! decodebin ! \453 videoscale ! ffmpegcolorspace ! \454 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \455 videobox border-alpha=0 bottom=-480 ! \456 videomixer name=mix ! ffmpegcolorspace ! videorate ! \457 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \458 jpegenc ! avimux ! filesink location=../youtube/helloPhysics.flv \459 \460 filesrc location=./lower.flv ! decodebin ! \461 videoscale ! ffmpegcolorspace ! \462 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \463 videobox top=-480 ! mix.464 #+end_src466 #+begin_src sh :results verbatim467 du -h youtube/helloPhysics.flv468 #+end_src470 #+results:471 : 180M physics-videos/helloPhysics.flv474 Thats a terribly large size!475 Let's compress it:477 ** COMMENT Compressing the HelloPhysics Video478 First, we'll scale the video, then, we'll decrease it's bitrate. The479 end result will be perfect for upload to YouTube.481 #+begin_src sh :results silent482 cd youtube484 gst-launch-0.10 \485 filesrc location=./helloPhysics.flv ! decodebin ! \486 videoscale ! ffmpegcolorspace ! \487 `: # the original size is 1280 by 960` \488 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \489 videoscale ! \490 `: # here we scale the video down` \491 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \492 `: # and here we limit the bitrate` \493 theoraenc bitrate=1024 quality=30 ! \494 oggmux ! progressreport update-freq=1 ! \495 filesink location=./helloPhysics.ogg496 #+end_src498 #+begin_src sh :results verbatim499 du -h youtube/helloPhysics.ogg500 #+end_src502 #+results:503 : 13M youtube/helloPhysics.ogg505 [[http://www.youtube.com/watch?v=WIJt9aRGusc][helloPhysics.ogg]]507 #+begin_html508 <iframe width="425" height="349"509 src="http://www.youtube.com/embed/WIJt9aRGusc?hl=en&fs=1"510 frameborder="0" allowfullscreen>511 </iframe>512 #+end_html515 ** COMMENT failed attempts516 Let's try the [[http://diracvideo.org/][Dirac]] video encoder.518 #+begin_src sh :results verbatim519 cd youtube520 START=$(date +%s)521 gst-launch-0.10 \522 filesrc location=./helloPhysics.flv ! decodebin ! \523 videoscale ! ffmpegcolorspace ! \524 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \525 schroenc ! filesink location=./helloPhysics.drc > /dev/null526 echo `expr $(( $(date +%s) - $START))`527 #+end_src530 #+results:531 : 142533 That took 142 seconds. Let's see how it does compression-wise:535 #+begin_src sh :results verbatim536 du -h ./youtube/helloPhysics.drc537 #+end_src539 #+results:540 : 22M ./physics-videos/helloPhysics.drc543 #+begin_src sh :results verbatim544 cd youtube545 START=$(date +%s)546 gst-launch-0.10 \547 filesrc location=./helloPhysics.flv ! decodebin ! \548 videoscale ! ffmpegcolorspace ! \549 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \550 theoraenc ! oggmux ! filesink location=./helloPhysics.ogg \551 > /dev/null552 echo `expr $(( $(date +%s) - $START))`553 #+end_src555 #+results:556 : 123558 #+begin_src sh :results verbatim559 du -h youtube/helloPhysics.ogg560 #+end_src562 #+results:563 : 59M physics-videos/helloPhysics.ogg566 =*.drc= files can not be uploaded to YouTube, so I'll go for the567 avi file.570 ** COMMENT text for videos571 Video output from JMonkeyEngine3 (www.jmonkeyengine.org/) using Xuggle572 (www.xuggle.com/). Everything is explained at573 http://aurellem.org/cortex/capture-video.html.576 Video output from JMonkeyEngine3 (www.jmonkeyengine.org/) HelloPhysics577 demo application using Xuggle (www.xuggle.com/). Everything is578 explained at http://aurellem.org/cortex/capture-video.html. Here,579 four points of view are simultaneously recorded and then glued580 together later.582 JME3 Xuggle Aurellem video capture585 * Showcase of recorded videos586 I encoded most of the original JME3 Hello demos for your viewing587 pleasure, all using the =Capture= and =IsoTimer= classes.589 ** HelloTerrain590 [[http://youtu.be/5_4wyDFwrVQ][HelloTerrain.avi]]592 #+begin_html593 <iframe width="425" height="349"594 src="http://www.youtube.com/embed/5_4wyDFwrVQ"595 frameborder="0" allowfullscreen>596 </iframe>597 #+end_html599 ** HelloAssets600 [[http://www.youtube.com/watch?v=oGg-Q6k1BM4][HelloAssets.avi]]602 #+begin_html603 <iframe width="425" height="349"604 src="http://www.youtube.com/embed/oGg-Q6k1BM4?hl=en&fs=1"605 frameborder="0" allowfullscreen>606 </iframe>607 #+end_html609 ** HelloEffects610 [[http://www.youtube.com/watch?v=TuxlLMe53hA][HelloEffects]]612 #+begin_html613 <iframe width="425" height="349"614 src="http://www.youtube.com/embed/TuxlLMe53hA?hl=en&fs=1"615 frameborder="0" allowfullscreen>616 </iframe>617 #+end_html619 ** HelloCollision620 [[http://www.youtube.com/watch?v=GPlvJkiZfFw][HelloCollision.avi]]622 #+begin_html623 <iframe width="425" height="349"624 src="http://www.youtube.com/embed/GPlvJkiZfFw?hl=en&fs=1"625 frameborder="0" allowfullscreen>626 </iframe>627 #+end_html629 ** HelloAnimation630 [[http://www.youtube.com/watch?v=SDCfOSPYUkg][HelloAnimation.avi]]632 #+begin_html633 <iframe width="425" height="349"634 src="http://www.youtube.com/embed/SDCfOSPYUkg?hl=en&fs=1"635 frameborder="0" allowfullscreen>636 </iframe>637 #+end_html639 ** HelloNode640 [[http://www.youtube.com/watch?v=pL-0fR0-ilQ][HelloNode.avi]]642 #+begin_html643 <iframe width="425" height="349"644 src="http://www.youtube.com/embed/pL-0fR0-ilQ?hl=en&fs=1"645 frameborder="0" allowfullscreen>646 </iframe>647 #+end_html649 ** HelloLoop650 [[http://www.youtube.com/watch?v=mosZzzcdE5w][HelloLoop.avi]]652 #+begin_html653 <iframe width="425" height="349"654 src="http://www.youtube.com/embed/mosZzzcdE5w?hl=en&fs=1"655 frameborder="0" allowfullscreen>656 </iframe>657 #+end_html660 *** COMMENT x-form the other stupid661 progressreport update-freq=1663 gst-launch-0.10 \664 filesrc location=./helloPhy ! decodebin ! \665 videoscale ! ffmpegcolorspace ! \666 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \667 x264enc ! avimux ! filesink location=helloPhysics.avi \670 gst-launch-0.10 \671 filesrc location=./HelloAnimationStatic.flv ! decodebin ! \672 videoscale ! ffmpegcolorspace ! \673 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \674 videobox border-alpha=0 left=-640 ! \675 videomixer name=mix ! ffmpegcolorspace ! videorate ! \676 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \677 x264enc ! avimux ! progressreport update-freq=1 ! \678 filesink location=../youtube/HelloAnimation.avi \679 \680 filesrc location=./HelloAnimationMotion.flv ! decodebin ! \681 videoscale ! ffmpegcolorspace ! \682 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \683 videobox right=-640 ! mix.685 gst-launch-0.10 \686 filesrc location=./HelloCollisionMotion.flv ! decodebin ! \687 videoscale ! ffmpegcolorspace ! \688 video/x-raw-yuv, width=800, height=600, framerate=25/1 ! \689 x264enc bitrate=1024 ! avimux ! \690 filesink location=../youtube/HelloCollision.avi692 gst-launch-0.10 \693 filesrc location=./HelloEffectsStatic.flv ! decodebin ! \694 videoscale ! ffmpegcolorspace ! \695 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \696 videobox border-alpha=0 left=-640 ! \697 videomixer name=mix ! ffmpegcolorspace ! videorate ! \698 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \699 x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \700 filesink location=../youtube/HelloEffects.avi \701 \702 filesrc location=./HelloEffectsMotion.flv ! decodebin ! \703 videoscale ! ffmpegcolorspace ! \704 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \705 videobox right=-640 ! mix.707 gst-launch-0.10 \708 filesrc location=./HelloTerrainMotion.flv ! decodebin ! \709 videoscale ! ffmpegcolorspace ! \710 video/x-raw-yuv, width=800, height=600, framerate=25/1 ! \711 x264enc bitrate=1024 ! avimux ! \712 filesink location=../youtube/HelloTerrain.avi715 gst-launch-0.10 \716 filesrc location=./HelloAssetsStatic.flv ! decodebin ! \717 videoscale ! ffmpegcolorspace ! \718 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \719 videobox border-alpha=0 left=-640 ! \720 videomixer name=mix ! ffmpegcolorspace ! videorate ! \721 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \722 x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \723 filesink location=../youtube/HelloAssets.avi \724 \725 filesrc location=./HelloAssetsMotion.flv ! decodebin ! \726 videoscale ! ffmpegcolorspace ! \727 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \728 videobox right=-640 ! mix.731 gst-launch-0.10 \732 filesrc location=./HelloNodeStatic.flv ! decodebin ! \733 videoscale ! ffmpegcolorspace ! \734 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \735 videobox border-alpha=0 left=-640 ! \736 videomixer name=mix ! ffmpegcolorspace ! videorate ! \737 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \738 x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \739 filesink location=../youtube/HelloNode.avi \740 \741 filesrc location=./HelloNodeMotion.flv ! decodebin ! \742 videoscale ! ffmpegcolorspace ! \743 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \744 videobox right=-640 ! mix.746 gst-launch-0.10 \747 filesrc location=./HelloLoopStatic.flv ! decodebin ! \748 videoscale ! ffmpegcolorspace ! \749 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \750 videobox border-alpha=0 left=-640 ! \751 videomixer name=mix ! ffmpegcolorspace ! videorate ! \752 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \753 x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \754 filesink location=../youtube/HelloLoop.avi \755 \756 filesrc location=./HelloLoopMotion.flv ! decodebin ! \757 videoscale ! ffmpegcolorspace ! \758 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \759 videobox right=-640 ! mix.