Re: [mediacapture-record] Ability to record non-realtime / frame-by-frame (#213)

Thanks for a great lib, @Vanilagy. Helps a ton! I can confirm that using it with MediaStreamTrackProcessor#getReader works as expected.

Here's my example (wrapping @theatrejs):

```ts
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 }
}
```

-- 
GitHub Notification of comment by akre54
Please view or discuss this issue at https://github.com/w3c/mediacapture-record/issues/213#issuecomment-1430325280 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Tuesday, 14 February 2023 20:21:13 UTC