shiveshnavin commited on
Commit
9a00d8d
·
1 Parent(s): a49c134

Add proxy render

Browse files
Files changed (6) hide show
  1. package.ci.json +1 -1
  2. proxy-renderer.js +73 -52
  3. renderer.js +2 -2
  4. routes.js +3 -2
  5. ssr.js +2 -2
  6. start.sh +0 -32
package.ci.json CHANGED
@@ -9,7 +9,7 @@
9
  "scripts": {
10
  "submodule": "git submodule init && git submodule update",
11
  "ci": "echo Runnin on CI",
12
- "start": "remotion studio --log=verbose --disable-git-source --port=3000 & PORT=8080 node server.js",
13
  "bundle": "echo -n | remotion bundle",
14
  "skip-font-warn": "sed -E -i \"s/\\bfontsLoaded[[:space:]]*>[[:space:]]*20\\b/fontsLoaded > 20000/g\" build/bundle.js",
15
  "extract32": "set MODIFY_FILES=1 && node app.js",
 
9
  "scripts": {
10
  "submodule": "git submodule init && git submodule update",
11
  "ci": "echo Runnin on CI",
12
+ "start": "node server.js",
13
  "bundle": "echo -n | remotion bundle",
14
  "skip-font-warn": "sed -E -i \"s/\\bfontsLoaded[[:space:]]*>[[:space:]]*20\\b/fontsLoaded > 20000/g\" build/bundle.js",
15
  "extract32": "set MODIFY_FILES=1 && node app.js",
proxy-renderer.js CHANGED
@@ -2,69 +2,90 @@ import { renderFrames, renderStill, stitchFramesToVideo } from '@remotion/render
2
  import { bundle } from '@remotion/bundler';
3
  import path from 'path';
4
  import fs from 'fs';
5
-
 
 
6
  const { RenderUtils } = await import('./src/RenderUtils.cjs');
7
  const { GenerateScript } = await import('./src/GenerateScript.cjs');
8
 
9
  const originalManuScriptPath = path.join(process.cwd(), 'public/original_manuscript.json');
10
-
11
- export const renderProxy = async (outFile, frameRange) => {
 
12
  const ScriptStr = fs.readFileSync(originalManuScriptPath);
13
  const ScriptInput = JSON.parse(ScriptStr);
14
  let {
15
  duration,
16
  Script,
17
- contents,
18
- intro,
19
- outro,
20
- playListsIDs
21
  } = GenerateScript(ScriptInput)
22
- let renderConfig = {
23
- composition: {
24
- id: compositionId,
25
- fps: Script.meta.fps,
26
- height: Script.meta?.resolution?.height,
27
- width: Script.meta?.resolution?.width,
28
- durationInFrames: duration,
29
- defaultProps: Object.assign(Script, {
30
- bgMusic: RenderUtils.getFileName(Script.bgMusic),
31
- contents: contents,
32
- intro: intro,
33
- outro: outro
34
- }),
35
- props: Object.assign(Script, {
36
- bgMusic: RenderUtils.getFileName(Script.bgMusic),
37
- contents: contents,
38
- intro: intro,
39
- outro: outro
40
- }),
41
- },
42
- serveUrl: bundleLocation,
43
- output: path.join(frameOutputDir, 'output.jpg'),
44
- // additional renderer options
45
- audioCodec: 'mp3',
46
- imageFormat: 'jpeg',
47
- enableMultiProcessOnLinux: true,
48
- jpegQuality: 70,
49
- timeoutInMilliseconds: 60000,
50
- concurrency: 1,
51
- gl: 'angle'
52
- }
53
-
54
- if (!fs.existsSync(outputDir)) {
55
- fs.mkdirSync(outputDir, { recursive: true });
56
- }
57
 
58
- const resultVideo = await stitchFramesToVideo({
59
- assetsInfo: result.assetsInfo,
60
- ...renderConfig,
61
- ...renderConfig.composition,
62
- audioCodec: 'mp3',
63
- outputLocation: outFile,
64
- verbose: true
65
- })
66
-
67
- console.log('resultVideo', resultVideo)
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  }
 
2
  import { bundle } from '@remotion/bundler';
3
  import path from 'path';
4
  import fs from 'fs';
5
+ import axios from 'axios';
6
+ import os from 'os'
7
+ import { exec } from 'child_process';
8
  const { RenderUtils } = await import('./src/RenderUtils.cjs');
9
  const { GenerateScript } = await import('./src/GenerateScript.cjs');
10
 
11
  const originalManuScriptPath = path.join(process.cwd(), 'public/original_manuscript.json');
12
+ let cmd = `npm run preview`;
13
+ const childProcess = exec(cmd);
14
+ export const renderProxy = async (outFile, options) => {
15
  const ScriptStr = fs.readFileSync(originalManuScriptPath);
16
  const ScriptInput = JSON.parse(ScriptStr);
17
  let {
18
  duration,
19
  Script,
 
 
 
 
20
  } = GenerateScript(ScriptInput)
21
+ const composition = ScriptInput?.meta?.renderComposition;
22
+ return new Promise((resolve, reject) => {
23
+ const renderOptions = {
24
+ compositionId: composition,
25
+ startFrame: options?.startFrame ?? 0,
26
+ endFrame: options?.endFrame ?? duration - 1,
27
+ logLevel: options?.logLevel ?? "verbose",
28
+ type: options?.type ?? "video",
29
+ outName: outFile ?? "out/output.mp4",
30
+ imageFormat: options?.imageFormat ?? "jpeg",
31
+ jpegQuality: options?.jpegQuality ?? 70,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
 
 
 
 
 
 
 
 
 
 
33
 
34
+ scale: options?.scale ?? 1,
35
+ codec: options?.codec ?? "h264",
36
+ concurrency: options?.concurrency ?? os.cpus().length,
37
+ crf: options?.crf ?? 18,
38
+ muted: options?.muted ?? false,
39
+ enforceAudioTrack: options?.enforceAudioTrack ?? false,
40
+ proResProfile: options?.proResProfile ?? null,
41
+ x264Preset: options?.x264Preset ?? "medium",
42
+ pixelFormat: options?.pixelFormat ?? "yuv420p",
43
+ audioBitrate: options?.audioBitrate ?? null,
44
+ videoBitrate: options?.videoBitrate ?? null,
45
+ everyNthFrame: options?.everyNthFrame ?? 1,
46
+ numberOfGifLoops: options?.numberOfGifLoops ?? null,
47
+ delayRenderTimeout: options?.delayRenderTimeout ?? 300000,
48
+ audioCodec: options?.audioCodec ?? "aac",
49
+ disallowParallelEncoding: options?.disallowParallelEncoding ?? false,
50
+ chromiumOptions: {
51
+ headless: options?.chromiumOptions?.headless ?? true,
52
+ disableWebSecurity: options?.chromiumOptions?.disableWebSecurity ?? false,
53
+ ignoreCertificateErrors: options?.chromiumOptions?.ignoreCertificateErrors ?? false,
54
+ gl: options?.chromiumOptions?.gl ?? null,
55
+ userAgent: options?.chromiumOptions?.userAgent ?? null,
56
+ enableMultiProcessOnLinux: options?.chromiumOptions?.enableMultiProcessOnLinux ?? true
57
+ },
58
+ envVariables: options?.envVariables ?? {},
59
+ serializedInputPropsWithCustomSchema: options?.serializedInputPropsWithCustomSchema ?? JSON.stringify(Script),
60
+ offthreadVideoCacheSizeInBytes: options?.offthreadVideoCacheSizeInBytes ?? null,
61
+ offthreadVideoThreads: options?.offthreadVideoThreads ?? null,
62
+ colorSpace: options?.colorSpace ?? "default",
63
+ multiProcessOnLinux: options?.multiProcessOnLinux ?? true,
64
+ encodingBufferSize: options?.encodingBufferSize ?? null,
65
+ encodingMaxRate: options?.encodingMaxRate ?? null,
66
+ beepOnFinish: options?.beepOnFinish ?? false,
67
+ repro: options?.repro ?? false,
68
+ forSeamlessAacConcatenation: options?.forSeamlessAacConcatenation ?? false,
69
+ separateAudioTo: options?.separateAudioTo ?? null,
70
+ hardwareAcceleration: options?.hardwareAcceleration ?? "disable",
71
+ chromeMode: options?.chromeMode ?? "headless-shell"
72
+ };
73
+ console.log('Invoking studio with', renderOptions)
74
+ axios.post('http://localhost:3000/api/render', renderOptions).then(resp => {
75
+ console.log('Studio started render', resp.data)
76
 
77
+ childProcess.stdout.on('data', (data) => {
78
+ console.log(data)
79
+ if (data.includes('Cleanup: Closing browser instance')) {
80
+ resolve(outFile)
81
+ }
82
+ });
83
+ childProcess.stderr.on('data', (data) => {
84
+ console.error(data)
85
+ if (data.includes('Failed to render')) {
86
+ reject(data)
87
+ }
88
+ });
89
+ }).catch(reject)
90
+ })
91
  }
renderer.js CHANGED
@@ -51,12 +51,12 @@ export function getNpmScript(mediaType) {
51
  export async function doRender(jobId, composition, sendToObserver, target = 'render', ssrOptions, proxyOptions) {
52
  let outFile = path.join(process.cwd(), `out`, `${jobId}-video.mp4`);
53
  if (ssrOptions) {
54
- await renderSSR(outFile, ssrOptions.frameRange)
55
  sendToObserver(jobId, 'completed');
56
  return outFile
57
  }
58
  else if (proxyOptions) {
59
- await renderProxy(outFile, proxyOptions.frameRange)
60
  sendToObserver(jobId, 'completed');
61
  return outFile
62
  }
 
51
  export async function doRender(jobId, composition, sendToObserver, target = 'render', ssrOptions, proxyOptions) {
52
  let outFile = path.join(process.cwd(), `out`, `${jobId}-video.mp4`);
53
  if (ssrOptions) {
54
+ await renderSSR(outFile, ssrOptions.startFrame, ssrOptions.endFrame)
55
  sendToObserver(jobId, 'completed');
56
  return outFile
57
  }
58
  else if (proxyOptions) {
59
+ await renderProxy(outFile, proxyOptions)
60
  sendToObserver(jobId, 'completed');
61
  return outFile
62
  }
routes.js CHANGED
@@ -58,7 +58,7 @@ RenderRouter.post('/api/render-sync', async (req, res) => {
58
  let pref = new PerformanceRecorder();
59
  const dir = path.join(__dirname, 'public')
60
  const zipFile = path.join(dir, `exported-${jobId}.zip`)
61
- if (!existsSync(zipFile)) {
62
  if (!skipClear) {
63
  clear();
64
  }
@@ -78,7 +78,8 @@ RenderRouter.post('/api/render-sync', async (req, res) => {
78
  logs.push(log);
79
  },
80
  getNpmScript(req.query.media_type),
81
- req.body.ssrOptions
 
82
  );
83
  }
84
  const uploader = new FileUploader('oracle', {
 
58
  let pref = new PerformanceRecorder();
59
  const dir = path.join(__dirname, 'public')
60
  const zipFile = path.join(dir, `exported-${jobId}.zip`)
61
+ if (!existsSync(zipFile) || req.body.force || req.query.force) {
62
  if (!skipClear) {
63
  clear();
64
  }
 
78
  logs.push(log);
79
  },
80
  getNpmScript(req.query.media_type),
81
+ req.body.ssr,
82
+ req.body.proxy
83
  );
84
  }
85
  const uploader = new FileUploader('oracle', {
ssr.js CHANGED
@@ -28,7 +28,7 @@ function updateAssetInfo(assetInfoNew) {
28
  fs.writeFileSync(assetsInfoFile, JSON.stringify(assetInfoNew))
29
  }
30
 
31
- export const renderSSR = async (outFile, frameRange) => {
32
  const ScriptStr = fs.readFileSync(originalManuScriptPath);
33
  const ScriptInput = JSON.parse(ScriptStr);
34
  let {
@@ -103,7 +103,7 @@ export const renderSSR = async (outFile, frameRange) => {
103
  },
104
  imageSequencePattern: frameNamePattern,
105
  outputDir: frameOutputDir,
106
- frameRange: frameRange ?? [0, duration - 1],
107
  onFrameUpdate: (rendered, frameIndex, timeTakenPerFrameMs) => {
108
  if (rendered % 10 !== 0 && frameIndex !== duration - 1) return;
109
  const remainingFrames = Math.max(0, duration - frameIndex);
 
28
  fs.writeFileSync(assetsInfoFile, JSON.stringify(assetInfoNew))
29
  }
30
 
31
+ export const renderSSR = async (outFile, startFrame, endFrame) => {
32
  const ScriptStr = fs.readFileSync(originalManuScriptPath);
33
  const ScriptInput = JSON.parse(ScriptStr);
34
  let {
 
103
  },
104
  imageSequencePattern: frameNamePattern,
105
  outputDir: frameOutputDir,
106
+ frameRange: [startFrame ?? 0, endFrame ?? duration - 1],
107
  onFrameUpdate: (rendered, frameIndex, timeTakenPerFrameMs) => {
108
  if (rendered % 10 !== 0 && frameIndex !== duration - 1) return;
109
  const remainingFrames = Math.max(0, duration - frameIndex);
start.sh CHANGED
@@ -1,45 +1,13 @@
1
  #!/usr/bin/env bash
2
  set -e
3
 
4
- # Optional: redirect logs to file /var/log/app.log if you like
5
- # Start your app in background. Assumes `npm start` binds to 0.0.0.0:3000 (and 8083 for renderer).
6
- # If your app needs env vars set, ensure they are available to the container at runtime.
7
-
8
  echo "Starting app (npm start) in background..."
9
  npm start &
10
 
11
  APP_PID=$!
12
  echo "App PID: $APP_PID"
13
 
14
- # Give the app a short moment to start and bind sockets (adjust if needed)
15
  sleep 1
16
 
17
- # Start nginx in foreground to keep the container alive
18
  echo "Starting nginx (foreground)..."
19
  nginx -g 'daemon off;'
20
-
21
- # when nginx exits, container exits (and child app will be killed)
22
- # export DISPLAY=:10.0 && is_pm2=1 node server.js
23
-
24
-
25
- # sudo nano /etc/systemd/system/media-render-farm.service
26
- # sudo systemctl status media-render-farm.service
27
- # sudo systemctl restart media-render-farm.service
28
- # sudo systemctl daemon-reload
29
- # sudo systemctl restart media-render-farm.service
30
- # journalctl -u media-render-farm.service -f
31
-
32
- # [Unit]
33
- # Description=Semibit Media Render Farm
34
- # After=network.target
35
-
36
- # [Service]
37
- # ExecStart=/home/ubuntu/apps/node/semibit-media-render-farm/sstart.sh
38
- # WorkingDirectory=/home/ubuntu/apps/node/semibit-media-render-farm
39
- # Restart=always
40
- # User=ubuntu
41
- # Group=ubuntu
42
- # Environment="NODE_ENV=production"
43
-
44
- # [Install]
45
- # WantedBy=multi-user.target
 
1
  #!/usr/bin/env bash
2
  set -e
3
 
 
 
 
 
4
  echo "Starting app (npm start) in background..."
5
  npm start &
6
 
7
  APP_PID=$!
8
  echo "App PID: $APP_PID"
9
 
 
10
  sleep 1
11
 
 
12
  echo "Starting nginx (foreground)..."
13
  nginx -g 'daemon off;'