Two posts ago I started talking about img-genner. Guiding my authorship of the library by using it. Today I made a change that allows for what I think are exciting possibilities.
One of the best uses I've found for this library has been using it to generate animations, surprisingly I've started to take a liking to my own library(oh dear, I've started warming to my own work, whatever will I do with my non-existent objectivity?).
Today, I learned something very useful from the ffmpeg-user mailing list, that it is possible to just concatenate png files and pass them to ffmpeg. This enables an easy method for img-genner to be used to generate animations directly without having to turn the png files into video.
(ql:quickload :img-genner) (defparameter *ffmpeg-format* "ffmpeg -f png_pipe -i - ~a ~a") (defparameter *ffmpeg-input* (uiop:launch-program (format nil *ffmpeg-format* "-deadline best" "movie.webm") :input :stream)) (defparameter *image* (img-genner:make-image 640 480)) (defparameter *circles* nil) (defun reset-image(image) ;Taken from the previous post (loop for i from 0 below (array-total-size image) do(setf (row-major-aref image i) 0))) (defun bound(pos min-x min-y max-x max-y) ;As is this (setf (aref pos 0) (if (> (aref pos 0) max-x) min-x (if (< (aref pos 0) min-x) max-x (aref pos 0))) (aref pos 1) (if (> (aref pos 1) max-y) min-y (if (< (aref pos 1) min-y) max-y (aref pos 1))))) (defun tick() (reset-image *image*) (loop for (i . (dx dy c)) in *circles* do(img-genner:move-by i dx dy) do(bound (slot-value i 'img-genner:origin) 0.0 0.0 640.0 480.0) do(img-genner:rotate-by i (- (random 1.5) 0.75)) do(img-genner:fill-shape i *image* (img-genner:static-color-stroker c)))) (loop repeat 20 do(push (cons (img-genner:make-ellipse (random 640.0) (random 640.0) (+ 10.0 (random 10.0)) (+ 10.0 (random 10.0))) (list (1- (random 2.0)) (1- (random 2.0)) (img-genner:get-random-color))) *circles*)) (loop repeat 1000 do(tick) (img-genner:save-image *image* (uiop:process-info-input *ffmpeg-input*))) (uiop:close-streams *ffmpeg-input*) (uiop:wait-process *ffmpeg-input*)
You will notice the return of some code from the last one, but it avoids the usage of hashtables.
The important part is the
uiop:launch-program. It creates a process which runs asynchronously, that is, that it doesn't block, and you can obtain the input stream, which is what
:input :stream does. Obtaining the stream is done by calling
uiop:process-info-input on the ffmpeg-input structure.
The next step will be reading from ffmpeg, but I'll leave that for my next post.