Commit f56b21ab by ramdayalmunda

video generation code completed

parent 2a90ab81
module.exports.CONFIG = { module.exports = {
PORT: process.env.PORT || 5000, PORT: process.env.PORT || 5000,
S3_ACCESS_KEY: process.env.S3_ACCESS_KEY, S3_ACCESS_KEY: process.env.S3_ACCESS_KEY,
S3_SECRET_KEY: process.env.S3_SECRET_KEY, S3_SECRET_KEY: process.env.S3_SECRET_KEY,
......
const { STATUS_CODE } = require("../helper/constants") const { STATUS_CODE, TEMP_IMAGE_DIR, TEMP_VIDEO_DIR } = require("../helper/constants")
const { generateCanvas, mergeImages } = require("../helper/tutor-shot") const { generateCanvas, mergeImages } = require("../helper/tutor-shot")
const path = require('path') const path = require('path')
const sharp = require('sharp') const sharp = require('sharp')
const fs = require('fs') const fs = require('fs')
const { createVideoFromImages } = require("../helper/ffmpeg-helper") const { createVideoFromImages } = require("../helper/ffmpeg-helper")
const { deleteFile } = require("../helper/utilities") const { deleteFile } = require("../helper/utilities")
const { generatePreSignedGetUrl } = require("../helper/upload")
module.exports.generateVideo = async function (req, res) { module.exports.generateVideo = async function (req, res) {
console.log('generate Video', req.body) console.log('generate Video')
try { try {
let tutorShotData = req.body.tutorShotData; let tutorShotData = req.body.tutorShotData;
let videoPath = req.body.videoPath let videoPath; // local path of the video file
let thumbnailPath = req.body.thumbnailPath let thumbnailPath // local path of the thumbnail file
let fileName = req.body.fileName let fileName; // remote name of the final video file
let thumbnailName = req.body.thumbnailName let thumbnailName; // remote name of the final thumbnail
if (tutorShotData) { if (tutorShotData) {
console.log('got tutor-shot Data')
let imageDir = path.join(__dirname, '..', 'temporary', 'images') let imageDir = TEMP_IMAGE_DIR
let imagePathString = path.join(imageDir, `${tutorShotData._id}_%d.png`) let imagePathString = path.join(imageDir, `${tutorShotData._id}_%d.png`)
videoPath = path.join(TEMP_VIDEO_DIR, `${tutorShotData._id}.mp4`)
console.log('videoPath', videoPath)
thumbnailPath = path.join(TEMP_IMAGE_DIR, `${tutorShotData._id}_thumbnail`)
fileName = tutorShotData._id
thumbnailName = `${tutorShotData._id}_thumbnail`
// // this is to generate each individual images and get their buffers // // this is to generate each individual images and get their buffers
let frameNumber = 1; let frameNumber = 1;
let imageArr = [] let imageArr = []
for (let i = 0; i < tutorShotData.segments.length; i++) { for (let i = 0; i < tutorShotData.segments.length; i++) {
console.log(i, 'tutor-shot', tutorShotData.segments[i])
if (tutorShotData.segments[i].imageUrl) tutorShotData.segments[i].signedImageUrl = await generatePreSignedGetUrl(tutorShotData.segments[i].imageUrl) if (tutorShotData.segments[i].imageUrl) tutorShotData.segments[i].signedImageUrl = await generatePreSignedGetUrl(tutorShotData.segments[i].imageUrl)
// if (tutorShotData.segments[i].thumbnailUrl) tutorShotData.segments[i].signedThumbnailUrl = await generatePreSignedGetUrl(tutorShotData.segments[i].thumbnailUrl) // if (tutorShotData.segments[i].thumbnailUrl) tutorShotData.segments[i].signedThumbnailUrl = await generatePreSignedGetUrl(tutorShotData.segments[i].thumbnailUrl)
let CE = generateCanvas(tutorShotData.segments[i], { dimension: tutorShotData.segments[i].dimension }) let CE = generateCanvas(tutorShotData.segments[i], { dimension: tutorShotData.segments[i].dimension })
...@@ -34,27 +43,36 @@ module.exports.generateVideo = async function (req, res) { ...@@ -34,27 +43,36 @@ module.exports.generateVideo = async function (req, res) {
{ buffer: await CE.getBuffer() } { buffer: await CE.getBuffer() }
], ],
{ {
// outputType: "buffer", outputType: "buffer",
return: "Buffer",
} }
) )
console.log('mergin image completed')
let limit = 24 * ((tutorShotData.segments[i]?.duration) ? (tutorShotData.segments[i].duration) : 2); let limit = 24 * ((tutorShotData.segments[i]?.duration) ? (tutorShotData.segments[i].duration) : 2);
let frameNum = 0 let frameNum = 0
let firstImage = path.join(imageDir, `${tutorShotData._id}_${frameNumber++}.png`)
await sharp(mergedImage).toFile(firstImage)
imageArr.push(firstImage)
do { do {
let fileName = path.join(imageDir, `${tutorShotData._id}_${frameNumber++}.png`) let fileName = path.join(imageDir, `${tutorShotData._id}_${frameNumber++}.png`)
imageArr.push(fileName) imageArr.push(fileName)
await sharp(mergedImage).toFile(fileName) fs.copyFileSync(firstImage, fileName)
console.log('image generated', fileName)
} while (++frameNum < limit) } while (++frameNum < limit)
if (i == 0 && thumbnailPath) { if (i == 0 && thumbnailPath) {
const imageBase64 = Buffer.from(mergedImage, 'base64'); // Replace 'your_image_buffer_data_here' with your actual image buffer data fs.copyFileSync(firstImage, thumbnailPath)
// Write the buffer data to the file console.log('thumbnail generated')
await fs.writeFile(thumbnailPath, imageBase64);
} }
} }
console.log('---ALL images generated', videoPath)
console.log('___BEFORE__')
console.log('outputFilePath', path.parse(videoPath))
console.log('outputFileName', path.dirname(videoPath).name)
console.log('__CONFIGURED___')
let options = { let options = {
outputFilePath: path.dirname(videoPath), outputFilePath: path.dirname(videoPath),
outputFileName: path.parse(videoPath).name, outputFileName: path.parse(videoPath).name,
...@@ -63,23 +81,26 @@ module.exports.generateVideo = async function (req, res) { ...@@ -63,23 +81,26 @@ module.exports.generateVideo = async function (req, res) {
imagePathString: imagePathString, imagePathString: imagePathString,
deleteImages: true,// default is true deleteImages: true,// default is true
} }
console.log('to create Video from image')
await createVideoFromImages([], options) await createVideoFromImages([], options)
console.log('Video from images Created')
// to delete the individual frames that were generated and the thumbnail // to delete the individual frames that were generated and the thumbnail
!(async function () { // !(async function () {
deleteFile(imageArr) // deleteFile(imageArr)
})() // })()
return videoPath // return videoPath
} }
let remotePath = path.join(CONFIG.S3_PATH.TUTOR_SHOT, fileName) // let remotePath = path.join(CONFIG.S3_PATH.TUTOR_SHOT, fileName)
let remoteThumbnailPath = path.join(CONFIG.S3_PATH.TUTOR_SHOT, thumbnailName) // let remoteThumbnailPath = path.join(CONFIG.S3_PATH.TUTOR_SHOT, thumbnailName)
await uploadToAwsS3(videoPath, remotePath) // await uploadToAwsS3(videoPath, remotePath)
await uploadToAwsS3(thumbnailPath, remoteThumbnailPath) // await uploadToAwsS3(thumbnailPath, remoteThumbnailPath)
res.status(STATUS_CODE.OK).json() res.status(STATUS_CODE.OK).json()
} catch (err) { } catch (err) {
console.log(err) console.log('------ERROR:GENERATING VIDEO',err)
res.status(STATUS_CODE.ERROR).json() res.status(STATUS_CODE.ERROR).json()
} }
} }
\ No newline at end of file
const path = require('path')
module.exports.STATUS_CODE = { module.exports.STATUS_CODE = {
OK: 200, OK: 200,
NOT_FOUND: 400, NOT_FOUND: 400,
ERROR: 500 ERROR: 500
} }
module.exports.TEMP_IMAGE_DIR = path.join(__dirname, '..', 'temporary', 'image');
module.exports.TEMP_VIDEO_DIR = path.join(__dirname, '..', 'temporary', 'video');
module.exports.TEMP_AUDIO_DIR = path.join(__dirname, '..', 'temporary', 'audio');
\ No newline at end of file
...@@ -27,6 +27,10 @@ const path = require('path') ...@@ -27,6 +27,10 @@ const path = require('path')
module.exports.createVideoFromImages = async function (imageArr, options) { module.exports.createVideoFromImages = async function (imageArr, options) {
return new Promise(async (res, rej) => { return new Promise(async (res, rej) => {
console.log('createVideoFromImages')
console.log('imageArr', imageArr)
console.log('options', options)
let frameRate = options?.frameRate ? options.frameRate : 24 let frameRate = options?.frameRate ? options.frameRate : 24
let tempImageDir = path.join(__dirname, '..', 'temporary', 'images') let tempImageDir = path.join(__dirname, '..', 'temporary', 'images')
let outputFilePath = path.join(options.outputFilePath, `${options.outputFileName}.${options.outputFormat}`) let outputFilePath = path.join(options.outputFilePath, `${options.outputFileName}.${options.outputFormat}`)
...@@ -40,6 +44,7 @@ module.exports.createVideoFromImages = async function (imageArr, options) { ...@@ -40,6 +44,7 @@ module.exports.createVideoFromImages = async function (imageArr, options) {
imagePathString = path.join(tempImageDir, `${options.outputFileName}_%d.png`) imagePathString = path.join(tempImageDir, `${options.outputFileName}_%d.png`)
////// to create temporary image files ////// ////// to create temporary image files //////
for (let i = 0; i < imageArr.length; i++) { for (let i = 0; i < imageArr.length; i++) {
console.log('looping image arr')
if (imageArr[i].filePath) { if (imageArr[i].filePath) {
let limit = imageArr[i]?.duration ? imageArr[i].duration : 1 let limit = imageArr[i]?.duration ? imageArr[i].duration : 1
limit = limit * frameRate limit = limit * frameRate
...@@ -55,8 +60,13 @@ module.exports.createVideoFromImages = async function (imageArr, options) { ...@@ -55,8 +60,13 @@ module.exports.createVideoFromImages = async function (imageArr, options) {
} }
////// using ffmpeg creating video ////// ////// using ffmpeg creating video //////
console.log('ffmpeg config')
console.log('imagePathString', imagePathString)
console.log('outputFilePath', outputFilePath)
console.log('frameRate', frameRate)
ffmpeg() ffmpeg()
.on('end', () => { .on('end', () => {
console.log('VIDEO END')
res(path.join(options.outputFilePath, `${options.outputFileName}.${options.outputFormat}`)) res(path.join(options.outputFilePath, `${options.outputFileName}.${options.outputFormat}`))
////// to delete the frames that are created ////// ////// to delete the frames that are created //////
......
...@@ -31,6 +31,7 @@ module.exports.mergeImages = async function (imageArr, options) { ...@@ -31,6 +31,7 @@ module.exports.mergeImages = async function (imageArr, options) {
compositeArr.push({ input: await nextSharp.toBuffer() }) compositeArr.push({ input: await nextSharp.toBuffer() })
} }
imageSharp.composite(compositeArr) imageSharp.composite(compositeArr)
await imageSharp.toFile('/var/www/BeGenieUs/begenieus-jobs/temporary/image/temp-1.png')
if (options.outputType == 'buffer') return imageSharp.toBuffer() if (options.outputType == 'buffer') return imageSharp.toBuffer()
if (options.outputType == 'file' && options.outputFile) { if (options.outputType == 'file' && options.outputFile) {
await imageSharp.toFile(options.outputFile) await imageSharp.toFile(options.outputFile)
......
const Fs = require('fs'); const Fs = require('fs');
const AWS = require('aws-sdk'); const AWS = require('aws-sdk');
const CONFIG = require('../config');
AWS.config.update({ AWS.config.update({
accessKeyId: CONFIG.S3_ACCESS_KEY, accessKeyId: CONFIG.S3_ACCESS_KEY,
...@@ -41,3 +42,13 @@ module.exports.uploadToAwsS3 = async function (localPath, remotePath, options) { ...@@ -41,3 +42,13 @@ module.exports.uploadToAwsS3 = async function (localPath, remotePath, options) {
return { status: httpStatus.NETWORK_ERROR, path: remotePath } return { status: httpStatus.NETWORK_ERROR, path: remotePath }
} }
} }
module.exports.generatePreSignedGetUrl = async function (fileName) {
return await new Promise((resolve, reject) => {
s3.getSignedUrl('getObject', {
Key: fileName,
}, (err, url) => {
resolve(url); // successful response
});
})
}
\ No newline at end of file
const express = require('express') const express = require('express')
const CONFIG = require('./config.js') const CONFIG = require('./config.js')
console.log('CONFIG', CONFIG)
const PORT = CONFIG.PORT; const PORT = CONFIG.PORT;
const app = express() const app = express()
app.use( express.json() )
app.use( require("./routes/tutor-shot") ) app.use( '/tutor-shot',require("./routes/tutor-shot") )
app.listen( PORT, ()=>{ app.listen( PORT, ()=>{
console.log(`BeGenieUs jobs running on http://localhost:${PORT}`) console.log(`BeGenieUs jobs running on http://localhost:${PORT}`)
......
...@@ -4,17 +4,19 @@ ...@@ -4,17 +4,19 @@
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"start": "node index.js" "start": "node index.js",
"dev": "pm2 restart ../jobs.config.js"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"aws-sdk": "^2.1570.0",
"axios": "^1.6.7", "axios": "^1.6.7",
"canvas": "^2.11.2", "canvas": "^2.11.2",
"express": "^4.18.3", "express": "^4.18.3",
"fluent-ffmpeg": "^2.1.2", "fluent-ffmpeg": "^2.1.2",
"mongoose": "^8.2.0", "mongoose": "^8.2.1",
"sharp": "^0.33.2" "sharp": "^0.32.1"
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment