Create videos using React!

Overview


Reactive Video




Reactive Videos are videos created using HTML and React components. This allows you to leverage the almost limitless possibilities of the web browser to render dynamic content into a video file.

How does it work?

Reactive Video fires up one or more Puppeteer/Chromium tabs to render the React component hierarchy and rapidly capture screenshots for each frame when they are done rendering.

NOTE: It starts a HTTP server on localhost serving files in the current directory for the Puppeteer client.

Features

  • Edit videos with code! 🤓
  • Full power of the web
  • Parallel rendering 🔥 Super fast (compared to editly)
  • Supports all video formats/codecs that FFmpeg supports
  • Headless mode (runs in the cloud)
  • Output to any dimensions and aspect ratio, e.g. Instagram post (1:1), Instagram story (9:16), YouTube (16:9), or any other dimensions you like.
  • Live preview for easy development
  • Open source

Installation

First install and setup ffmpeg/ffprobe.

npm i -g reactive-video

Usage

Create a file MyVideo.js with the content:

import React from 'react';
import { Image, Segment, FFmpegVideo, useVideo, setRoot } from 'reactive-video';

const MyVideo = () => {
  const { currentFrame, currentTime, durationFrames, durationTime } = useVideo();

  return (
    <>
      {/* This segment lasts 30 frames. Print out the current frame number */}
      <Segment duration={30}>
        <div
          style={{ width: '100%', height: '100%', backgroundColor: `hsl(${(currentFrame * 10) % 360}deg 78% 37%)`, color: 'white', display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column', fontSize: 100 }}
        >
          Current frame {currentFrame}
        </div>
      </Segment>

      {/* This segment starts from 60 frames. Shows an image with a Ken Burns zoom effect */}
      <Segment
        start={30}
        duration={30}
        render={(segment) => (
          <Image src="https://static.mifi.no/losslesscut/47320816_571610306620180_5860442193520120371_n.jpg" style={{ width: '100%', transform: `scale(${1 + (segment.currentFrame / segment.durationFrames) * 0.1})` }} />
        )}
      />

      {/* This segment starts from 60 frames. Cut from 100 frames in the source video */}
      <Segment start={60}>
        <Segment start={-100}>
          <FFmpegVideo src="https://static.mifi.no/Zv5RvLhCz4M-small.mp4" style={{ width: '100%' }} />
        </Segment>
      </Segment>
    </>
  );
};

// Set this as the root component, so we know what to render
setRoot(MyVideo);

Shell

Then run in a shell:

reactive-video --duration-frames 90 MyVideo.js

Live preview

Or to start a live preview:

reactive-video --duration-frames 90 MyVideo.js --preview

Programmatic API

Or you can use the programmatic API. Create a new Node.js project, then add reactive-video:

mkdir awesome-project
cd awesome-project
npm init
npm i --save reactive-video

Create index.js:

const Editor = require('reactive-video/editor');

(async () => {
  const editor = Editor({
    devMode: true,
  });

  const width = 1280;
  const height = 720;
  const fps = 25;
  const durationFrames = 90;
  const reactVideo = 'MyVideo.js'
  const userData = { some: 'value' };

  await editor.edit({
    reactVideo,
    width,
    height,
    durationFrames,
    userData,

    output: 'my-video.mp4',
    concurrency: 3,
    // headless: false,

  });

  // Or start a live preview
  await editor.preview({
    reactVideo,
    width,
    height,
    fps,
    durationFrames,
    userData,
  });
})().catch(console.error);

Node API

Reactive Video is split between code that runs in Node.js and code that runs in the React world. Coordination can happen through userData.

The Node API is being used directly by the CLI.

Editor.edit / Editor.preview

const Editor = require('reactive-video/editor');

const { edit, preview } = Editor({ ffmpegPath, ffprobePath });

See editor.js edit and preview for options.

React API

FFmpegVideo

Video backed by ffmpeg, streamed to canvas. Efficiently reuses the ffmpeg instance for serial rendering. Supports virtually all formats.

NOTE: src must be supplied as a local path without file://. (e.g. ./video.mp4). This is a current limitation that will be improved.

HTML5Video

Works the same as HTML <video>. Only supports certain codecs due to Chromium limitations (e.g. does not support h264.)

NOTE: src must be supplied as a full, absolute path (e.g. file:///Users/me/video.webm or https://example.com/video.webm). This is a current limitation that will be improved.

IFrame

Works the same as HTML <iframe>

NOTE: src must be supplied as a full, absolute path (e.g. file:///Users/me/index.html or https://example.com/index.html). This is a current limitation that will be improved.

Image

Works the same as HTML <image>

NOTE: src must be supplied as a full, absolute path (e.g. file:///Users/me/photo.jpg or https://example.com/photo.jpg). This is a current limitation that will be improved.

setRoot

You must call this once with your root component.

getUserData

Call this function to get user JSON data passed from CLI (--user-data) or Node.js userData option.

useVideo

A hook that can be used to get the current video state.

const {
  // Video (or Segment relative) frame count:
  currentFrame,
  // Video (or Segment relative) time:
  currentTime,
  // Video (or Segment) duration in frames:
  durationFrames,
  // Video (or Segment) duration in seconds:
  durationTime,

  // Global, never altered:
  video: {
    currentFrame,
    currentTime,
    durationFrames,
    durationTime,
  },

  // Global video properties
  fps,
  width,
  height,
} = useVideo();

useAsyncRenderer

A hook used to get a waitFor function that must be used when you want the frame capture operation to be delayed due to an asynchronous task that needs to finish first.

const { waitFor } = useAsyncRenderer();
waitFor(async () => {
  setState(await api.loadSomeData());
});

Segment

A Segment will, for a specific timespan specified by frame number start and duration, render either:

  1. Its provided children:
<Segment><MyComponents /></Segment>
  1. or a render prop:
<Segment render={(props) => <MyComponents />} />

Segment props

  • start - First frame that contents should be shown from (default 0)
  • duration - Number of frames that contents should be visible for (default video durationFrames).

Segments will override the following variables in the useVideo hook for its children:

  • currentFrame
  • currentTime
  • durationFrames
  • durationTime

Theses variables will instead be relative to the start/duration of the Segment.

If the render prop is used, the render function's provided props argument will also contain the same variables.

Examples

See examples

Your video here?

Submit a PR if you want to share your Reactive Video here.

TODO

  • Preview doesn't support local paths (unless imported)
  • Improve docs
  • Audio
  • ci tests
  • Improve logging
  • multiple FFmpegVideos from the same source file (videoServer.js) not supported
  • FFmpegVideo/HTML5Video fallback to previous frame if missing?
  • HTML5Video calculate file:// paths relative to cwd, or proxy local files
  • puppeteer intercept request instead of starting local express server (if possible/fast to send big binary data)
  • Improve preview (don't use query string) webpack inject?
  • preview.html wait for render complete, to avoid flooding with ffmpeg processes
  • Retry screencast (sometimes, very rarely, Page.screencastFrame stops getting called)
  • Do we need webpack mode production? We don't need all the uglifying etc. development is much faster
  • Source maps would be great in production too
  • make it easiser to animate (mount/unmount?) provide a react component that clamps animations? something like <Segment start={} duration={} render=((animation) => 0..1) easing="easeIn" />

Ideas

  • subtitle rendering (programmatically create Segments)
  • easy merge videos recipe/helper
  • webgl
  • react three js
  • create demo video, YouTube video
  • editly features
  • Recreate editly's video in reactive-video

Donate 🙈

This project is maintained by me alone. The project will always remain free and open source, but if it's useful for you, consider supporting me. :) It will give me extra motivation to improve it. Or even better donate to ffmpeg because they are doing the world a big favor 🙏

See also

  • editly - Declarative video API I also created earlier
  • remotion - Great inspiration

Made with ❤️ in 🇳🇴

More apps by mifi.no

Follow me on GitHub, YouTube, IG, Twitter for more awesome content!

Comments
  • Node api example is broken

    Node api example is broken

    reactive-video --duration-frames 90 MyVideo.js works as expected But node api example generate a broken file https://github.com/mifi/reactive-video#programmatic-api

    opened by gut4 5
  • Remote video error

    Remote video error

    Hello, I'm getting TypeError: must pass in a file:// URI to convert to a file path when trying to use the code from your exemple : <Video src="https://static.mifi.no/Zv5RvLhCz4M-small.mp4" />

    I tried with or without headless and with different version of @reactive-video/builder

    Do you have any clue?

    opened by IvanDhalluin 4
  • Best way to wait for https content to load

    Best way to wait for https content to load

    Hi,

    First, thanks for your amazing work, this lib is (will be really) usefull to me.

    I'm trying to compute video from SVG sequence. Here I'm just generating a black and white slideshow off an array of image.

    This is working but I have a small issue, I need to wait some times, here 250ms to be sure the image is loaded. Otherwise the first frame(s) of each image will be white.

    import React, { useEffect } from 'react'
    import { Segment, useAsyncRenderer } from 'reactive-video'
    
    const images = [
      'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80',
      'https://images.unsplash.com/photo-1454496522488-7a8e488e8606?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1176&q=80',
      'https://images.unsplash.com/photo-1483728642387-6c3bdd6c93e5?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1176&q=80'
    ]
    
    function SvgImage({ url }) {
      const { waitFor } = useAsyncRenderer()
      useEffect(() => {
        waitFor(async () => {
          await timeout(250)
        })
      }, [waitFor])
    
      return (
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
          <defs>
            <filter id="black-and-white" colorInterpolationFilters="sRGB">
              <feColorMatrix in="SourceGraphic" type="saturate" values="0" result="blackAndWhite" />
              <feComponentTransfer in="blackAndWhite">
                <feFuncR type="table" tableValues=".01 .25 .82 1" />
                <feFuncG type="table" tableValues=".01 .25 .82 1" />
                <feFuncB type="table" tableValues=".01 .25 .82 1" />
              </feComponentTransfer>
            </filter>
          </defs>
          <image x={0} y={0} width={'100%'} height={'100%'} xlinkHref={url} preserveAspectRatio="xMidYMid slice" filter={`url(#black-and-white)`} />
        </svg>
      )
    }
    
    export default () => {
      return (
        <>
          {images.map((url, i) =>
            <Segment key={url} duration={30} start={30 * i}>
              <SvgImage url={url} />
            </Segment>
          )}
        </>
      )
    }
    

    Do you think there is a better way to achieve this?

    opened by IvanDhalluin 2
  • [bug] Error: Bundle failed

    [bug] Error: Bundle failed

    $ reactive-video --duration-frames 90 MyVideo.js
    Compiling Reactive Video Javascript
    assets by status 36.2 KiB [cached] 1 asset
    orphan modules 17.3 KiB [orphan] 10 modules
    cacheable modules 30.2 KiB
      modules by path C:/Users/tomby/AppData/Roaming/npm/node_modules/@reactive-video/builder/node_modules/ 8.54 KiB
        C:\Users\tomby\AppData\Roaming\npm\node_modules\@reactive-video\builder\node_modules\react\index.js 190 bytes [built] [code generated]
        C:\Users\tomby\AppData\Roaming\npm\node_modules\@reactive-video\builder\node_modules\react\cjs\react.production.min.js 6.3 KiB [built] [code generated]
        C:\Users\tomby\AppData\Roaming\npm\node_modules\@reactive-video\builder\node_modules\object-assign\index.js 2.06 KiB [built] [code generated]
      C:\Users\tomby\AppData\Roaming\npm\node_modules\@reactive-video\builder\puppeteerEntry.js 4.25 KiB [built] [code generated] [1 error]
      ./MyVideo.js + 9 modules 17.4 KiB [built] [code generated]
    
    ERROR in C:\Users\tomby\AppData\Roaming\npm\node_modules\@reactive-video\builder\puppeteerEntry.js 79:4
    Module parse failed: Unexpected token (79:4)
    You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
    |   // <div key={currentFrame} id={getId(currentFrame)}>
    |   return (
    >     <div id={getId(currentFrame)} style={frameCanvasStyle}>
    |       <VideoContextProvider
    |         currentFrame={currentFrame}
    
    webpack 5.51.1 compiled with 1 error in 897 ms
    Error: Bundle failed
    

    I only copy-pasted README example. Win10, bash, ffmpeg -v works.

    TIA :)

    opened by tomByrer 2
  • upgrade puppeteer and fix race condition

    upgrade puppeteer and fix race condition

    • breaking: api change
    • useMemo is not safe
    • simplify: don't need to use hook at all (remove useAsyncRenderer)
    • add waitFor component names for easier debug
    opened by mifi 1
  • Blank video frame on duplicate requests

    Blank video frame on duplicate requests

    The <img> element inside FFmpegVideo fetched getFrame on the server twice with the same key seg11_raw.mkv, presumably due to time being different. Suspect that for some reason React first fetched seg11_raw but with the wrong time value (maybe from the previous segment/frame). Then it fetched the frame again 200ms later (presumably with time: 0). This caused the first ffmpeg to be killed (killed: true), as intended, but the browser element never reported an error, and the render finished with a blank (white) video for that one frame.

    Full log:

    2022-04-10T17:09:24.310Z - info: Compiling Reactive Video Javascript
    2022-04-10T17:09:28.263Z - info: Starting server
    2022-04-10T17:09:28.271Z - info: Launching puppeteer, concurrency: 9
    2022-04-10T17:09:28.532Z - info: Rendering frames
    2022-04-10T17:09:29.836Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":662,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg4_raw.mkv","width":1280}
    2022-04-10T17:09:30.335Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":0,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg0_raw.mkv","width":1280}
    2022-04-10T17:09:30.368Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":331,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg1_raw.mkv","width":1280}
    2022-04-10T17:09:30.441Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":993,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg6_raw.mkv","width":1280}
    2022-04-10T17:09:30.475Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":2648,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg16_raw.mkv","width":1280}
    2022-04-10T17:09:30.577Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":1655,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg10_raw.mkv","width":1280}
    2022-04-10T17:09:30.775Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":2317,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg14_raw.mkv","width":1280}
    2022-04-10T17:09:31.031Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":1324,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg8_raw.mkv","width":1280}
    2022-04-10T17:09:31.112Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":1986,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg12_raw.mkv","width":1280}
    2022-04-10T17:09:31.291Z - info: Progress 0.00% FPS: 0.00 Parts: 0: 0.00%, 2: 0.00%
    2022-04-10T17:09:33.606Z - info: Progress 1.01% FPS: 12.39 Parts: 0: 2.72%, 1: 0.30%, 2: 1.51%, 3: 0.60%, 4: 0.30%, 5: 0.91%, 6: 0.60%, 7: 0.60%, 8: 1.51%
    2022-04-10T17:09:35.127Z - info: Progress 2.01% FPS: 15.23 Parts: 0: 3.93%, 1: 1.21%, 2: 2.72%, 3: 1.51%, 4: 1.21%, 5: 2.11%, 6: 1.51%, 7: 1.51%, 8: 2.42%
    2022-04-10T17:09:36.421Z - info: Progress 3.02% FPS: 17.19 Parts: 0: 5.44%, 1: 2.11%, 2: 3.32%, 3: 2.72%, 4: 2.11%, 5: 3.02%, 6: 2.42%, 7: 2.72%, 8: 3.32%
    2022-04-10T17:09:37.671Z - info: Progress 4.03% FPS: 18.50 Parts: 0: 6.34%, 1: 3.32%, 2: 4.53%, 3: 3.63%, 4: 3.02%, 5: 3.93%, 6: 3.32%, 7: 3.63%, 8: 4.53%
    2022-04-10T17:09:38.877Z - info: Progress 5.04% FPS: 19.50 Parts: 0: 7.85%, 1: 4.23%, 2: 5.44%, 3: 4.53%, 4: 3.93%, 5: 5.14%, 6: 4.23%, 7: 4.53%, 8: 5.44%
    2022-04-10T17:09:40.245Z - info: Progress 6.04% FPS: 19.87 Parts: 0: 9.06%, 1: 5.14%, 2: 6.34%, 3: 5.74%, 4: 5.14%, 5: 6.04%, 6: 5.14%, 7: 5.44%, 8: 6.34%
    2022-04-10T17:09:41.516Z - info: Progress 7.05% FPS: 20.33 Parts: 0: 9.97%, 1: 6.04%, 2: 7.55%, 3: 6.65%, 4: 6.34%, 5: 6.95%, 6: 6.34%, 7: 6.34%, 8: 7.25%
    2022-04-10T17:09:42.925Z - info: Progress 8.06% FPS: 20.44 Parts: 0: 11.18%, 1: 6.65%, 2: 8.46%, 3: 7.85%, 4: 7.55%, 5: 7.85%, 6: 7.25%, 7: 7.25%, 8: 8.46%
    2022-04-10T17:09:44.019Z - info: Progress 9.06% FPS: 21.04 Parts: 0: 12.08%, 1: 7.85%, 2: 9.67%, 3: 8.76%, 4: 8.46%, 5: 8.76%, 6: 8.16%, 7: 8.46%, 8: 9.37%
    2022-04-10T17:09:45.272Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":331,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg2_raw.mkv","width":1280}
    2022-04-10T17:09:45.335Z - info: Progress 10.07% FPS: 21.20 Parts: 0: 13.29%, 1: 8.46%, 2: 10.88%, 3: 9.67%, 4: 9.37%, 5: 9.97%, 6: 9.37%, 7: 9.37%, 8: 10.27%
    2022-04-10T17:09:46.617Z - info: Progress 11.08% FPS: 21.38 Parts: 0: 14.80%, 1: 9.06%, 2: 11.78%, 3: 10.57%, 4: 10.57%, 5: 10.88%, 6: 10.27%, 7: 10.27%, 8: 11.48%
    2022-04-10T17:09:47.619Z - info: Progress 12.08% FPS: 21.91 Parts: 0: 15.71%, 1: 10.57%, 2: 12.69%, 3: 11.48%, 4: 11.48%, 5: 11.78%, 6: 11.18%, 7: 11.48%, 8: 12.39%
    2022-04-10T17:09:48.761Z - info: Progress 13.09% FPS: 22.19 Parts: 0: 16.92%, 1: 12.08%, 2: 13.60%, 3: 12.39%, 4: 12.69%, 5: 12.39%, 6: 12.39%, 7: 12.08%, 8: 13.29%
    2022-04-10T17:09:49.852Z - info: Progress 14.10% FPS: 22.51 Parts: 0: 17.52%, 1: 13.60%, 2: 14.50%, 3: 13.60%, 4: 13.60%, 5: 13.60%, 6: 13.29%, 7: 13.29%, 8: 13.90%
    2022-04-10T17:09:51.006Z - info: Progress 15.11% FPS: 22.70 Parts: 0: 18.73%, 1: 15.11%, 2: 15.41%, 3: 14.50%, 4: 14.50%, 5: 14.50%, 6: 13.90%, 7: 14.20%, 8: 15.11%
    2022-04-10T17:09:52.027Z - info: Progress 16.11% FPS: 23.04 Parts: 0: 19.64%, 1: 16.62%, 2: 16.31%, 3: 15.41%, 4: 15.41%, 5: 15.41%, 6: 15.11%, 7: 15.11%, 8: 16.01%
    2022-04-10T17:09:52.729Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":662,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg5_raw.mkv","width":1280}
    2022-04-10T17:09:53.206Z - info: Progress 17.12% FPS: 23.16 Parts: 0: 20.54%, 1: 18.13%, 2: 16.92%, 3: 16.62%, 4: 16.31%, 5: 16.31%, 6: 16.01%, 7: 16.01%, 8: 17.22%
    2022-04-10T17:09:54.290Z - info: Progress 18.13% FPS: 23.37 Parts: 0: 21.75%, 1: 19.64%, 2: 17.52%, 3: 17.52%, 4: 17.22%, 5: 17.22%, 6: 17.22%, 7: 16.92%, 8: 18.13%
    2022-04-10T17:09:55.279Z - info: Progress 19.13% FPS: 23.66 Parts: 0: 22.96%, 1: 21.15%, 2: 18.73%, 3: 18.43%, 4: 18.13%, 5: 18.13%, 6: 17.82%, 7: 17.82%, 8: 19.03%
    2022-04-10T17:09:56.406Z - info: Progress 20.14% FPS: 23.79 Parts: 0: 23.87%, 1: 22.66%, 2: 19.94%, 3: 19.34%, 4: 19.34%, 5: 18.73%, 6: 18.73%, 7: 18.73%, 8: 19.94%
    2022-04-10T17:09:56.975Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":331,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg3_raw.mkv","width":1280}
    2022-04-10T17:09:57.473Z - info: Progress 21.15% FPS: 23.96 Parts: 0: 25.08%, 1: 23.26%, 2: 21.15%, 3: 20.24%, 4: 20.24%, 5: 19.94%, 6: 19.64%, 7: 19.64%, 8: 21.15%
    2022-04-10T17:09:58.603Z - info: Progress 22.16% FPS: 24.07 Parts: 0: 25.98%, 1: 24.47%, 2: 22.66%, 3: 21.15%, 4: 21.15%, 5: 20.85%, 6: 20.54%, 7: 20.54%, 8: 22.05%
    2022-04-10T17:09:59.626Z - info: Progress 23.16% FPS: 24.26 Parts: 0: 27.19%, 1: 25.98%, 2: 23.87%, 3: 21.75%, 4: 22.05%, 5: 21.75%, 6: 21.45%, 7: 21.45%, 8: 22.96%
    2022-04-10T17:10:00.531Z - info: Progress 24.17% FPS: 24.53 Parts: 0: 28.40%, 1: 27.49%, 2: 25.08%, 3: 22.66%, 4: 22.96%, 5: 22.66%, 6: 22.36%, 7: 22.36%, 8: 23.56%
    2022-04-10T17:10:01.522Z - info: Progress 25.18% FPS: 24.72 Parts: 0: 29.91%, 1: 29.00%, 2: 26.28%, 3: 23.56%, 4: 23.56%, 5: 23.56%, 6: 23.26%, 7: 23.26%, 8: 24.17%
    2022-04-10T17:10:01.673Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":993,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg7_raw.mkv","width":1280}
    2022-04-10T17:10:02.668Z - info: Progress 26.18% FPS: 24.77 Parts: 0: 31.12%, 1: 30.51%, 2: 27.79%, 3: 23.87%, 4: 24.47%, 5: 24.47%, 6: 24.17%, 7: 24.17%, 8: 25.08%
    2022-04-10T17:10:03.570Z - info: Progress 27.19% FPS: 25.01 Parts: 0: 32.33%, 1: 31.42%, 2: 28.70%, 3: 25.38%, 4: 25.68%, 5: 25.38%, 6: 24.77%, 7: 25.08%, 8: 25.98%
    2022-04-10T17:10:04.483Z - info: Progress 28.20% FPS: 25.23 Parts: 0: 33.53%, 1: 32.93%, 2: 29.91%, 3: 26.59%, 4: 26.28%, 5: 26.28%, 6: 25.68%, 7: 25.98%, 8: 26.59%
    2022-04-10T17:10:05.623Z - info: Progress 29.20% FPS: 25.26 Parts: 0: 34.74%, 1: 34.14%, 2: 31.12%, 3: 27.49%, 4: 27.49%, 5: 27.19%, 6: 26.28%, 7: 26.89%, 8: 27.49%
    2022-04-10T17:10:06.590Z - info: Progress 30.21% FPS: 25.42 Parts: 0: 35.95%, 1: 35.35%, 2: 32.63%, 3: 29.00%, 4: 28.10%, 5: 27.79%, 6: 27.19%, 7: 27.49%, 8: 28.40%
    2022-04-10T17:10:07.490Z - info: Progress 31.22% FPS: 25.62 Parts: 0: 37.46%, 1: 36.56%, 2: 33.84%, 3: 30.21%, 4: 28.70%, 5: 28.70%, 6: 28.10%, 7: 28.10%, 8: 29.31%
    2022-04-10T17:10:08.351Z - info: Progress 32.23% FPS: 25.83 Parts: 0: 38.67%, 1: 37.76%, 2: 35.35%, 3: 31.42%, 4: 29.61%, 5: 29.61%, 6: 28.70%, 7: 29.00%, 8: 29.91%
    2022-04-10T17:10:08.795Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":1324,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg9_raw.mkv","width":1280}
    2022-04-10T17:10:09.209Z - info: Progress 33.23% FPS: 26.04 Parts: 0: 39.88%, 1: 39.27%, 2: 36.56%, 3: 32.63%, 4: 29.91%, 5: 30.21%, 6: 29.91%, 7: 29.61%, 8: 31.12%
    2022-04-10T17:10:10.211Z - info: Progress 34.24% FPS: 26.14 Parts: 0: 41.09%, 1: 40.48%, 2: 37.76%, 3: 33.84%, 4: 30.51%, 5: 31.42%, 6: 30.82%, 7: 30.51%, 8: 31.72%
    2022-04-10T17:10:11.101Z - info: Progress 35.25% FPS: 26.30 Parts: 0: 42.30%, 1: 41.69%, 2: 38.97%, 3: 35.05%, 4: 31.72%, 5: 32.02%, 6: 31.72%, 7: 31.12%, 8: 32.63%
    2022-04-10T17:10:11.868Z - info: Progress 36.25% FPS: 26.55 Parts: 0: 43.50%, 1: 43.20%, 2: 39.88%, 3: 36.56%, 4: 32.93%, 5: 32.63%, 6: 32.33%, 7: 32.02%, 8: 33.23%
    2022-04-10T17:10:12.607Z - info: Progress 37.26% FPS: 26.80 Parts: 0: 44.71%, 1: 44.41%, 2: 41.09%, 3: 37.76%, 4: 33.84%, 5: 33.53%, 6: 33.23%, 7: 32.63%, 8: 34.14%
    2022-04-10T17:10:13.178Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":0,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg1_raw.mkv","width":1280}
    2022-04-10T17:10:13.541Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":1655,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg11_raw.mkv","width":1280}
    2022-04-10T17:10:13.617Z - info: Progress 38.27% FPS: 26.87 Parts: 0: 45.02%, 1: 45.62%, 2: 42.30%, 3: 39.27%, 4: 35.05%, 5: 34.44%, 6: 34.14%, 7: 33.53%, 8: 35.05%
    2022-04-10T17:10:13.758Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":1655,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg11_raw.mkv","width":1280}
    2022-04-10T17:10:14.079Z - error: Server read frame error message=Command failed with exit code 255: /home/ubuntu/ffmpeg-4.4-amd64-static/ffmpeg -hide_banner -ss 0 -noautorotate -i /seg11_raw.mkv -an -vf fps=30 -map 0:v:0 -q:v 5 -pix_fmt rgba -vcodec mjpeg -f image2pipe -, stack=Error: Command failed with exit code 255: /home/ubuntu/ffmpeg-4.4-amd64-static/ffmpeg -hide_banner -ss 0 -noautorotate -i /seg11_raw.mkv -an -vf fps=30 -map 0:v:0 -q:v 5 -pix_fmt rgba -vcodec mjpeg -f image2pipe -
        at makeError (/home/ubuntu/source/packages/backend/node_modules/execa/lib/error.js:60:11)
        at handlePromise (/home/ubuntu/source/packages/backend/node_modules/execa/index.js:118:26)
        at runMicrotasks (<anonymous>)
        at processTicksAndRejections (node:internal/process/task_queues:96:5)
        at async readFrame (/home/ubuntu/source/packages/backend/node_modules/@reactive-video/builder/videoServer.js:191:19)
        at async /home/ubuntu/source/packages/backend/node_modules/@reactive-video/builder/server.js:50:34, shortMessage=Command failed with exit code 255: /home/ubuntu/ffmpeg-4.4-amd64-static/ffmpeg -hide_banner -ss 0 -noautorotate -i /seg11_raw.mkv -an -vf fps=30 -map 0:v:0 -q:v 5 -pix_fmt rgba -vcodec mjpeg -f image2pipe -, command=/home/ubuntu/ffmpeg-4.4-amd64-static/ffmpeg -hide_banner -ss 0 -noautorotate -i /seg11_raw.mkv -an -vf fps=30 -map 0:v:0 -q:v 5 -pix_fmt rgba -vcodec mjpeg -f image2pipe -, escapedCommand="/home/ubuntu/ffmpeg-4.4-amd64-static/ffmpeg" -hide_banner -ss 0 -noautorotate -i "/seg11_raw.mkv" -an -vf "fps=30" -map "0:v:0" "-q:v" 5 -pix_fmt rgba -vcodec mjpeg -f image2pipe -, exitCode=255, signal=undefined, signalDescription=undefined, stdout=undefined, stderr=undefined, failed=true, timedOut=false, isCanceled=false, killed=true
    2022-04-10T17:10:14.183Z - info: Part 5,1770 log Failed to load resource: the server responded with a status of 400 (Bad Request)
    2022-04-10T17:10:14.509Z - info: Progress 39.27% FPS: 27.01 Parts: 0: 45.92%, 1: 46.83%, 2: 43.50%, 3: 40.48%, 4: 36.25%, 5: 34.74%, 6: 35.35%, 7: 34.44%, 8: 35.95%
    2022-04-10T17:10:15.264Z - info: Progress 40.28% FPS: 27.22 Parts: 0: 46.53%, 1: 48.04%, 2: 45.02%, 3: 41.69%, 4: 37.46%, 5: 35.95%, 6: 35.95%, 7: 35.35%, 8: 36.56%
    2022-04-10T17:10:16.157Z - info: Progress 41.29% FPS: 27.35 Parts: 0: 47.13%, 1: 49.55%, 2: 45.92%, 3: 42.90%, 4: 38.37%, 5: 37.46%, 6: 36.86%, 7: 35.95%, 8: 37.46%
    2022-04-10T17:10:16.919Z - info: Progress 42.30% FPS: 27.55 Parts: 0: 47.73%, 1: 51.06%, 2: 47.13%, 3: 44.11%, 4: 39.58%, 5: 38.37%, 6: 37.46%, 7: 36.86%, 8: 38.37%
    2022-04-10T17:10:17.690Z - info: Progress 43.30% FPS: 27.74 Parts: 0: 48.64%, 1: 52.57%, 2: 48.04%, 3: 45.62%, 4: 40.79%, 5: 39.27%, 6: 38.37%, 7: 37.46%, 8: 38.97%
    2022-04-10T17:10:17.836Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":1986,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg13_raw.mkv","width":1280}
    2022-04-10T17:10:18.616Z - info: Progress 44.31% FPS: 27.83 Parts: 0: 49.55%, 1: 53.78%, 2: 49.24%, 3: 46.83%, 4: 41.99%, 5: 40.48%, 6: 38.37%, 7: 38.37%, 8: 40.18%
    2022-04-10T17:10:19.619Z - info: Progress 45.32% FPS: 27.87 Parts: 0: 50.45%, 1: 55.29%, 2: 50.45%, 3: 48.34%, 4: 42.60%, 5: 41.39%, 6: 39.58%, 7: 38.67%, 8: 41.09%
    2022-04-10T17:10:20.450Z - info: Progress 46.32% FPS: 28.01 Parts: 0: 51.36%, 1: 56.19%, 2: 51.06%, 3: 49.24%, 4: 43.81%, 5: 42.90%, 6: 40.79%, 7: 39.58%, 8: 41.99%
    2022-04-10T17:10:21.163Z - info: Progress 47.33% FPS: 28.21 Parts: 0: 51.96%, 1: 57.40%, 2: 52.27%, 3: 50.45%, 4: 44.71%, 5: 44.11%, 6: 41.99%, 7: 40.18%, 8: 42.90%
    2022-04-10T17:10:21.938Z - info: Progress 48.34% FPS: 28.37 Parts: 0: 52.87%, 1: 58.31%, 2: 53.17%, 3: 51.96%, 4: 45.92%, 5: 45.32%, 6: 43.20%, 7: 40.79%, 8: 43.50%
    2022-04-10T17:10:22.766Z - info: Progress 49.35% FPS: 28.50 Parts: 0: 53.78%, 1: 59.21%, 2: 54.08%, 3: 52.87%, 4: 47.13%, 5: 46.53%, 6: 44.41%, 7: 41.69%, 8: 44.41%
    2022-04-10T17:10:23.189Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":2317,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg15_raw.mkv","width":1280}
    2022-04-10T17:10:23.583Z - info: Progress 50.35% FPS: 28.63 Parts: 0: 54.68%, 1: 60.73%, 2: 55.29%, 3: 54.08%, 4: 48.34%, 5: 47.73%, 6: 45.32%, 7: 41.99%, 8: 45.02%
    2022-04-10T17:10:24.260Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":2648,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg17_raw.mkv","width":1280}
    2022-04-10T17:10:24.315Z - info: Progress 51.36% FPS: 28.80 Parts: 0: 55.59%, 1: 61.93%, 2: 56.19%, 3: 55.29%, 4: 49.24%, 5: 48.94%, 6: 46.53%, 7: 42.90%, 8: 45.62%
    2022-04-10T17:10:25.069Z - info: Progress 52.37% FPS: 28.95 Parts: 0: 56.50%, 1: 62.84%, 2: 57.40%, 3: 56.50%, 4: 50.45%, 5: 50.15%, 6: 47.73%, 7: 43.81%, 8: 45.92%
    2022-04-10T17:10:25.075Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":331,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg4_raw.mkv","width":1280}
    2022-04-10T17:10:25.995Z - info: Progress 53.37% FPS: 29.01 Parts: 0: 57.10%, 1: 63.14%, 2: 58.31%, 3: 58.01%, 4: 51.66%, 5: 51.36%, 6: 48.94%, 7: 44.71%, 8: 47.13%
    2022-04-10T17:10:26.637Z - info: Progress 54.38% FPS: 29.21 Parts: 0: 58.01%, 1: 64.05%, 2: 59.52%, 3: 58.91%, 4: 52.57%, 5: 52.57%, 6: 49.85%, 7: 45.92%, 8: 48.04%
    2022-04-10T17:10:27.299Z - info: Progress 55.39% FPS: 29.40 Parts: 0: 58.61%, 1: 64.65%, 2: 60.42%, 3: 60.12%, 4: 53.78%, 5: 53.78%, 6: 50.76%, 7: 47.13%, 8: 49.24%
    2022-04-10T17:10:27.986Z - info: Progress 56.39% FPS: 29.58 Parts: 0: 59.21%, 1: 65.26%, 2: 61.63%, 3: 61.33%, 4: 54.68%, 5: 54.98%, 6: 51.96%, 7: 48.34%, 8: 50.15%
    2022-04-10T17:10:28.524Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":662,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg6_raw.mkv","width":1280}
    2022-04-10T17:10:28.739Z - info: Progress 57.40% FPS: 29.71 Parts: 0: 60.12%, 1: 66.16%, 2: 61.93%, 3: 62.54%, 4: 55.89%, 5: 56.19%, 6: 53.17%, 7: 49.55%, 8: 51.06%
    2022-04-10T17:10:29.620Z - info: Progress 58.41% FPS: 29.78 Parts: 0: 61.03%, 1: 67.07%, 2: 62.24%, 3: 63.75%, 4: 56.80%, 5: 57.70%, 6: 54.08%, 7: 50.76%, 8: 52.27%
    2022-04-10T17:10:30.545Z - info: Progress 59.42% FPS: 29.82 Parts: 0: 61.63%, 1: 67.98%, 2: 63.14%, 3: 64.95%, 4: 57.70%, 5: 58.91%, 6: 55.29%, 7: 51.66%, 8: 53.47%
    2022-04-10T17:10:31.313Z - info: Progress 60.42% FPS: 29.94 Parts: 0: 62.54%, 1: 68.58%, 2: 63.75%, 3: 66.16%, 4: 58.91%, 5: 60.12%, 6: 56.50%, 7: 52.87%, 8: 54.38%
    2022-04-10T17:10:32.054Z - info: Progress 61.43% FPS: 30.06 Parts: 0: 63.14%, 1: 69.49%, 2: 64.65%, 3: 67.37%, 4: 59.82%, 5: 61.63%, 6: 57.40%, 7: 53.78%, 8: 55.59%
    2022-04-10T17:10:32.882Z - info: Progress 62.44% FPS: 30.15 Parts: 0: 64.05%, 1: 70.09%, 2: 65.26%, 3: 68.58%, 4: 61.03%, 5: 63.14%, 6: 58.61%, 7: 54.68%, 8: 56.50%
    2022-04-10T17:10:33.653Z - info: Progress 63.44% FPS: 30.26 Parts: 0: 64.65%, 1: 71.00%, 2: 65.86%, 3: 69.79%, 4: 61.93%, 5: 64.35%, 6: 59.52%, 7: 55.89%, 8: 58.01%
    2022-04-10T17:10:34.421Z - info: Progress 64.45% FPS: 30.36 Parts: 0: 65.56%, 1: 71.60%, 2: 66.77%, 3: 71.00%, 4: 63.14%, 5: 65.56%, 6: 60.73%, 7: 56.80%, 8: 58.91%
    2022-04-10T17:10:35.143Z - info: Progress 65.46% FPS: 30.49 Parts: 0: 66.47%, 1: 72.21%, 2: 67.67%, 3: 72.21%, 4: 64.05%, 5: 67.07%, 6: 61.63%, 7: 58.01%, 8: 59.82%
    2022-04-10T17:10:36.010Z - info: Progress 66.47% FPS: 30.54 Parts: 0: 67.07%, 1: 73.11%, 2: 68.28%, 3: 73.72%, 4: 65.26%, 5: 68.28%, 6: 62.54%, 7: 59.21%, 8: 60.73%
    2022-04-10T17:10:36.793Z - info: Progress 67.47% FPS: 30.64 Parts: 0: 67.67%, 1: 74.02%, 2: 69.18%, 3: 74.92%, 4: 66.16%, 5: 69.18%, 6: 63.75%, 7: 60.42%, 8: 61.93%
    2022-04-10T17:10:37.630Z - info: Progress 68.48% FPS: 30.70 Parts: 0: 68.58%, 1: 74.62%, 2: 69.79%, 3: 76.13%, 4: 67.37%, 5: 70.09%, 6: 64.95%, 7: 61.93%, 8: 62.84%
    2022-04-10T17:10:38.366Z - info: Progress 69.49% FPS: 30.81 Parts: 0: 69.49%, 1: 75.53%, 2: 70.39%, 3: 77.34%, 4: 67.98%, 5: 71.30%, 6: 66.16%, 7: 63.14%, 8: 64.05%
    2022-04-10T17:10:38.904Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":993,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg8_raw.mkv","width":1280}
    2022-04-10T17:10:39.299Z - info: Progress 70.49% FPS: 30.83 Parts: 0: 70.09%, 1: 76.44%, 2: 71.30%, 3: 77.64%, 4: 69.18%, 5: 72.81%, 6: 67.67%, 7: 64.05%, 8: 65.26%
    2022-04-10T17:10:40.044Z - info: Progress 71.50% FPS: 30.93 Parts: 0: 71.00%, 1: 77.34%, 2: 72.21%, 3: 77.95%, 4: 70.39%, 5: 74.32%, 6: 68.58%, 7: 65.26%, 8: 66.47%
    2022-04-10T17:10:41.012Z - info: Progress 72.51% FPS: 30.93 Parts: 0: 71.60%, 1: 77.95%, 2: 72.81%, 3: 78.85%, 4: 71.60%, 5: 75.53%, 6: 69.79%, 7: 66.47%, 8: 67.98%
    2022-04-10T17:10:41.797Z - info: Progress 73.51% FPS: 31.01 Parts: 0: 72.51%, 1: 78.85%, 2: 73.72%, 3: 79.76%, 4: 72.51%, 5: 76.74%, 6: 70.69%, 7: 67.67%, 8: 69.18%
    2022-04-10T17:10:42.672Z - info: Progress 74.52% FPS: 31.05 Parts: 0: 73.11%, 1: 79.46%, 2: 74.32%, 3: 80.66%, 4: 73.72%, 5: 78.25%, 6: 72.21%, 7: 68.88%, 8: 70.09%
    2022-04-10T17:10:43.461Z - info: Progress 75.53% FPS: 31.13 Parts: 0: 74.02%, 1: 80.36%, 2: 74.92%, 3: 81.27%, 4: 74.62%, 5: 79.15%, 6: 73.72%, 7: 70.09%, 8: 71.60%
    2022-04-10T17:10:44.014Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":1324,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg10_raw.mkv","width":1280}
    2022-04-10T17:10:44.214Z - info: Progress 76.54% FPS: 31.22 Parts: 0: 74.92%, 1: 81.27%, 2: 75.83%, 3: 82.18%, 4: 74.92%, 5: 80.66%, 6: 74.62%, 7: 71.30%, 8: 73.11%
    2022-04-10T17:10:45.084Z - info: Progress 77.54% FPS: 31.26 Parts: 0: 75.83%, 1: 81.87%, 2: 76.44%, 3: 83.08%, 4: 75.23%, 5: 82.18%, 6: 76.13%, 7: 72.81%, 8: 74.32%
    2022-04-10T17:10:46.028Z - info: Progress 78.55% FPS: 31.27 Parts: 0: 76.74%, 1: 82.78%, 2: 77.34%, 3: 83.99%, 4: 76.13%, 5: 83.69%, 6: 77.04%, 7: 74.02%, 8: 75.23%
    2022-04-10T17:10:46.870Z - info: Progress 79.56% FPS: 31.31 Parts: 0: 77.34%, 1: 83.69%, 2: 77.95%, 3: 84.89%, 4: 76.74%, 5: 84.89%, 6: 78.25%, 7: 75.53%, 8: 76.74%
    2022-04-10T17:10:47.787Z - info: Progress 80.56% FPS: 31.33 Parts: 0: 78.25%, 1: 84.59%, 2: 78.85%, 3: 85.80%, 4: 77.64%, 5: 86.40%, 6: 79.46%, 7: 76.44%, 8: 77.64%
    2022-04-10T17:10:48.714Z - info: Progress 81.57% FPS: 31.34 Parts: 0: 78.85%, 1: 85.20%, 2: 79.46%, 3: 86.71%, 4: 78.55%, 5: 87.61%, 6: 80.66%, 7: 77.95%, 8: 79.15%
    2022-04-10T17:10:49.462Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":1655,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg12_raw.mkv","width":1280}
    2022-04-10T17:10:49.765Z - info: Progress 82.58% FPS: 31.31 Parts: 0: 79.76%, 1: 86.40%, 2: 80.36%, 3: 87.61%, 4: 79.46%, 5: 88.22%, 6: 82.18%, 7: 79.15%, 8: 80.06%
    2022-04-10T17:10:50.791Z - info: Progress 83.59% FPS: 31.28 Parts: 0: 80.66%, 1: 87.31%, 2: 81.57%, 3: 88.52%, 4: 80.36%, 5: 88.82%, 6: 83.08%, 7: 80.66%, 8: 81.27%
    2022-04-10T17:10:51.157Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":1986,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg14_raw.mkv","width":1280}
    2022-04-10T17:10:52.118Z - info: Progress 84.59% FPS: 31.14 Parts: 0: 81.57%, 1: 88.52%, 2: 82.18%, 3: 89.73%, 4: 81.27%, 5: 89.73%, 6: 83.69%, 7: 82.78%, 8: 81.87%
    2022-04-10T17:10:53.154Z - info: Progress 85.60% FPS: 31.11 Parts: 0: 82.48%, 1: 89.43%, 2: 83.08%, 3: 90.94%, 4: 82.18%, 5: 90.63%, 6: 84.29%, 7: 84.29%, 8: 83.08%
    2022-04-10T17:10:54.104Z - info: Progress 86.61% FPS: 31.11 Parts: 0: 83.38%, 1: 90.33%, 2: 83.99%, 3: 91.54%, 4: 83.08%, 5: 91.54%, 6: 85.20%, 7: 86.10%, 8: 84.29%
    2022-04-10T17:10:55.069Z - info: Progress 87.61% FPS: 31.11 Parts: 0: 84.29%, 1: 91.24%, 2: 84.89%, 3: 92.45%, 4: 83.99%, 5: 92.45%, 6: 86.40%, 7: 87.31%, 8: 85.50%
    2022-04-10T17:10:55.991Z - info: Progress 88.62% FPS: 31.13 Parts: 0: 85.20%, 1: 92.15%, 2: 85.80%, 3: 93.35%, 4: 84.89%, 5: 93.35%, 6: 87.31%, 7: 88.82%, 8: 86.71%
    2022-04-10T17:10:57.083Z - info: Progress 89.63% FPS: 31.08 Parts: 0: 86.40%, 1: 93.05%, 2: 86.71%, 3: 94.26%, 4: 85.80%, 5: 94.26%, 6: 88.22%, 7: 90.03%, 8: 87.92%
    2022-04-10T17:10:58.154Z - info: Progress 90.63% FPS: 31.05 Parts: 0: 87.31%, 1: 93.96%, 2: 87.61%, 3: 95.17%, 4: 86.71%, 5: 95.17%, 6: 88.82%, 7: 91.84%, 8: 89.12%
    2022-04-10T17:10:59.137Z - info: Progress 91.64% FPS: 31.04 Parts: 0: 87.92%, 1: 94.86%, 2: 88.52%, 3: 96.07%, 4: 87.31%, 5: 96.07%, 6: 89.73%, 7: 93.66%, 8: 90.63%
    2022-04-10T17:11:00.128Z - info: Progress 92.65% FPS: 31.03 Parts: 0: 88.52%, 1: 95.77%, 2: 89.43%, 3: 96.68%, 4: 88.52%, 5: 96.98%, 6: 90.63%, 7: 95.47%, 8: 91.84%
    2022-04-10T17:11:01.053Z - info: createFfmpeg {"ffmpegStreamFormat":"jpeg","fileFps":30,"fps":30,"height":720,"jpegQuality":90,"renderId":2317,"scale":null,"secret":"VRgcqmW0jdBPKlcgymWsxxwyCPXIpPUCGEanDniAWL8=","streamIndex":0,"uri":"file:///seg16_raw.mkv","width":1280}
    2022-04-10T17:11:01.361Z - info: Progress 93.66% FPS: 30.94 Parts: 0: 89.43%, 1: 96.68%, 2: 90.33%, 3: 97.89%, 4: 89.43%, 5: 97.89%, 6: 91.54%, 7: 96.37%, 8: 93.35%
    2022-04-10T17:11:02.525Z - info: Progress 94.66% FPS: 30.87 Parts: 0: 90.33%, 1: 97.58%, 2: 91.24%, 3: 98.79%, 4: 90.63%, 5: 98.79%, 6: 92.75%, 7: 96.98%, 8: 94.86%
    2022-04-10T17:11:03.218Z - info: Output ffmpeg exited with code 0
    2022-04-10T17:11:03.377Z - info: Output ffmpeg exited with code 0
    2022-04-10T17:11:03.501Z - info: Progress 95.67% FPS: 30.87 Parts: 0: 91.24%, 1: 98.49%, 2: 92.45%, 3: 99.70%, 4: 91.54%, 5: 99.70%, 6: 93.66%, 7: 98.19%, 8: 96.07%
    2022-04-10T17:11:04.711Z - info: Output ffmpeg exited with code 0
    2022-04-10T17:11:04.747Z - info: Progress 96.68% FPS: 30.78 Parts: 0: 92.45%, 1: 99.70%, 2: 93.35%, 3: 99.70%, 4: 92.45%, 5: 99.70%, 6: 94.86%, 7: 99.70%, 8: 98.19%
    2022-04-10T17:11:04.833Z - info: Output ffmpeg exited with code 0
    2022-04-10T17:11:05.411Z - info: Output ffmpeg exited with code 0
    2022-04-10T17:11:06.082Z - info: Progress 97.68% FPS: 30.66 Parts: 0: 94.56%, 1: 99.70%, 2: 95.17%, 3: 99.70%, 4: 94.26%, 5: 99.70%, 6: 96.68%, 7: 99.70%, 8: 99.70%
    2022-04-10T17:11:07.580Z - info: Progress 98.69% FPS: 30.50 Parts: 0: 96.68%, 1: 99.70%, 2: 97.28%, 3: 99.70%, 4: 96.68%, 5: 99.70%, 6: 99.09%, 7: 99.70%, 8: 99.70%
    2022-04-10T17:11:07.935Z - info: Output ffmpeg exited with code 0
    2022-04-10T17:11:08.775Z - info: Output ffmpeg exited with code 0
    2022-04-10T17:11:09.236Z - info: Output ffmpeg exited with code 0
    2022-04-10T17:11:09.353Z - info: Progress 99.70% FPS: 30.25 Parts: 0: 99.70%, 1: 99.70%, 2: 99.70%, 3: 99.70%, 4: 99.70%, 5: 99.70%, 6: 99.70%, 7: 99.70%, 8: 99.70%
    2022-04-10T17:11:09.356Z - info: Output ffmpeg exited with code 0
    2022-04-10T17:11:09.397Z - info: Terminating renderer workers
    2022-04-10T17:11:09.414Z - info: Merging parts
    2022-04-10T17:11:10.724Z - info: Stopping bundle watcher
    2022-04-10T17:11:10.727Z - info: Bundle watcher stopped
    2022-04-10T17:11:10.727Z - info: Edit finished: /reactive-video.mkv
    
    bug 
    opened by mifi 1
  • `Page crashed!`, `net::ERR_INSUFFICIENT_RESOURCES` errors

    `Page crashed!`, `net::ERR_INSUFFICIENT_RESOURCES` errors

    When running with high concurrency (many browser instances), I'm experiencing these errors after a few seconds of running on Ubuntu:

    • fatal Page crashed! error
    • net::ERR_INSUFFICIENT_RESOURCES from <FFmpegVideo> <img> error event.

    After a lot of digging I found out that it's because the system is running out of disk space. The disk space is being claimed by files that are immediately deleted by chromium (so they don't show up in du -hs) inside the /tmp folder, which has limited space. The files can be seen with lsof:

    /tmp/.org.chromium.Chromium.0FNTrV
    /tmp/.org.chromium.Chromium.Ra8ezE
    /tmp/.org.chromium.Chromium.nQK7nC
    /tmp/.org.chromium.Chromium.WQadCm
    /tmp/.org.chromium.Chromium.IzapN6
    /tmp/.org.chromium.Chromium.Mq2VFV
    ...
    

    I've tried these options to puppeteer but none seem to affect these tmp files:

    PUPPETEER_TMP_DIR
    page.setCacheEnabled(false);
    --disk-cache-dir
    --media-cache-size=0
    --disk-cache-size=0
    

    However what turns out to work is to remove the --disable-dev-shm-usage from puppeteer/chromium! If this flag is removed, the files will instead be stored in /dev/shm which has a lot more space (usually many gigabytes on larger AWS EC2 machines). Turns out that the flag was added by default to puppeteer in https://github.com/puppeteer/puppeteer/commit/18f2ecdffdfc70e891750b570bfe8bea5b5ca8c2 - interesting discussion here: https://github.com/puppeteer/puppeteer/issues/1834

    Use ignoreDefaultArgs: ['--disable-dev-shm-usage']

    See also:

    • https://stackoverflow.com/questions/24122506/neterr-insufficient-resources-error-when-adding-numerous-img-elements-to-dom
    • https://bugs.chromium.org/p/chromium/issues/detail?id=715363
    • https://bugs.chromium.org/p/chromium/issues/detail?id=1085829
    • https://bugs.chromium.org/p/chromium/issues/detail?id=333996
    • https://bugs.chromium.org/p/chromium/issues/detail?id=265642
    • https://bugs.chromium.org/p/chromium/issues/detail?id=736452
    • https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md#tips
    • https://github.com/puppeteer/puppeteer/issues/6286
    • https://stackoverflow.com/questions/57956697/unhandledpromiserejectionwarning-error-page-crashed-while-using-puppeteer
    • https://bugs.chromium.org/p/chromium/issues/detail?id=108055
    opened by mifi 1
  • Allow passing more args to Puppeteer

    Allow passing more args to Puppeteer

    It makes possible to add ['--no-sandbox', '--disable-setuid-sandbox'] (Setting Up Chrome Linux Sandbox) for solving https://github.com/mifi/reactive-video/issues/7

    opened by IvanDhalluin 1
  • Cloud - Puppeteer args

    Cloud - Puppeteer args

    Hi, I am using your lib to run with GCP Cloud Run. It works great!

    My only concern is that I needed to disable Puppeteer sandbox : '--no-sandbox', '--disable-setuid-sandbox' (Setting Up Chrome Linux Sandbox)

    Maybe you can allow access to Puppeteer args in Editor config?

    opened by IvanDhalluin 1
  • Sporadic blank frames (canvas/img)

    Sporadic blank frames (canvas/img)

    Sometimes screenshot will take a screenshot before canvas/image has finished rendering.

    Observations/testing:

    • More easily reproduceable with high concurrency like 30
    • Any other elements on the page will be screenshotted but not the canvas or img (type png or raw), which are sourced from the ffmpeg data: https://github.com/mifi/reactive-video/blob/65a19364f2b3e21fc2c813eb931ffd8140ff2a5d/packages/frontend/src/components/FFmpegVideo.js#L39
      • I tried a scene with one Image, one FFmpegVideo and some text - only the Image and text got rendered
    • From testing, I have confirmed that ffmpeg is not returning white frames
      • There are never any white frames returned from the canvas's ctx.getImageData()
    • when adding a border to the canvas or image, the border does not show in the screenshot when the issue is triggered, so the html element is really not rendered yet at the time of screeshot
    • also converting canvas to canvas.dataURL() and setting on src on img yields the same sporadic issue
    • multiple setTimeout(..., 0) and multiple requestAnimationFrame does not help. (or multiple awaitDomRenderSettled)
    • png seems to produce more frequently than raw (maybe due to higher CPU usage)
    • captureType screenshot can reproduce it but screencast seems to reproduce even more often
    • Tends to happen at the first frame after puppeteer boots up (on the first frame of some random part when multiple parts), maybe due to high CPU

    Workarounds

    • setTimeout(500) or page.waitForNetworkIdle (which I think also waits for 500ms) will workaround this issue but it's a hack because it's not real synchronisation and may in theory fail some time.
    • Render the first frame of each part twice and check if equal, or just always render first frame of each part twice

    Alternatives

    Doesn't work

    const rect = imgRef.current.getBoundingClientRect();
    if (!rect.width || !rect.height) throw new Error('wh');
    
    await new Promise((resolve, reject) => {
      const observer = new IntersectionObserver((entries) => {
        if (entries[0].isIntersecting) {
          // el is visible
          resolve();
        } else {
          // el is not visible
          reject(new Error('invis'));
        }
      });
      observer.observe(imgRef.current);
    })
    
    await new Promise((resolve, reject) => {
      let timeout2;
      const timeout = setTimeout(() => {
        clearTimeout(timeout2);
        reject(new Error('Image never completed'));
      }, 10000);
    
      function checkComplete() {
        if (imgRef.current.complete && imgRef.current.naturalWidth > ) {
          clearTimeout(timeout);
          resolve();
          return;
        }
    
        timeout2 = setTimeout(checkComplete, 100);
      }
    
      checkComplete();
    });
    

    HeadlessExperimental frame control

    • https://docs.google.com/document/d/1PppegrpXhOzKKAuNlP6XOEnviXFGUiX2hop00Cxcv4o/edit#
    • https://groups.google.com/a/chromium.org/g/headless-dev/c/S5CoLs46AiE?pli=1

    Not tried

    • callback from ReactDOM.render(element, container[, callback]) https://reactjs.org/docs/react-dom.html#render
    • https://pptr.dev/#?product=Puppeteer&version=v5.2.1&show=api-elementhandleboundingbox
    • https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitforselectorselector-options https://github.com/puppeteer/puppeteer/blob/1de9906260269491c9011fcab33a58e280603fd3/lib/DOMWorld.js#L505

    Links

    • https://stackoverflow.com/questions/15875128/is-there-element-rendered-event
    • https://stackoverflow.com/questions/26556436/react-after-render-code

    Possibly related

    • https://github.com/puppeteer/puppeteer/issues/5352
    opened by mifi 1
  • Improve test similarity checks

    Improve test similarity checks

    jest-image-snapshot already uses ssim, but for our video comparison we could also use it to reduce false test failures due to compression artifact differences:

    • https://github.com/obartra/ssim
    • https://ottverse.com/calculate-psnr-vmaf-ssim-using-ffmpeg/
    enhancement 
    opened by mifi 0
  • Error running example

    Error running example

    I created both index.js and MyVideo.js with the examples provided. however, when I run index.js I get this error:

    ERROR in ./node_modules/@reactive-video/builder/previewEntry.js 38:4
    Module parse failed: Unexpected token (38:4)
    You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
    |
    |   return (
    >     <>
    |       <input type="range" min={0} max={durationFrames - 1} onChange={(e) => handleCurrentFrameChange(parseInt(e.target.value, 10))} value={currentFrame} style={{ width: '100%', margin: '10px 0' }} />
    |
    
    webpack 5.72.0 compiled with 1 error in 1580 ms
    
    opened by seriiix 4
Releases(v1.0.5)
Owner
Mikael Finstad
App developer 🇳🇴 Creator of LosslessCut and full-stack JS contractor.
Mikael Finstad
Lightweight customizable placeholders for third party content of your website (e.g. Youtube Videos) compatible with the Usercentrics CMP.

Usercentrics Widgets Lightweight customizable placeholders for third party content of your website (e.g. Youtube Videos) compatible with the Usercentr

Netresearch 3 Nov 17, 2022
A tool to download all videos and convert to mp3 inside a video set of bilibili.

bilibili-video2mp3 A tool to download all videos and convert to mp3 inside a video set of bilibili (also works for single video, of course). You will

wxsm 23 Dec 15, 2022
Um simples bot para o Telegram que baixa vídeos e áudios do TikTok & outras funcionalidades

Kelle Estella (Telegram) Um simples bot para o Telegram que baixa vídeos e áudios do TikTok & outras funcionalidades. Clique aqui para utilizá-lo. Com

Luis Gabriel Araújo 3 Apr 20, 2022
A program that makes scripting videos easier.

A program that makes scripting videos easier. Scripts can be written using only the keyboard.

Samuel Albert 18 Jun 22, 2022
Scraper for TikTok. Download videos, music, fetch users info and more.

tiktok-scraper A fast light-weight scraper for tiktok to fetch and download video posts, video music, user info and more. Installation npm i tiktok-sc

null 41 Jan 1, 2023
Compress program that uses H264,VP9 and Vorbis algorithms with ffmpeg to compress anime videos and audios

Vaniply Compress tool to compress videos and audios using H264,VP9 and Vorbis algorithms Installation and running Just clone the repository and open a

null 18 Oct 15, 2022
Bookwise is a video library web app that consists of a collection of Videos

Bookwise is a video library web app that consists of a collection of Videos. It has features such as like videos, creating playlists, adding videos to playlists, adding to watch later, history, feed, etc. but of a specific niche.

Rutvik Umak 18 Jun 13, 2022
Compress program that uses H264,VP9 and Vorbis algorithms with ffmpeg to compress anime videos and audios

Vaniply Compress tool to compress videos and audios using H264,VP9 and Vorbis algorithms Installation and running Just clone the repository and open a

OpenAnime 20 May 30, 2022
A lightweight web component helper for HTML5 videos.

Video Radio Star A lightweight web component helper for HTML5 videos. Intended for use with muted by default HTML5 videos. Demo Demo out of viewport u

Zach Leatherman 58 Dec 12, 2022
A JavaScript library for optimizing html pages with video content that prevents videos from loading on mobile devices.

?? js-vido — JavaScript Video Download Optimizer A JavaScript library for optimizing html pages with video content that prevents videos from loading o

Ariel Montes 1 Feb 9, 2021
Recap let's you recap on your favourite social network videos by downloading them on your devices, from the range of YouTube, SoundCloud, Facebook, Twitter, Instagram, TikTok, Vimeo, Dailymotion, VK, or AOL.

Recap A Social Network Video Downloader Recap let's you recap on your favourite social network videos by downloading them on your devices, from the ra

John Oladele 4 Sep 24, 2022
Saturn Stealer is a tool for create a server and the create malware, themalware is discord token straler/grabber.

Saturn-Stealer ⚠️ It is strictly forbidden to use this software for illegal purposes. This software was coded for educational purposes. The developer

ENDLEPH 13 Aug 28, 2022
Audio visualizer library for javascript. Create dynamic animations that react to an audio file or audio stream.

Wave.js Audio visualizer library for javascript. Installation Install With CDN <script src="https://cdn.jsdelivr.net/gh/foobar404/wave.js/dist/bundle.

Austin Michaud λ 497 Dec 21, 2022
An simple package to create an Activity in Discord Voice Channel using Discord.js

discordjs-activity An simple package to create an Activity in Discord Voice Channel using Discord.js ?? | Installation npm install discordjs-activity

Sudhan 55 Nov 15, 2022
QBCore - Create codes using discord bot to redeem items & cash in your server!

Things you should know: The code was built for Old QBCore, you can of course change it to new if you want. (If you need help feel free to ask) When yo

NaorNC 16 Dec 10, 2022
A documentation bot built using slash-create for its documentation, functionality derived from Eris Docs bot.

docs-bot A service that handles navigation of a docgen project manifest. Commands All arguments are required. $ npx slash-up list /docs - Search docu

/create 4 Dec 15, 2022
Create custom would you rather questions for our discord bot using this simple ui tool!

Json Generator How to run the project Install the VSCode Live Server Extention. Navigate to the html file. Start the Live Server. Want to contribute?

Would You Bot 7 Dec 15, 2022
A web video player built for the HTML5 world using React library.

video-react Video.React is a web video player built from the ground up for an HTML5 world using React library. Installation Install video-react and pe

null 2.4k Jan 6, 2023
Web Application that represents a music player using the spotify API, React, JS, CSS, HTML, nodeJS, Firebase, material-ui, JSON and other technologies. Made by Yohan Hmaiti

Web Application that represents a music player using the spotify API, React, JS, CSS, HTML, nodeJS, Firebase, material-ui, JSON and other technologies. Made by Yohan Hmaiti

Yohan Hmaiti 2 Jan 8, 2022