Skip to content

Commit

Permalink
Refactor encoder settings and scene settings api (#8)
Browse files Browse the repository at this point in the history
* Refactor encoder settings and scene settings api

- scene settings are defined at scene load time, so you can set scene resolution and animaiton length there.
- encoder settings are defined before every render, so you  can set seek options there.

* Additional scene deifinition changes

* Updating documentation

* Update whats-new.md

* Update whats-new.md

* Update whats-new.md

* v1.1.0
  • Loading branch information
chrisgervang authored Jun 8, 2020
1 parent 9ffe597 commit 5cb40fd
Show file tree
Hide file tree
Showing 16 changed files with 151 additions and 90 deletions.
17 changes: 8 additions & 9 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ function getKeyframes(animationLoop, data) {
}

export function sceneBuilder(animationLoop) {
const length = 5000;
const lengthMs = 5000;
const data = [{sourcePosition: [-122.41669, 37.7853], targetPosition: [-122.41669, 37.781]}];
const keyframes = getKeyframes(animationLoop, data);
return new DeckScene({animationLoop, length, keyframes, data, renderLayers});
return new DeckScene({animationLoop, keyframes, data, renderLayers, lengthMs, width: 1920, height: 1080});
}
```

Expand All @@ -80,25 +80,24 @@ import {sceneBuilder} from './scene';

const adapter = new DeckAdapter(sceneBuilder, WebMEncoder);

/** @type {import('@hubble.gl/core/src/types').FrameEncoderSettings} */
const encoderSettings = {
framerate: 30
}

export default function App() {
const deckgl = useRef(null);
const [ready, setReady] = useState(false);
const [busy, setBusy] = useState(false);
const nextFrame = useNextFrame();

if (busy) {
adapter.update(nextFrame);
}

return (
<div style={{position: 'relative'}}>
<DeckGL
width={1920}
height={1080}
ref={deckgl}
{...adapter.getProps(deckgl, setReady, nextFrame)}
/>
<div style={{position: 'absolute'}}>{ready && <BasicControls adapter={adapter} busy={busy} setBusy={setBusy} />}</div>
<div style={{position: 'absolute'}}>{ready && <BasicControls adapter={adapter} busy={busy} setBusy={setBusy} encoderSettings={encoderSettings}/>}</div>
</div>
);
}
Expand Down
14 changes: 13 additions & 1 deletion docs/whats-new.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Whats New

## 1.0.0
## 1.0.1

Initial release.

## 1.1.0 (draft)

- Encoders are constructed right before rendering starts, instead of only when a scene is defined. [#1](https://github.com/uber/hubble.gl/pull/1)
- DeckAdapter.render now accepts a onStop callback.
- Remove stop and dispose from FrameEncoders [#3](https://github.com/uber/hubble.gl/pull/3)
- Allow PNGEncoder transparent frames [#4](https://github.com/uber/hubble.gl/pull/4)
- Refactor encoder settings and scene settings api [#8](https://github.com/uber/hubble.gl/pull/8)
- scene settings are defined at scene load time, so you can set scene resolution and animation length there.
- encoder settings are defined before every render, so you can set seek options there.
- format-specific encoder settings are namespaced by encoder (`jpeg` settings are under `jpeg`, etc..).
- Gif Encoder [#7](https://github.com/uber/hubble.gl/pull/7)
3 changes: 1 addition & 2 deletions examples/minimal/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ const INITIAL_VIEW_STATE = {

const adapter = new DeckAdapter(sceneBuilder);

/** @type {import('@hubble.gl/core/src/types').FrameEncoderSettings} */
const encoderSettings = {
animationLengthMs: 15000,
startOffsetMs: 0,
framerate: 30,
webm: {
quality: 0.8
Expand Down
11 changes: 9 additions & 2 deletions examples/minimal/scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,17 @@ function getKeyframes(animationLoop, data) {
}

export async function sceneBuilder(animationLoop) {
const length = 5000;
const data = await fetch(
'https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/bart-lines.json'
).then(x => x.json());
const keyframes = getKeyframes(animationLoop, data);
return new DeckScene({animationLoop, length, keyframes, data, renderLayers});
return new DeckScene({
animationLoop,
keyframes,
data,
renderLayers,
lengthMs: 5000,
width: 720,
height: 480
});
}
7 changes: 2 additions & 5 deletions examples/terrain/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ const INITIAL_VIEW_STATE = {

const adapter = new DeckAdapter(sceneBuilder);

/** @type {import('@hubble.gl/core/src/types').FrameEncoderSettings} */
const encoderSettings = {
animationLengthMs: 15000,
startOffsetMs: 0,
framerate: 30,
framerate: 10,
webm: {
quality: 0.8
},
Expand All @@ -36,8 +35,6 @@ export default function App() {
return (
<div style={{position: 'relative'}}>
<DeckGL
width={720}
height={480}
ref={deckgl}
initialViewState={INITIAL_VIEW_STATE}
{...adapter.getProps(deckgl, setReady, nextFrame)}
Expand Down
12 changes: 10 additions & 2 deletions examples/terrain/scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,17 @@ function getKeyframes(animationLoop, data) {
}

export const sceneBuilder = animationLoop => {
const length = 15000;
const lengthMs = 15000;
const data = {};
// set up keyframes
const keyframes = getKeyframes(animationLoop, data);
return new DeckScene({animationLoop, length, keyframes, data, renderLayers});
return new DeckScene({
animationLoop,
keyframes,
data,
renderLayers,
lengthMs,
width: 720,
height: 480
});
};
32 changes: 7 additions & 25 deletions modules/core/docs/deck-adapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Constructor

```js
new DeckAdapter(sceneBuilder, Encoder, encoderSettings);
new DeckAdapter(sceneBuilder);
```

## Parameters
Expand All @@ -18,21 +18,13 @@ async function sceneBuilder(animationLoop) {
const data = await fetch(...)
const keyframes = {}
const renderLayers = ...
const length = 5000 // ms
return new DeckScene({animationLoop, length, keyframes, data, renderLayers})
const lengthMs = 5000 // ms
const width = 1920 // px
const height = 1080 // px
return new DeckScene({animationLoop, keyframes, data, renderLayers, lengthMs, width, height})
}
```

##### `Encoder` (`typeof FrameEncoder`, Optional)

* Default: `PreviewEncoder`

FrameEncoder class for capturing deck canvas. See [Encoders]()

##### `encoderSettings` (`FrameEncoderSettings`, Optional)

* Default: `{}` (See `FrameEncoder` for internal defaults)

## Methods

##### `getProps`
Expand All @@ -47,25 +39,15 @@ Parameters:

* `onNextFrame` (`(nextTimeMs: number) => void`) - Callback indicating the next frame in a rendering should be displayed.

##### `update`

Call in react render when recording to request a new frame.

Parameters:

* `onNextFrame` (`(nextTimeMs: number) => void`) - Callback indicating the next frame in a rendering should be displayed.

##### `render`

Start rendering.

Parameters:

* `startTimeMs` (`number`, Optional) - Offset the animation. Defaults to 0.

##### `preview`
* `Encoder` (`typeof FrameEncoder`, Optional) - Default: `PreviewEncoder`. FrameEncoder class for capturing deck canvas. See [Encoders](/docs/encoder)

Preview rendering.
* `encoderSettings` (`FrameEncoderSettings`, Optional) - Default: `{}` (See [Encoder Overview](/docs/encoder) for internal defaults)

##### `stop`

Expand Down
12 changes: 12 additions & 0 deletions modules/core/docs/encoder/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Overview

### FrameEncoderSettings

* `startOffsetMs` (`number`, Optional) - Offset the animation. Defaults to 0.

* `durationMs` (`number`, Optional) - Set to render a smaller duration than the whole clip. Defaults to scene length.

* `filename`(`string`, Optional) - Filename for rendered video. Defaults to UUID.

* `framerate` (`number`, Optional) - framerate of rendered video. Defaults to 30.

See encoders for additional namespaced settings.

##### Video

All encoder classes implement the [`Encoder`]() abstract class and inherit from the [`FrameEncoder`]() or [`TarEncoder`]() base classes.
Expand Down
6 changes: 6 additions & 0 deletions modules/core/docs/encoder/jpeg-sequence-encoder.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

A photo sequence encoder that inherits [TarEncoder](). Saves each frame as a photo contained in a `".tar"` archive.

## FrameEncoderSettings

In addition to the top level [FrameEncoderSettings](/docs/encoder), these settings are available under the `jpeg` namespace.

* `quality` - See member note. Defaults to 0.8.

## Members

* `extension` - `".jpeg"`
Expand Down
6 changes: 6 additions & 0 deletions modules/core/docs/encoder/webm-encoder.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

A WebM video format encoder that inherits [FrameEncoder]().

## FrameEncoderSettings

In addition to the top level [FrameEncoderSettings](/docs/encoder), these settings are available under the `webm` namespace.

* `quality` - See member note. Defaults to 0.8.

## Members

* `extension` - `".webm"`
Expand Down
39 changes: 23 additions & 16 deletions modules/core/src/adapters/deck-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ export default class DeckAdapter {
/** @type {boolean} */
shouldAnimate;

/**
* @param {(animationLoop: any) => DeckScene | Promise<DeckScene>} sceneBuilder
*/
constructor(sceneBuilder) {
this.sceneBuilder = sceneBuilder;
this.videoCapture = new VideoCapture();
Expand All @@ -53,7 +56,7 @@ export default class DeckAdapter {
* @param {(nextTimeMs: number) => void} onNextFrame
*/
getProps(deckRef, setReady, onNextFrame) {
return {
const props = {
viewState: this._getViewState(),
layers: this._getLayers(),
onAfterRender: () => this._onAfterRender(onNextFrame),
Expand All @@ -64,16 +67,22 @@ export default class DeckAdapter {
}),
_animate: this.shouldAnimate
};

if (this.scene) {
props.width = this.scene.width;
props.height = this.scene.height;
}
return props;
}

/**
* @param {typeof import('../encoders').FrameEncoder} Encoder
* @param {import('types').FrameEncoderSettings} encoderSettings
* @param {() => void} onStop
*/
render(Encoder = PreviewEncoder, encoderSettings = {}, onStop = undefined) {
this.shouldAnimate = true;

if (!encoderSettings.animationLengthMs) {
encoderSettings.animationLengthMs = this.scene.length;
}

this.videoCapture.render(Encoder, encoderSettings, onStop);
this.videoCapture.render(Encoder, encoderSettings, this.scene.lengthMs, onStop);
this.scene.animationLoop.timeline.setTime(encoderSettings.startOffsetMs);
}

Expand Down Expand Up @@ -106,7 +115,7 @@ export default class DeckAdapter {
}

_getViewState() {
if (!this.videoCapture || !this.scene) {
if (!this.scene) {
return null;
}
const frame = this.scene.keyframes.camera.getFrame();
Expand All @@ -115,7 +124,7 @@ export default class DeckAdapter {
}

_getLayers() {
if (!this.videoCapture || !this.scene) {
if (!this.scene) {
return [];
}
return this.scene.renderLayers();
Expand All @@ -125,12 +134,10 @@ export default class DeckAdapter {
* @param {(nextTimeMs: number) => void} proceedToNextFrame
*/
_onAfterRender(proceedToNextFrame) {
if (this.videoCapture) {
// console.log('after render');
this.videoCapture.capture(this.deck.canvas, nextTimeMs => {
this.scene.animationLoop.timeline.setTime(nextTimeMs);
proceedToNextFrame(nextTimeMs);
});
}
// console.log('after render');
this.videoCapture.capture(this.deck.canvas, nextTimeMs => {
this.scene.animationLoop.timeline.setTime(nextTimeMs);
proceedToNextFrame(nextTimeMs);
});
}
}
Loading

0 comments on commit 5cb40fd

Please sign in to comment.