- From: Viktor Shchelochkov via GitHub <sysbot+gh@w3.org>
- Date: Mon, 10 Feb 2025 13:42:09 +0000
- To: public-webrtc-logs@w3.org
> Thanks for a great lib, [@Vanilagy](https://github.com/Vanilagy). Helps a ton! I can confirm that using it with MediaStreamTrackProcessor#getReader works as expected.
>
> Here's my example (wrapping [@theatrejs](https://github.com/theatrejs)):
>
> import { createRafDriver, ISheet, val } from '@theatre/core'
> import { useRef } from 'react'
> import WebMMuxer from 'webm-muxer'
>
> export const rafDriver = createRafDriver({ name: 'Hubble rAF driver' })
>
> export const useRenderer = ({
> sheet,
> fps = 30,
> width = 1280,
> height = 720,
> bitrate = 1e6,
> }: {
> sheet: ISheet
> fps?: number
> width?: number
> height?: number
> bitrate?: number
> }) => {
> const { sequence } = sheet
> const duration = val(sequence.pointer.length)
> const totalFrames = duration * fps
>
> // A way for the renderer to signal that the frame has finished drawing
> const renderDone = useRef((_a?: unknown) => {})
> const frameReady = () => {
> return new Promise((resolve) => (renderDone.current = resolve))
> }
>
> const captureFrame = () => {
> renderDone.current()
> }
>
> const startCapture = async ({ canvas }: { canvas: HTMLCanvasElement }) => {
> let i = 0
>
> let videoEncoder = new VideoEncoder({
> output: (chunk, meta) => muxer.addVideoChunk(chunk, meta, i * fps * 1000),
> error: (e) => console.error(e),
> })
>
> videoEncoder.configure({
> codec: 'vp09.00.10.08',
> width,
> height,
> bitrate,
> bitrateMode: "constant"
> })
>
> async function encodeFrame(data: VideoFrame) {
> const keyFrame = i % 60 === 0
> videoEncoder.encode(data, { keyFrame })
> }
>
> async function finishEncoding() {
> await videoEncoder.flush()
> muxer.finalize()
> reader.releaseLock()
> await fileWritableStream.close()
> }
>
> const fileHandle = await window.showSaveFilePicker({
> suggestedName: `video.webm`,
> types: [
> {
> description: 'Video File',
> accept: { 'video/webm': ['.webm'] },
> },
> ],
> })
>
> const fileWritableStream = await fileHandle.createWritable()
>
> const muxer = new WebMMuxer({
> target: fileWritableStream,
> video: {
> codec: 'V_VP9',
> width,
> height,
> frameRate: fps,
> },
> })
>
> await sheet.project.ready
> const track = canvas.captureStream(0).getVideoTracks()[0]
> // @ts-expect-error
> const mediaProcessor = new MediaStreamTrackProcessor(track)
> const reader = mediaProcessor.readable.getReader()
>
> for (i = 0; i < totalFrames; i++) {
> sequence.position = i / fps
> rafDriver.tick(performance.now())
>
> console.log(`capturing frame ${i}/${totalFrames} at simtime ${i / fps}`)
>
> await frameReady()
>
> // @ts-expect-error
> track.requestFrame()
> const result = await reader.read()
> const frame = result.value
>
> await encodeFrame(frame)
>
> frame.close()
> }
> finishEncoding()
> }
>
> return { startCapture, captureFrame }
> }
@akre54 solution was almost perfect for me, but Safari, despite what MDN and caniuse.com says, still has not implemented MediaStreamTrackProcessor, so I created this workaround which works perfectly in Safari:
```ts
const frame = new VideoFrame(canvas, {
timestamp: currentFrame * frameInterval * 1000,
duration: frameInterval * 1000,
})
```
In that case you don't even need MediaStreamTrackProcessor at all
--
GitHub Notification of comment by VityaSchel
Please view or discuss this issue at https://github.com/w3c/mediacapture-record/issues/213#issuecomment-2648025322 using your GitHub account
--
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Monday, 10 February 2025 13:42:10 UTC