vivus icon indicating copy to clipboard operation
vivus copied to clipboard

Export animated svg as .mov or .mp4

Open michaelrommel opened this issue 4 years ago • 6 comments

Dear maxwellito,

thank you very much for the library and the vivus instant website - it is a joy to use!

I wondered, if there are any recommendations or best practises, when one wants to export the animated svg into a video with a defined resolution (FullHD or 4K).

At the moment I have embedded the resulting svg in a website and perform a screen recording while the browser plays the animation. I encountered two difficulties:

  1. Timing

When the animation is being played back too quickly, the screen recorder misses frames and the resulting video is yanky. I overcame this by having the exported animation from vivus instant set to a 4x longer time, then I post process the recorded animation and speed it up 4x. This produced good results. Also, if I record on a 4KTV with a 60HZ refresh rate, the grabbed video is more yanky, than when I record it on a 120 Hz refresh rate monitor. After the post processing, though, both are practically the same.

  1. Resolution

Because of the screen grabbing, I actually can only record in resolutions below the monitor's resolution and lose a bit of detail.

Therefore I was looking for a way to export the animated frames into a movie (or a series of image, that I could then import into Final Cut). Does anyone know about any such solution?

Thank you in advance. If this is not the right way to ask for help, please feel free to tell me, I will then close this issue.

All the best,

Michael.

michaelrommel avatar Aug 23 '20 18:08 michaelrommel

Hello Michael,

First, thanks for your kind words. Its always nice to hear from users :)

Your issue is a very interesting one. I must admit, I had to think about a solution for a similar problem but never had the chance to implement it.

Let's start by the library constraints. Vivus uses requestAnimationFrame to time intervals between frames. Depending on your machine/SVG complexity the frame rate might vary. In this case it will be difficult to increase the frame rate as you need.

My guess, to make it possible, would be the following stack:

  • Your webpage containing the animation and the styling required
  • A Puppeteer script to open the page at the resolution of your choice, and render each frame and export it. (This is doable by setting the progress of the animation with .setFrameProgress(progress))
  • FFMPEG script to combine all the pictures into one video. Or import them into Final Cut if you prefer.

I dunno if it's what you had in mind. I'm happy to give more details and help you start the project.

I hope this helps :)

maxwellito avatar Aug 23 '20 19:08 maxwellito

Hi,

thank you for your speedy reply - I also thought about puppeteer, as I am using this already for GUI tests. But I looked into animTimingFunction instead of the setFrameProgress function - so I will give that a try. If I read this correctly, then let's say given I want a roughly 2 sec intro of a video in 60p I would run the argument to that function from 0 to 1 in 0.008 increments which results in 125 images. I will give that a try next weekend and let you know how it went. Right now I am busy with work...

Thanks for the helpful hint!

Michael.

michaelrommel avatar Aug 25 '20 18:08 michaelrommel

You can definitely override window.requestAnimationFrame (before loading Vivus) by something like (fn) => setTimeout(fn, 1000/120). However your computer must be tough enough to generate the frames at the right time. Otherwise, you can slow down the timeout to 10 frames a second, and accelerate it on Final Cut.

maxwellito avatar Aug 26 '20 08:08 maxwellito

Perhaps if you added an event to Vivus, so that for every frame you triggered an event frame which people then could hook into? Using something like Puppeteer then, you might generate a screenshoot of that current frame.

netsi1964 avatar Sep 06 '20 12:09 netsi1964

It's something doable with the base API

// Init the Vivus instance
const duration = 200;
const myVivus = new Vivus('svgId', {duration, start: 'manual'});
let currentFrame = 0;

// Function to move to the next frame
// Will return 'true' once the last frame is reached
function nextFrame () {
  myVivus.setFrameProgress((currentFrame++)/duration);
  return currentFrame === duration;
}

maxwellito avatar Sep 08 '20 12:09 maxwellito

Hi, I ended up making a super quick and dirty Electron app to solve this very issue. https://github.com/jeremypatrickdahan/vivus-electron

It is essentially a giant security hole, so never use this in production or with untrusted svg files... It is quite difficult to preserve transparency with video. I ended up using a quicktime codec (qtrle), though webm also works.

Ho, and resolution is set at 2K, although it is quite easy to change. It is easy to modify to only get the PNG sequence to import it in a video editor.

EDIT : I had some more time to play with this. This quick app is actually for a relative, who uses an iPad for video editing. So I needed to export everything as HEVC with an alpha channel, which is only possible on macOS Catalina for now. So FFMPEG is tuned for Apple ProRes4444 (and no longer qtrle) and then avconvert (the macOS version of avconv) converts to HEVC + alpha. It works well and the resulting files are very small, but everything is currently very slow.

jdexyz avatar Dec 04 '20 01:12 jdexyz