view org/capture-video.org @ 303:35d9e7d04d87

Added cover sheet for Winston yay
author Dylan Holmes <ocsenave@gmail.com>
date Sat, 18 Feb 2012 02:06:06 -0600
parents da4de661c5d9
children 301e91a6c2d1
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
16 running.
18 In this post, I'll explain how you can alter your JMonkeyEngine3 game
19 to output video while it is running. The main trick is to alter the
20 pace of JMonkeyEngine3's in-game time: we allow the engine as much
21 time as it needs to compute complicated in-game events and to encode
22 video frames. As a result, the game appears to speed up and slow down
23 as the computational demands shift, but the end result is perfectly
24 smooth video output at a constant framerate.
27 * Video recording requires a steady framerate
28 ** The built-in =Timer= rushes to keep up.
29 #* Game-time vs. User-time vs. Video-time
31 Standard JME3 applications use a =Timer= object to manage time
32 in the simulated world. Because most JME3 applications (e.g. games)
33 are supposed to happen \ldquo{}live\rdquo{}, the built-in =Timer=
34 requires simulated time to match real time. This means that the
35 application must rush to finish all of its calculations on
36 schedule: the more complicated the calculations, the more the
37 application is obligated to rush. And if the workload becomes too
38 much to handle on schedule, =Timer= forces the application to cut
39 corners: it demands fast, approximate answers instead of careful,
40 accurate ones. Although this policy sometimes causes physically impossible
41 glitches and choppy framerates, it ensures that the user will never be
42 kept waiting while the computer stops to make a complicated
43 calculation.
45 Now, the built-in =Timer= values speed over accuracy because real-time
46 applications require it. On the other hand, if your goal is to record a
47 glitch-free video, you need a =Timer= that will take its time to
48 ensure that all calculations are accurate, even if they take a long time. In the next section, we
49 will create a new kind of =Timer=\mdash{}called =IsoTimer=\mdash{}which
50 slows down to let the computer finish all its calculations. The result
51 is a perfectly steady framerate and a flawless physical simulation.
53 # are supposed to happen \ldquo live \rdquo, this =Timer= requires the
54 # application to update in real-time. In order to keep up with the real world, JME applications cannot
55 # afford to take too much time on expensive computations. Whenever the
56 # workload becomes too much for the computer to handle on schedule,
57 # =Timer= forces the computer to cut corners, giving fast, approximate
58 # answers instead of careful, accurate ones. Although physical accuracy sometimes
59 # suffers as a result, this policy ensures that the user will never be
60 # kept waiting while the computer stops to make a complicated
61 # calculation.
63 #fast answers are more important than accurate ones.
65 # A standard JME3 application that extends =SimpleApplication= or
66 # =Application= tries as hard as it can to keep in sync with
67 # /user-time/. If a ball is rolling at 1 game-mile per game-hour in the
68 # game, and you wait for one user-hour as measured by the clock on your
69 # wall, then the ball should have traveled exactly one game-mile. In
70 # order to keep sync with the real world, the game throttles its physics
71 # engine and graphics display. If the computations involved in running
72 # the game are too intense, then the game will first skip frames, then
73 # sacrifice physics accuracy. If there are particuraly demanding
74 # computations, then you may only get 1 fps, and the ball may tunnel
75 # through the floor or obstacles due to inaccurate physics simulation,
76 # but after the end of one user-hour, that ball will have traveled one
77 # game-mile.
79 # When we're recording video, we don't care if the game-time syncs with
80 # user-time, but instead whether the time in the recorded video
81 # (video-time) syncs with user-time. To continue the analogy, if we
82 # recorded the ball rolling at 1 game-mile per game-hour and watched the
83 # video later, we would want to see 30 fps video of the ball rolling at
84 # 1 video-mile per /user-hour/. It doesn't matter how much user-time it
85 # took to simulate that hour of game-time to make the high-quality
86 # recording.
87 ** COMMENT Two examples to clarify the point:
88 *** Recording from a Simple Simulation
90 **** Without a Special Timer
91 You have a simulation of a ball rolling on an infinite empty plane at
92 one game-mile per game-hour, and a really good computer. Normally,
93 JME3 will throttle the physics engine and graphics display to sync the
94 game-time with user-time. If it takes one-thousandth of a second
95 user-time to simulate one-sixtieth of a second game time and another
96 one-thousandth of a second to draw to the screen, then JME3 will just
97 sit around for the remainder of $\frac{1}{60} - \frac{2}{1000}$
98 user-seconds, then calculate the next frame in $\frac{2}{1000}$
99 user-seconds, then wait, and so on. For every second of user time that
100 passes, one second of game-time passes, and the game will run at 60
101 frames per user-second.
104 **** With a Special Timer
105 Then, you change the game's timer so that user-time will be synced to
106 video-time. Assume that encoding a single frame takes 0 seconds
107 user-time to complete.
109 Now, JME3 takes advantage of all available resources. It still takes
110 one-thousandth of a second to calculate a physics tick, and another
111 one-thousandth to render to the screen. Then it takes 0 seconds to
112 write the video frame to disk and encode the video. In only one second
113 of user time, JME3 will complete 500 physics-tick/render/encode-video
114 cycles, and $\frac{500}{60}=8\frac{1}{3}$ seconds of game-time will
115 have passed. Game-time appears to dilate $8\frac{1}{3}\times$ with
116 respect to user-time, and in only 7.2 minutes user-time, one hour of
117 video will have been recorded. The game itself will run at 500 fps.
118 When someone watches the video, they will see 60 frames per
119 user-second, and $\frac{1}{60}$ video-seconds will pass each frame. It
120 will take exactly one hour user-time (and one hour video-time) for the
121 ball in the video to travel one video-mile.
123 *** Recording from a Complex Simulation
125 *** Without a Special Timer
126 You have a simulation of a ball rolling on an infinite empty plane at
127 one game-mile per game-hour accompanied by multiple explosions
128 involving thousands of nodes, particle effects, and complicated shadow
129 shaders to create realistic shadows. You also have a slow
130 laptop. Normally, JME3 must sacrifice rendering and physics simulation
131 to try to keep up. If it takes $\frac{1}{120}$ of a user-second to
132 calculate $\frac{1}{60}$ game-seconds, and an additional
133 $\frac{1}{60}$ of a user-second to render to screen, then JME3 has
134 it's work cut out for it. In order to render to the screen, it will
135 first step the game forward by up to four physics ticks before
136 rendering to the screen. If it still isn't fast enough then it will
137 decrease the accuracy of the physics engine until game-time and user
138 time are synched or a certain threshold is reached, at which point the
139 game visibly slows down. In this case, JME3 continuously repeat a
140 cycle of two physics ticks, and one screen render. For every
141 user-second that passes, one game-second will pass, but the game will
142 run at 30 fps instead of 60 fps like before.
144 *** With a Special Timer
145 Then, you change the game's timer so that user-time will be synced to
146 video-time. Once again, assume video encoding takes $\frac{1}{60}$ of
147 a user-second.
149 Now, JME3 will spend $\frac{1}{120}$ of a user-second to step the
150 physics tick $\frac{1}{60}$ game-seconds, $\frac{1}{60}$ to draw to
151 the screen, and an additional $\frac{1}{60}$ to encode the video and
152 write the frame to disk. This is a total of $\frac{1}{24}$
153 user-seconds for each $\frac{1}{60}$ game-seconds. It will take
154 $(\frac{60}{24} = 2.5)$ user-hours to record one game-hour and game-time
155 will appear to flow two-fifths as fast as user time while the game is
156 running. However, just as in example one, when all is said and done we
157 will have an hour long video at 60 fps.
160 ** COMMENT proposed names for the new timer
161 # METRONOME
162 # IsoTimer
163 # EvenTimer
164 # PulseTimer
165 # FixedTimer
166 # RigidTimer
167 # FixedTempo
168 # RegularTimer
169 # MetronomeTimer
170 # ConstantTimer
171 # SteadyTimer
174 ** =IsoTimer= records time like a metronome
176 The easiest way to achieve this special timing is to create a new
177 timer that always reports the same framerate to JME3 every time it is
178 called.
181 =./src/com/aurellem/capture/IsoTimer.java=
182 #+include ../../jmeCapture/src/com/aurellem/capture/IsoTimer.java src java
184 If an Application uses this =IsoTimer= instead of the normal one, we
185 can be sure that every call to =simpleUpdate=, for example, corresponds
186 to exactly $(\frac{1}{fps})$ seconds of game-time.
188 * =VideoRecorder= manages video feeds in JMonkeyEngine.
191 ** =AbstractVideoRecorder= provides a general framework for managing videos.
193 Now that the issue of time is solved, we just need a function that
194 writes each frame to a video. We can put this function somewhere
195 where it will be called exactly once per frame.
197 The basic functions that a =VideoRecorder= should support are
198 recording, starting, stopping, and possibly a cleanup step
199 where it finalizes the recording (e.g. by writing headers for a video
200 file).
202 An appropiate interface describing this behaviour could look like
203 this:
205 =./src/com/aurellem/capture/video/VideoRecorder.java=
206 #+include ../../jmeCapture/src/com/aurellem/capture/video/VideoRecorder.java src java
209 JME3 already provides exactly the class we need: the =SceneProcessor=
210 class can be attached to any viewport and the methods defined therein
211 will be called at the appropriate points in the rendering process.
213 However, it is also important to properly close the video stream and
214 write headers and such, and even though =SceneProcessor= has a
215 =.cleanup()= method, it is only called when the =SceneProcessor= is
216 removed from the =RenderManager=, not when the game is shutting down
217 when the user pressed ESC, for example. To obtain reliable shutdown
218 behaviour, we also have to implement =AppState=, which provides a
219 =.cleanup()= method that /is/ called on shutdown.
221 Here is an AbstractVideoRecorder class that takes care of the details
222 of setup and teardown.
224 =./src/com/aurellem/capture/video/AbstractVideoRecorder.java=
225 #+include ../../jmeCapture/src/com/aurellem/capture/video/AbstractVideoRecorder.java src java
228 ** There are many options for handling video files in Java
230 If you want to generate video from Java, a great option is [[http://www.xuggle.com/][Xuggle]]. It
231 takes care of everything related to video encoding and decoding and
232 runs on Windows, Linux and Mac. Out of all the video frameworks for
233 Java, I personally like this one the best.
235 Here is a =VideoRecorder= that uses [[http://www.xuggle.com/][Xuggle]] to write each frame to a
236 video file.
238 =./src/com/aurellem/capture/video/XuggleVideoRecorder.java=
239 #+include ../../jmeCapture/src/com/aurellem/capture/video/XuggleVideoRecorder.java src java
241 With this, we are able to record video!
243 However, it can be hard to properly install Xuggle. If you would rather not use Xuggle, here is an alternate class that uses
244 [[http://www.randelshofer.ch/blog/2008/08/writing-avi-videos-in-pure-java/][Werner 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 java
249 This =AVIVideoRecorder= is more limited than the
250 =XuggleVideoRecorder=, but requires less external dependencies.
252 Finally, for those of you who prefer to create the final video from a
253 sequence of images, there is the =FileVideoRecorder=, which records
254 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
256 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 java
264 * How to record videos yourself
266 ** Include this code.
268 No matter how complicated your application is, it's easy to add
269 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 advanced split-screen videos with multiple views, in the simplest case, you want to capture a single view\mdash{}
273 exactly what's on screen. In this case, the following simple =captureVideo=
274 method will do the job:
276 #+begin_src java
277 public static void captureVideo(final Application app,
278 final File file) throws IOException{
279 final AbstractVideoRecorder videoRecorder;
280 if (file.getCanonicalPath().endsWith(".avi")){
281 videoRecorder = new AVIVideoRecorder(file);}
282 else if (file.isDirectory()){
283 videoRecorder = new FileVideoRecorder(file);}
284 else { videoRecorder = new XuggleVideoRecorder(file);}
286 Callable<Object> thunk = new Callable<Object>(){
287 public Object call(){
288 ViewPort viewPort =
289 app.getRenderManager()
290 .createPostView("aurellem record", app.getCamera());
291 viewPort.setClearFlags(false, false, false);
292 // get GUI node stuff
293 for (Spatial s : app.getGuiViewPort().getScenes()){
294 viewPort.attachScene(s);
295 }
296 app.getStateManager().attach(videoRecorder);
297 viewPort.addProcessor(videoRecorder);
298 return null;
299 }
300 };
301 app.enqueue(thunk);
302 }
303 #+end_src
305 This method selects the appropriate =VideoRecorder= class
306 for the file type you specify, and instructs your
307 application to record video to the file.
312 Now that you have a =captureVideo= method, you use it like this:
314 - Establish an =Isotimer= and set its framerate :: For example, if
315 you want to record video with a framerate of 30 fps, include
316 the following line of code somewhere in the initializtion of
317 your application:
318 #+begin_src java :exports code
319 this.setTimer(new IsoTimer(30));
320 #+end_src
322 - Choose the output file :: If you want to record from the game's
323 main =ViewPort= to a file called =/home/r/record.flv=, then
324 include the following line of code somewhere before you call =app.start()=;
326 #+begin_src java :exports code
327 Capture.captureVideo(app, new File("/home/r/record.flv"));
328 #+end_src
331 ** Simple example
334 This example will record video from the ocean scene from the
335 JMonkeyEngine test suite.
336 #+begin_src java
337 File video = File.createTempFile("JME-water-video", ".avi");
338 captureVideo(app, video);
339 app.start();
340 System.out.println(video.getCanonicalPath());
341 #+end_src
344 I've added support for this under a class called
345 =com.aurellem.capture.Capture=. You can get it [[http://hg.bortreb.com/jmeCapture/][here]].
348 ** Hello Video! example
350 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
351 augmented it with video output as follows:
353 =./src/com/aurellem/capture/examples/HelloVideo.java=
354 #+include ../../src/com/aurellem/capture/examples/HelloVideo.java src java
356 The videos are created in the =hello-video= directory
358 #+begin_src sh :results verbatim :exports both
359 du -h hello-video/*
360 #+end_src
362 #+results:
363 : 932K hello-video/hello-video-moving.flv
364 : 640K hello-video/hello-video-static.flv
366 And can be immediately uploaded to youtube
368 - [[http://www.youtube.com/watch?v=C8gxVAySaPg][hello-video-moving.flv]]
369 #+BEGIN_HTML
370 <iframe width="425" height="349"
371 src="http://www.youtube.com/embed/C8gxVAySaPg"
372 frameborder="0" allowfullscreen>
373 </iframe>
374 #+END_HTML
375 - [[http://www.youtube.com/watch?v=pHcFOtIS07Q][hello-video-static.flv]]
376 #+BEGIN_HTML
377 <iframe width="425" height="349"
378 src="http://www.youtube.com/embed/pHcFOtIS07Q"
379 frameborder="0" allowfullscreen>
380 </iframe>
382 #+END_HTML
385 * COMMENT More Examples
386 ** COMMENT Hello Physics
387 =HelloVideo= is boring. Let's add some video capturing to =HelloPhysics=
388 and create something fun!
390 This example is a modified version of =HelloPhysics= that creates four
391 simultaneous views of the same scene of cannonballs careening into a
392 brick wall.
394 =./jme3/src/test/jme3test/helloworld/HelloPhysicsWithVideo.java=
395 #+include ./jme3/src/test/jme3test/helloworld/HelloPhysicsWithVideo.java src java
397 Running the program outputs four videos into the =./physics-videos=
398 directory.
400 #+begin_src sh :exports both :results verbatim
401 ls ./physics-videos | grep -
402 #+end_src
404 #+results:
405 : lower-left.flv
406 : lower-right.flv
407 : upper-left.flv
408 : upper-right.flv
410 The videos are fused together with the following =gstreamer= commands:
412 #+begin_src sh :results silent
413 cd physics-videos
415 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_src
430 #+begin_src sh :results silent
431 cd physics-videos
433 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_src
448 #+begin_src sh :results silent
449 cd physics-videos
451 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_src
466 #+begin_src sh :results verbatim
467 du -h youtube/helloPhysics.flv
468 #+end_src
470 #+results:
471 : 180M physics-videos/helloPhysics.flv
474 Thats a terribly large size!
475 Let's compress it:
477 ** COMMENT Compressing the HelloPhysics Video
478 First, we'll scale the video, then, we'll decrease it's bitrate. The
479 end result will be perfect for upload to YouTube.
481 #+begin_src sh :results silent
482 cd youtube
484 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.ogg
496 #+end_src
498 #+begin_src sh :results verbatim
499 du -h youtube/helloPhysics.ogg
500 #+end_src
502 #+results:
503 : 13M youtube/helloPhysics.ogg
505 [[http://www.youtube.com/watch?v=WIJt9aRGusc][helloPhysics.ogg]]
507 #+begin_html
508 <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_html
515 ** COMMENT failed attempts
516 Let's try the [[http://diracvideo.org/][Dirac]] video encoder.
518 #+begin_src sh :results verbatim
519 cd youtube
520 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/null
526 echo `expr $(( $(date +%s) - $START))`
527 #+end_src
530 #+results:
531 : 142
533 That took 142 seconds. Let's see how it does compression-wise:
535 #+begin_src sh :results verbatim
536 du -h ./youtube/helloPhysics.drc
537 #+end_src
539 #+results:
540 : 22M ./physics-videos/helloPhysics.drc
543 #+begin_src sh :results verbatim
544 cd youtube
545 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/null
552 echo `expr $(( $(date +%s) - $START))`
553 #+end_src
555 #+results:
556 : 123
558 #+begin_src sh :results verbatim
559 du -h youtube/helloPhysics.ogg
560 #+end_src
562 #+results:
563 : 59M physics-videos/helloPhysics.ogg
566 =*.drc= files can not be uploaded to YouTube, so I'll go for the
567 avi file.
570 ** COMMENT text for videos
571 Video output from JMonkeyEngine3 (www.jmonkeyengine.org/) using Xuggle
572 (www.xuggle.com/). Everything is explained at
573 http://aurellem.org/cortex/capture-video.html.
576 Video output from JMonkeyEngine3 (www.jmonkeyengine.org/) HelloPhysics
577 demo application using Xuggle (www.xuggle.com/). Everything is
578 explained at http://aurellem.org/cortex/capture-video.html. Here,
579 four points of view are simultaneously recorded and then glued
580 together later.
582 JME3 Xuggle Aurellem video capture
585 * Showcase of recorded videos
586 I encoded most of the original JME3 Hello demos for your viewing
587 pleasure, all using the =Capture= and =IsoTimer= classes.
589 ** HelloTerrain
590 [[http://youtu.be/5_4wyDFwrVQ][HelloTerrain.avi]]
592 #+begin_html
593 <iframe width="425" height="349"
594 src="http://www.youtube.com/embed/5_4wyDFwrVQ"
595 frameborder="0" allowfullscreen>
596 </iframe>
597 #+end_html
599 ** HelloAssets
600 [[http://www.youtube.com/watch?v=oGg-Q6k1BM4][HelloAssets.avi]]
602 #+begin_html
603 <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_html
609 ** HelloEffects
610 [[http://www.youtube.com/watch?v=TuxlLMe53hA][HelloEffects]]
612 #+begin_html
613 <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_html
619 ** HelloCollision
620 [[http://www.youtube.com/watch?v=GPlvJkiZfFw][HelloCollision.avi]]
622 #+begin_html
623 <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_html
629 ** HelloAnimation
630 [[http://www.youtube.com/watch?v=SDCfOSPYUkg][HelloAnimation.avi]]
632 #+begin_html
633 <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_html
639 ** HelloNode
640 [[http://www.youtube.com/watch?v=pL-0fR0-ilQ][HelloNode.avi]]
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>
646 </iframe>
647 #+end_html
649 ** HelloLoop
650 [[http://www.youtube.com/watch?v=mosZzzcdE5w][HelloLoop.avi]]
652 #+begin_html
653 <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_html
660 *** COMMENT x-form the other stupid
661 progressreport update-freq=1
663 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.avi
692 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.avi
715 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.