Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic bring-your-own-encoder rendering #92

Merged
merged 1 commit into from
May 27, 2023
Merged

Add basic bring-your-own-encoder rendering #92

merged 1 commit into from
May 27, 2023

Conversation

sigvef
Copy link
Member

@sigvef sigvef commented Apr 10, 2023

Add basic bring-your-own-encoder rendering

This adds a basic encoder-agnostic rendering function to renin, so that
you can render your demos to video.

To use this, you need to add some boilerplate/integration code to your
demo project. In your project, you can for instance use mp4-wasm as the
encoder. Here is a quick guide on how to do that.

First, install mp4-wasm:

yarn add mp4-wasm

Then, add these imports to the top of your demo's main.ts:

import loadMP4Module from "mp4-wasm";
import mp4wasm from "mp4-wasm/build/mp4.wasm?url";

And finally, comment out renin.loop() in main.ts and instead do
something like this:

// commented out for rendering purposes
// renin.loop()

(async () => {
  const wasmBinary = await (await fetch(mp4wasm)).arrayBuffer();
  const MP4 = await loadMP4Module({ wasmBinary });
  const width = 1920;
  const height = 1080;
  const encoder = MP4.createWebCodecsEncoder({
    width,
    height,
    fps: 60,
    encoderOptions: {
      framerate: 60,
      bitrate: 24_000_000,
    },
  });
  render(renin, { encoder, width, height });
})();

Now, the demo should play automatically when you visit renin in the
browser, and at the end a render.mp4 will be automatically downloaded.

It is without sound though, so we can add the music using ffmpeg:

ffmpeg -i render.mp4 -i music.ogg -c:v copy -map 0:v -map 1:a -y output.mp4

Now you have a finished video file that you can upload to YouTube!

mp4-wasm doesn't play nice with building renin as a lib -- otherwise we
could have bundled it with renin to make things easier.

@sigvef sigvef force-pushed the rendering branch 4 times, most recently from 49e4db0 to 0225f6e Compare April 10, 2023 21:56
This adds a basic encoder-agnostic rendering function to renin, so that
you can render your demos to video.

To use this, you need to add some boilerplate/integration code to your
demo project. In your project, you can for instance use mp4-wasm as the
encoder. Here is a quick guide on how to do that.

First, install mp4-wasm:

```bash
yarn add mp4-wasm
```

Then, add these imports to the top of your demo's `main.ts`:

```typescript
import loadMP4Module from "mp4-wasm";
import mp4wasm from "mp4-wasm/build/mp4.wasm?url";
```

And finally, comment out `renin.loop()` in `main.ts` and instead do
something like this:

```typescript
// commented out for rendering purposes
// renin.loop()

(async () => {
  const wasmBinary = await (await fetch(mp4wasm)).arrayBuffer();
  const MP4 = await loadMP4Module({ wasmBinary });
  const width = 1920;
  const height = 1080;
  const encoder = MP4.createWebCodecsEncoder({
    width,
    height,
    fps: 60,
    encoderOptions: {
      framerate: 60,
      bitrate: 24_000_000,
    },
  });
  render(renin, { encoder, width, height });
})();
```

Now, the demo should play automatically when you visit renin in the
browser, and at the end a render.mp4 will be automatically downloaded.

It is without sound though, so we can add the music using ffmpeg:

```bash
ffmpeg -i render.mp4 -i music.ogg -c:v copy -map 0:v -map 1:a -y output.mp4
```

Now you have a finished video file that you can upload to YouTube!

mp4-wasm doesn't play nice with building renin as a lib -- otherwise we
could have bundled it with renin to make things easier.
Copy link
Contributor

@trondkla trondkla left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, but why not have a standard implementation? :) Even if it doesn't play too nice 😄

@sigvef
Copy link
Member Author

sigvef commented Apr 11, 2023

Only that i didn't want to spend any more time trying to get the renin build to bundle mp4-wasm correctly 😅

@iver56
Copy link
Member

iver56 commented Apr 11, 2023

Closes #42

@stianjensen stianjensen merged commit b10afee into main May 27, 2023
@stianjensen stianjensen deleted the rendering branch May 27, 2023 12:21
@iver56
Copy link
Member

iver56 commented Sep 13, 2023

What's the best way to get an indication on the progress of the rendering?

@sigvef
Copy link
Member Author

sigvef commented Sep 14, 2023

Unless you do something to hide it, the demo itself will probably be visible on-screen during rendering. Also, I guess you could check the current frame of the demo or something?

@iver56
Copy link
Member

iver56 commented Sep 14, 2023

I think in my case there was an error that made the whole demo black, but it was still using 40% GPU for a few minutes and rendered a ~3 minutes long MP4 file with all black frames. The errors in the console indicate that it is related to a height that is NaN. Maybe I had to specify the aspect ratio somewhere? We hard-code height = 1080 in the snippet though 🤔 I used npx renin init mydemo as in the readme to init my project, and I'm not sure if that is currently API-compatible.

@iver56
Copy link
Member

iver56 commented Sep 14, 2023

The barebones inited project runs as expected when I do renin.loop() instead of the mp4 rendering though

@sigvef
Copy link
Member Author

sigvef commented Sep 14, 2023

Do you have aspectRatio in the renin options?

aspectRatio: 16.0/9,

@iver56
Copy link
Member

iver56 commented Sep 14, 2023

I can't remember (it's on my other laptop), but I briefly tried npx renin init myrenindemo here. It grabs renin 2.3.0 and gives me a main.ts like this:

import music from './music.ogg';
import { ACESFilmicToneMapping } from 'three';
import { Renin } from 'renin/lib/renin';
import { PostFx } from './PostFx';

export const renin = new Renin({
  music: {
    src: music,
    bpm: 114,
    subdivision: 12,
    beatOffset: 4,
  },
  root: PostFx,
  productionMode: import.meta.env.PROD,
  rendererOptions: {
    powerPreference: 'high-performance',
  },
  toneMapping: ACESFilmicToneMapping,
});

renin.loop();

So yes, it's missing aspectRatio, which I'm guessing caused the trouble I experienced.

Time to make a new renin release? 😃

@iver56
Copy link
Member

iver56 commented Sep 14, 2023

Yup, adding the aspectRatio fixed the rendering for me 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants