view 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
line wrap: on
line source
1 #+title: Capture Live Video Feeds from JMonkeyEngine
2 #+author: Robert McIntyre
3 #+email: rlm@mit.edu
4 #+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, Java
6 #+SETUPFILE: ../../aurellem/org/setup.org
7 #+INCLUDE: ../../aurellem/org/level-0.org
10 * The Problem
11 So you've made your cool new JMonkeyEngine3 game and you want to
12 create a demo video to show off your hard work. Screen capturing is
13 the most straightforward way to do this, but it can slow down your
14 game and produce low-quality video as a result. A better way is to
15 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 game
18 to output video while it is running. The main trick is to alter the
19 pace of JMonkeyEngine3's in-game time: we allow the engine as much
20 time as it needs to compute complicated in-game events and to encode
21 video frames. As a result, the game appears to speed up and slow down
22 as the computational demands shift, but the end result is perfectly
23 smooth video output at a constant framerate.
26 * Video recording requires a steady framerate
27 ** The built-in =Timer= rushes to keep up.
28 # * Game-time vs. User-time vs. Video-time
30 Standard JME3 applications use a =Timer= object to manage time in the
31 simulated world. Because most JME3 applications (e.g. games) are
32 supposed to happen \ldquo{}live\rdquo{}, the built-in =Timer= requires
33 simulated time to match real time. This means that the application
34 must rush to finish all of its calculations on schedule: the more
35 complicated the calculations, the more the application is obligated to
36 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 this
39 policy sometimes causes physically impossible glitches and choppy
40 framerates, it ensures that the user will never be kept waiting while
41 the computer stops to make a complicated calculation.
43 Now, the built-in =Timer= values speed over accuracy because real-time
44 applications require it. On the other hand, if your goal is to record
45 a glitch-free video, you need a =Timer= that will take its time to
46 ensure that all calculations are accurate, even if they take a long
47 time. In the next section, we will create a new kind of
48 =Timer=\mdash{}called =IsoTimer=\mdash{}which slows down to let the
49 computer finish all its calculations. The result is a perfectly steady
50 framerate and a flawless physical simulation.
52 # are supposed to happen \ldquo live \rdquo, this =Timer= requires the
53 # application to update in real-time. In order to keep up with the
54 # real world, JME applications cannot afford to take too much time on
55 # expensive computations. Whenever the workload becomes too much for
56 # the computer to handle on schedule, =Timer= forces the computer to
57 # cut corners, giving fast, approximate answers instead of careful,
58 # accurate ones. Although physical accuracy sometimes suffers as a
59 # result, this policy ensures that the user will never be kept waiting
60 # 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= or
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
67 # the game, and you wait for one user-hour as measured by the clock on
68 # your wall, then the ball should have traveled exactly one
69 # game-mile. In order to keep sync with the real world, the game
70 # throttles its physics engine and graphics display. If the
71 # computations involved in running the game are too intense, then the
72 # game will first skip frames, then sacrifice physics accuracy. If
73 # there are particularly demanding computations, then you may only get
74 # 1 fps, and the ball may tunnel through the floor or obstacles due to
75 # 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 syncs
79 # with user-time, but instead whether the time in the recorded video
80 # (video-time) syncs with user-time. To continue the analogy, if we
81 # recorded the ball rolling at 1 game-mile per game-hour and watched
82 # the video later, we would want to see 30 fps video of the ball
83 # rolling at 1 video-mile per /user-hour/. It doesn't matter how much
84 # user-time it took to simulate that hour of game-time to make the
85 # high-quality recording.
86 ** COMMENT Two examples to clarify the point:
87 *** Recording from a Simple Simulation
89 **** Without a Special Timer
90 You have a simulation of a ball rolling on an infinite empty plane at
91 one game-mile per game-hour, and a really good computer. Normally,
92 JME3 will throttle the physics engine and graphics display to sync the
93 game-time with user-time. If it takes one-thousandth of a second
94 user-time to simulate one-sixtieth of a second game time and another
95 one-thousandth of a second to draw to the screen, then JME3 will just
96 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 that
99 passes, one second of game-time passes, and the game will run at 60
100 frames per user-second.
103 **** With a Special Timer
104 Then, you change the game's timer so that user-time will be synced to
105 video-time. Assume that encoding a single frame takes 0 seconds
106 user-time to complete.
108 Now, JME3 takes advantage of all available resources. It still takes
109 one-thousandth of a second to calculate a physics tick, and another
110 one-thousandth to render to the screen. Then it takes 0 seconds to
111 write the video frame to disk and encode the video. In only one second
112 of user time, JME3 will complete 500 physics-tick/render/encode-video
113 cycles, and $\frac{500}{60}=8\frac{1}{3}$ seconds of game-time will
114 have passed. Game-time appears to dilate $8\frac{1}{3}\times$ with
115 respect to user-time, and in only 7.2 minutes user-time, one hour of
116 video will have been recorded. The game itself will run at 500 fps.
117 When someone watches the video, they will see 60 frames per
118 user-second, and $\frac{1}{60}$ video-seconds will pass each frame. It
119 will take exactly one hour user-time (and one hour video-time) for the
120 ball in the video to travel one video-mile.
122 *** Recording from a Complex Simulation
124 *** Without a Special Timer
125 You have a simulation of a ball rolling on an infinite empty plane at
126 one game-mile per game-hour accompanied by multiple explosions
127 involving thousands of nodes, particle effects, and complicated shadow
128 shaders to create realistic shadows. You also have a slow
129 laptop. Normally, JME3 must sacrifice rendering and physics simulation
130 to try to keep up. If it takes $\frac{1}{120}$ of a user-second to
131 calculate $\frac{1}{60}$ game-seconds, and an additional
132 $\frac{1}{60}$ of a user-second to render to screen, then JME3 has
133 it's work cut out for it. In order to render to the screen, it will
134 first step the game forward by up to four physics ticks before
135 rendering to the screen. If it still isn't fast enough then it will
136 decrease the accuracy of the physics engine until game-time and user
137 time are synced or a certain threshold is reached, at which point the
138 game visibly slows down. In this case, JME3 continuously repeat a
139 cycle of two physics ticks, and one screen render. For every
140 user-second that passes, one game-second will pass, but the game will
141 run at 30 fps instead of 60 fps like before.
143 *** With a Special Timer
144 Then, you change the game's timer so that user-time will be synced to
145 video-time. Once again, assume video encoding takes $\frac{1}{60}$ of
146 a user-second.
148 Now, JME3 will spend $\frac{1}{120}$ of a user-second to step the
149 physics tick $\frac{1}{60}$ game-seconds, $\frac{1}{60}$ to draw to
150 the screen, and an additional $\frac{1}{60}$ to encode the video and
151 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 take
153 $(\frac{60}{24} = 2.5)$ user-hours to record one game-hour and
154 game-time will appear to flow two-fifths as fast as user time while
155 the game is running. However, just as in example one, when all is said
156 and done we will have an hour long video at 60 fps.
159 ** COMMENT proposed names for the new timer
160 # METRONOME
161 # IsoTimer
162 # EvenTimer
163 # PulseTimer
164 # FixedTimer
165 # RigidTimer
166 # FixedTempo
167 # RegularTimer
168 # MetronomeTimer
169 # ConstantTimer
170 # SteadyTimer
173 ** =IsoTimer= records time like a metronome
175 The easiest way to achieve this special timing is to create a new
176 timer that always reports the same framerate to JME3 every time it is
177 called.
180 =./src/com/aurellem/capture/IsoTimer.java=
181 #+INCLUDE: "../../jmeCapture/src/com/aurellem/capture/IsoTimer.java" src java
183 If an Application uses this =IsoTimer= instead of the normal one, we
184 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 that
193 writes each frame to a video. We can put this function somewhere
194 where it will be called exactly once per frame.
196 The basic functions that a =VideoRecorder= should support are
197 recording, starting, stopping, and possibly a cleanup step
198 where it finalizes the recording (e.g. by writing headers for a video
199 file).
201 An appropriate interface describing this behavior could look like
202 this:
204 =./src/com/aurellem/capture/video/VideoRecorder.java=
205 #+include: "../../jmeCapture/src/com/aurellem/capture/video/VideoRecorder.java" src java
207 JME3 already provides exactly the class we need: the =SceneProcessor=
208 class can be attached to any viewport and the methods defined therein
209 will be called at the appropriate points in the rendering process.
211 However, it is also important to properly close the video stream and
212 write headers and such, and even though =SceneProcessor= has a
213 =.cleanup()= method, it is only called when the =SceneProcessor= is
214 removed from the =RenderManager=, not when the game is shutting down
215 when the user pressed ESC, for example. To obtain reliable shutdown
216 behavior, we also have to implement =AppState=, which provides a
217 =.cleanup()= method that /is/ called on shutdown.
219 Here is an AbstractVideoRecorder class that takes care of the details
220 of setup and teardown.
222 =./src/com/aurellem/capture/video/AbstractVideoRecorder.java=
223 #+include: ../../jmeCapture/src/com/aurellem/capture/video/AbstractVideoRecorder.java src java
226 ** There are many options for handling video files in Java
228 If you want to generate video from Java, a great option is [[http://www.xuggle.com/][Xuggle]]. It
229 takes care of everything related to video encoding and decoding and
230 runs on Windows, Linux and Mac. Out of all the video frameworks for
231 Java, I personally like this one the best.
233 Here is a =VideoRecorder= that uses [[http://www.xuggle.com/][Xuggle]] to write each frame to a
234 video file.
236 =./src/com/aurellem/capture/video/XuggleVideoRecorder.java=
237 #+include: ../../jmeCapture/src/com/aurellem/capture/video/XuggleVideoRecorder.java src java
239 With this, we are able to record video!
241 However, it can be hard to properly install Xuggle. If you would
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
243 Randelshofer's]] excellent pure Java AVI file writer.
245 =./src/com/aurellem/capture/video/AVIVideoRecorder.java=
246 #+include: ../../jmeCapture/src/com/aurellem/capture/video/AVIVideoRecorder.java src java
248 This =AVIVideoRecorder= is more limited than the
249 =XuggleVideoRecorder=, but requires less external dependencies.
251 Finally, for those of you who prefer to create the final video from a
252 sequence of images, there is the =FileVideoRecorder=, which records
253 each frame to a folder as a sequentially numbered image file. Note
254 that you have to remember the FPS at which you recorded the video, as
255 this information is lost when saving each frame to a file.
257 =./src/com/aurellem/capture/video/FileVideoRecorder.java=
258 #+include: ../../jmeCapture/src/com/aurellem/capture/video/FileVideoRecorder.java src java
260 * How to record videos yourself
262 ** Include this code.
264 No matter how complicated your application is, it's easy to add
265 support for video output with just a few lines of code.
266 # You can also record from multiple ViewPorts as the above example shows.
268 And although you can use =VideoRecorder= to record advanced
269 split-screen videos with multiple views, in the simplest case, you
270 want to capture a single view\mdash{} exactly what's on screen. In
271 this case, the following simple =captureVideo= method will do the job:
273 #+begin_src java
274 public static void captureVideo(final Application app,
275 final File file) throws IOException{
276 final AbstractVideoRecorder videoRecorder;
277 if (file.getCanonicalPath().endsWith(".avi")){
278 videoRecorder = new AVIVideoRecorder(file);}
279 else if (file.isDirectory()){
280 videoRecorder = new FileVideoRecorder(file);}
281 else { videoRecorder = new XuggleVideoRecorder(file);}
283 Callable<Object> thunk = new Callable<Object>(){
284 public Object call(){
285 ViewPort viewPort =
286 app.getRenderManager()
287 .createPostView("aurellem record", app.getCamera());
288 viewPort.setClearFlags(false, false, false);
289 // get GUI node stuff
290 for (Spatial s : app.getGuiViewPort().getScenes()){
291 viewPort.attachScene(s);
292 }
293 app.getStateManager().attach(videoRecorder);
294 viewPort.addProcessor(videoRecorder);
295 return null;
296 }
297 };
298 app.enqueue(thunk);
299 }
300 #+end_src
302 This method selects the appropriate =VideoRecorder= class for the file
303 type you specify, and instructs your application to record video to
304 the file.
306 Now that you have a =captureVideo= method, you use it like this:
308 - Establish an =Isotimer= and set its framerate :: For example, if
309 you want to record video with a framerate of 30 fps, include
310 the following line of code somewhere in the initialization of
311 your application:
312 #+begin_src java :exports code
313 this.setTimer(new IsoTimer(30));
314 #+end_src
316 - Choose the output file :: If you want to record from the game's
317 main =ViewPort= to a file called =/home/r/record.flv=, then
318 include the following line of code somewhere before you call
319 =app.start()=;
321 #+begin_src java :exports code
322 Capture.captureVideo(app, new File("/home/r/record.flv"));
323 #+end_src
326 ** Simple example
329 This example will record video from the ocean scene from the
330 JMonkeyEngine test suite.
331 #+begin_src java
332 File video = File.createTempFile("JME-water-video", ".avi");
333 captureVideo(app, video);
334 app.start();
335 System.out.println(video.getCanonicalPath());
336 #+end_src
339 I've added support for this under a class called
340 =com.aurellem.capture.Capture=. You can get it [[http://hg.bortreb.com/jmeCapture/][here]].
342 ** Hello Video! example
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
345 augmented it with video output as follows:
347 =./src/com/aurellem/capture/examples/HelloVideoRecording.java=
348 #+include: ../../jmeCapture/src/com/aurellem/capture/examples/HelloVideoRecording.java src java
350 The videos are created in the =hello-video= directory
352 #+begin_src sh :results verbatim :exports both
353 du -h hello-video/*
354 #+end_src
356 #+results:
357 : 932K hello-video/hello-video-moving.flv
358 : 640K hello-video/hello-video-static.flv
360 And can be immediately uploaded to YouTube
362 - [[http://www.youtube.com/watch?v=C8gxVAySaPg][hello-video-moving.flv]]
363 #+BEGIN_HTML
364 <iframe width="1062" height="872"
365 src="http://www.youtube.com/embed/C8gxVAySaPg"
366 frameborder="0" allowfullscreen>
367 </iframe>
368 #+END_HTML
369 - [[http://www.youtube.com/watch?v=pHcFOtIS07Q][hello-video-static.flv]]
370 #+BEGIN_HTML
371 <iframe width="1062" height="872"
372 src="http://www.youtube.com/embed/pHcFOtIS07Q"
373 frameborder="0" allowfullscreen>
374 </iframe>
375 #+END_HTML
378 * COMMENT More Examples
379 ** COMMENT Hello Physics
381 =HelloVideo= is boring. Let's add some video capturing to
382 =HelloPhysics= and create something fun!
384 This example is a modified version of =HelloPhysics= that creates four
385 simultaneous views of the same scene of cannonballs careening into a
386 brick wall.
388 # =./jme3/src/test/jme3test/helloworld/HelloPhysicsWithVideo.java=
389 # #+include: ./jme3/src/test/jme3test/helloworld/HelloPhysicsWithVideo.java src java
391 Running the program outputs four videos into the =./physics-videos=
392 directory.
394 #+begin_src sh :exports both :results verbatim
395 ls ./physics-videos | grep -
396 #+end_src
398 #+results:
399 : lower-left.flv
400 : lower-right.flv
401 : upper-left.flv
402 : upper-right.flv
404 The videos are fused together with the following =gstreamer= commands:
406 #+begin_src sh :results silent
407 cd physics-videos
409 gst-launch-0.10 \
410 filesrc location=./upper-right.flv ! decodebin ! \
411 videoscale ! ffmpegcolorspace ! \
412 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
413 videobox border-alpha=0 left=-640 ! \
414 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
415 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
416 jpegenc ! avimux ! filesink location=upper.flv \
417 \
418 filesrc location=./upper-left.flv ! decodebin ! \
419 videoscale ! ffmpegcolorspace ! \
420 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
421 videobox right=-640 ! mix.
422 #+end_src
424 #+begin_src sh :results silent
425 cd physics-videos
427 gst-launch-0.10 \
428 filesrc location=./lower-left.flv ! decodebin ! \
429 videoscale ! ffmpegcolorspace ! \
430 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
431 videobox border-alpha=0 left=-640 ! \
432 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
433 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
434 jpegenc ! avimux ! filesink location=lower.flv \
435 \
436 filesrc location=./lower-right.flv ! decodebin ! \
437 videoscale ! ffmpegcolorspace ! \
438 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
439 videobox right=-640 ! mix.
440 #+end_src
442 #+begin_src sh :results silent
443 cd physics-videos
445 gst-launch-0.10 \
446 filesrc location=./upper.flv ! decodebin ! \
447 videoscale ! ffmpegcolorspace ! \
448 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
449 videobox border-alpha=0 bottom=-480 ! \
450 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
451 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
452 jpegenc ! avimux ! filesink location=../youtube/helloPhysics.flv \
453 \
454 filesrc location=./lower.flv ! decodebin ! \
455 videoscale ! ffmpegcolorspace ! \
456 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
457 videobox top=-480 ! mix.
458 #+end_src
460 #+begin_src sh :results verbatim
461 du -h youtube/helloPhysics.flv
462 #+end_src
464 #+results:
465 : 180M physics-videos/helloPhysics.flv
468 That's a terribly large size!
469 Let's compress it:
471 ** COMMENT Compressing the HelloPhysics Video
472 First, we'll scale the video, then, we'll decrease it's bit-rate. The
473 end result will be perfect for upload to YouTube.
475 #+begin_src sh :results silent
476 cd youtube
478 gst-launch-0.10 \
479 filesrc location=./helloPhysics.flv ! decodebin ! \
480 videoscale ! ffmpegcolorspace ! \
481 `: # the original size is 1280 by 960` \
482 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
483 videoscale ! \
484 `: # here we scale the video down` \
485 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
486 `: # and here we limit the bitrate` \
487 theoraenc bitrate=1024 quality=30 ! \
488 oggmux ! progressreport update-freq=1 ! \
489 filesink location=./helloPhysics.ogg
490 #+end_src
492 #+begin_src sh :results verbatim
493 du -h youtube/helloPhysics.ogg
494 #+end_src
496 #+results:
497 : 13M youtube/helloPhysics.ogg
499 [[http://www.youtube.com/watch?v=WIJt9aRGusc][helloPhysics.ogg]]
501 #+begin_html
502 <iframe width="425" height="349"
503 src="http://www.youtube.com/embed/WIJt9aRGusc?hl=en&fs=1"
504 frameborder="0" allowfullscreen>
505 </iframe>
506 #+end_html
509 ** COMMENT failed attempts
510 Let's try the [[http://diracvideo.org/][Dirac]] video encoder.
512 #+begin_src sh :results verbatim
513 cd youtube
514 START=$(date +%s)
515 gst-launch-0.10 \
516 filesrc location=./helloPhysics.flv ! decodebin ! \
517 videoscale ! ffmpegcolorspace ! \
518 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
519 schroenc ! filesink location=./helloPhysics.drc > /dev/null
520 echo `expr $(( $(date +%s) - $START))`
521 #+end_src
524 #+results:
525 : 142
527 That took 142 seconds. Let's see how it does compression-wise:
529 #+begin_src sh :results verbatim
530 du -h ./youtube/helloPhysics.drc
531 #+end_src
533 #+results:
534 : 22M ./physics-videos/helloPhysics.drc
537 #+begin_src sh :results verbatim
538 cd youtube
539 START=$(date +%s)
540 gst-launch-0.10 \
541 filesrc location=./helloPhysics.flv ! decodebin ! \
542 videoscale ! ffmpegcolorspace ! \
543 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
544 theoraenc ! oggmux ! filesink location=./helloPhysics.ogg \
545 > /dev/null
546 echo `expr $(( $(date +%s) - $START))`
547 #+end_src
549 #+results:
550 : 123
552 #+begin_src sh :results verbatim
553 du -h youtube/helloPhysics.ogg
554 #+end_src
556 #+results:
557 : 59M physics-videos/helloPhysics.ogg
560 =*.drc= files can not be uploaded to YouTube, so I'll go for the
561 avi file.
564 ** COMMENT text for videos
565 Video output from JMonkeyEngine3 (www.jmonkeyengine.org/) using Xuggle
566 (www.xuggle.com/). Everything is explained at
567 http://aurellem.org/cortex/capture-video.html.
570 Video output from JMonkeyEngine3 (www.jmonkeyengine.org/) HelloPhysics
571 demo application using Xuggle (www.xuggle.com/). Everything is
572 explained at http://aurellem.org/cortex/capture-video.html. Here,
573 four points of view are simultaneously recorded and then glued
574 together later.
576 JME3 Xuggle Aurellem video capture
579 * Showcase of recorded videos
580 I encoded most of the original JME3 Hello demos for your viewing
581 pleasure, all using the =Capture= and =IsoTimer= classes.
583 ** HelloTerrain
584 [[http://youtu.be/5_4wyDFwrVQ][HelloTerrain.avi]]
586 #+begin_html
587 <iframe width="1062" height="872"
588 src="http://www.youtube.com/embed/5_4wyDFwrVQ"
589 frameborder="0" allowfullscreen>
590 </iframe>
591 #+end_html
593 ** HelloAssets
594 [[http://www.youtube.com/watch?v=oGg-Q6k1BM4][HelloAssets.avi]]
596 #+begin_html
597 <iframe width="1062" height="872"
598 src="http://www.youtube.com/embed/oGg-Q6k1BM4?hl=en&fs=1"
599 frameborder="0" allowfullscreen>
600 </iframe>
601 #+end_html
603 ** HelloEffects
604 [[http://www.youtube.com/watch?v=TuxlLMe53hA][HelloEffects]]
606 #+begin_html
607 <iframe width="1062" height="872"
608 src="http://www.youtube.com/embed/TuxlLMe53hA?hl=en&fs=1"
609 frameborder="0" allowfullscreen>
610 </iframe>
611 #+end_html
613 ** HelloCollision
614 [[http://www.youtube.com/watch?v=GPlvJkiZfFw][HelloCollision.avi]]
616 #+begin_html
617 <iframe width="1062" height="872"
618 src="http://www.youtube.com/embed/GPlvJkiZfFw?hl=en&fs=1"
619 frameborder="0" allowfullscreen>
620 </iframe>
621 #+end_html
623 ** HelloAnimation
624 [[http://www.youtube.com/watch?v=SDCfOSPYUkg][HelloAnimation.avi]]
626 #+begin_html
627 <iframe width="1062" height="872"
628 src="http://www.youtube.com/embed/SDCfOSPYUkg?hl=en&fs=1"
629 frameborder="0" allowfullscreen>
630 </iframe>
631 #+end_html
633 ** HelloLoop
634 [[http://www.youtube.com/watch?v=mosZzzcdE5w][HelloLoop.avi]]
636 #+begin_html
637 <iframe width="1062" height="872"
638 src="http://www.youtube.com/embed/mosZzzcdE5w?hl=en&fs=1"
639 frameborder="0" allowfullscreen>
640 </iframe>
641 #+end_html
644 *** COMMENT x-form the other stupid
645 progressreport update-freq=1
647 gst-launch-0.10 \
648 filesrc location=./helloPhy ! decodebin ! \
649 videoscale ! ffmpegcolorspace ! \
650 video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
651 x264enc ! avimux ! filesink location=helloPhysics.avi \
654 gst-launch-0.10 \
655 filesrc location=./HelloAnimationStatic.flv ! decodebin ! \
656 videoscale ! ffmpegcolorspace ! \
657 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
658 videobox border-alpha=0 left=-640 ! \
659 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
660 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
661 x264enc ! avimux ! progressreport update-freq=1 ! \
662 filesink location=../youtube/HelloAnimation.avi \
663 \
664 filesrc location=./HelloAnimationMotion.flv ! decodebin ! \
665 videoscale ! ffmpegcolorspace ! \
666 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
667 videobox right=-640 ! mix.
669 gst-launch-0.10 \
670 filesrc location=./HelloCollisionMotion.flv ! decodebin ! \
671 videoscale ! ffmpegcolorspace ! \
672 video/x-raw-yuv, width=800, height=600, framerate=25/1 ! \
673 x264enc bitrate=1024 ! avimux ! \
674 filesink location=../youtube/HelloCollision.avi
676 gst-launch-0.10 \
677 filesrc location=./HelloEffectsStatic.flv ! decodebin ! \
678 videoscale ! ffmpegcolorspace ! \
679 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
680 videobox border-alpha=0 left=-640 ! \
681 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
682 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
683 x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \
684 filesink location=../youtube/HelloEffects.avi \
685 \
686 filesrc location=./HelloEffectsMotion.flv ! decodebin ! \
687 videoscale ! ffmpegcolorspace ! \
688 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
689 videobox right=-640 ! mix.
691 gst-launch-0.10 \
692 filesrc location=./HelloTerrainMotion.flv ! decodebin ! \
693 videoscale ! ffmpegcolorspace ! \
694 video/x-raw-yuv, width=800, height=600, framerate=25/1 ! \
695 x264enc bitrate=1024 ! avimux ! \
696 filesink location=../youtube/HelloTerrain.avi
699 gst-launch-0.10 \
700 filesrc location=./HelloAssetsStatic.flv ! decodebin ! \
701 videoscale ! ffmpegcolorspace ! \
702 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
703 videobox border-alpha=0 left=-640 ! \
704 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
705 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
706 x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \
707 filesink location=../youtube/HelloAssets.avi \
708 \
709 filesrc location=./HelloAssetsMotion.flv ! decodebin ! \
710 videoscale ! ffmpegcolorspace ! \
711 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
712 videobox right=-640 ! mix.
715 gst-launch-0.10 \
716 filesrc location=./HelloNodeStatic.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/HelloNode.avi \
724 \
725 filesrc location=./HelloNodeMotion.flv ! decodebin ! \
726 videoscale ! ffmpegcolorspace ! \
727 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
728 videobox right=-640 ! mix.
730 gst-launch-0.10 \
731 filesrc location=./HelloLoopStatic.flv ! decodebin ! \
732 videoscale ! ffmpegcolorspace ! \
733 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
734 videobox border-alpha=0 left=-640 ! \
735 videomixer name=mix ! ffmpegcolorspace ! videorate ! \
736 video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
737 x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \
738 filesink location=../youtube/HelloLoop.avi \
739 \
740 filesrc location=./HelloLoopMotion.flv ! decodebin ! \
741 videoscale ! ffmpegcolorspace ! \
742 video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
743 videobox right=-640 ! mix.