Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
B
begenieus-jobs
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ramdayal Munda
begenieus-jobs
Commits
5e21b37a
Commit
5e21b37a
authored
Jul 29, 2024
by
Pragati Upadhyay
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
profile model change
parent
453e5c9a
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
49 additions
and
73 deletions
+49
-73
tutor-shot.js
controller/tutor-shot.js
+1
-2
ffmpeg-helper.js
helper/ffmpeg-helper.js
+48
-71
No files found.
controller/tutor-shot.js
View file @
5e21b37a
...
@@ -42,7 +42,7 @@ module.exports.generateVideo = async function (req, res) {
...
@@ -42,7 +42,7 @@ module.exports.generateVideo = async function (req, res) {
let
imageDir
=
TEMP_IMAGE_DIR
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
`
)
videoPath
=
path
.
join
(
TEMP_VIDEO_DIR
,
`
${
tutorShotData
.
_id
}
.
webm
`
)
thumbnailPath
=
path
.
join
(
TEMP_IMAGE_DIR
,
`
${
tutorShotData
.
_id
}
_thumbnail`
)
thumbnailPath
=
path
.
join
(
TEMP_IMAGE_DIR
,
`
${
tutorShotData
.
_id
}
_thumbnail`
)
fileName
=
`
${
tutorShotData
.
_id
}
.webm`
fileName
=
`
${
tutorShotData
.
_id
}
.webm`
thumbnailName
=
`
${
tutorShotData
.
_id
}
_thumbnail.png`
thumbnailName
=
`
${
tutorShotData
.
_id
}
_thumbnail.png`
...
@@ -146,7 +146,6 @@ module.exports.generateVideo = async function (req, res) {
...
@@ -146,7 +146,6 @@ module.exports.generateVideo = async function (req, res) {
socketPayload
.
percent
=
100
socketPayload
.
percent
=
100
socketPayload
.
complete
=
true
socketPayload
.
complete
=
true
socket
.
emit
(
"videoGenerationProgress"
,
socketPayload
)
socket
.
emit
(
"videoGenerationProgress"
,
socketPayload
)
console
.
log
(
"socketon"
)
console
.
log
(
'---Tutor-shot-generated----'
,
tutorShotData
?.
_id
)
console
.
log
(
'---Tutor-shot-generated----'
,
tutorShotData
?.
_id
)
}
}
...
...
helper/ffmpeg-helper.js
View file @
5e21b37a
const
sharp
=
require
(
'sharp'
)
const
ffmpeg
=
require
(
'fluent-ffmpeg'
);
const
f
fmpeg
=
require
(
'fluent-ffmpeg'
)
const
f
s
=
require
(
'fs'
);
const
fs
=
require
(
'fs'
)
const
path
=
require
(
'path'
);
const
path
=
require
(
'path'
)
const
sharp
=
require
(
'sharp'
);
/**
/**
*
*
* @param {[
* @param {string} imagePath - Path to the image file
* {
* @param {number} duration - Duration in seconds to display the image
* filePath: 'String: path of the file you want',
* @param {string} outputClipPath - Path to the output clip file
* buffer: 'Buffer: buffer of the file you want',
* @param {function} callback - Callback function
* duration: 'Number: duration in seconds, how long you want the image to be displayed',
* }
* ]} imageArr
* @param {
* {
* outputFileName: "String: name of the video file, without extension; (required)",
* outputFormat: "String: mp4 (required)",
* frameRate: "Number: frames per second; (required, default: 1)",
* imagePathString: "String: path to the individual frames: ex:'/path/test-video_%d.png'",
* deleteImages: "Boolean: to delete the individual frames from the disk; (default: true)",
* outputFilePath: "String: path to the directory where the video would be generated",
* }
* } options
* @returns
*/
*/
function
createClipFromImage
(
imagePath
,
duration
,
outputClipPath
,
callback
)
{
function
createClipFromImage
(
imagePath
,
duration
,
outputClipPath
,
callback
)
{
ffmpeg
(
imagePath
)
ffmpeg
(
imagePath
)
...
@@ -30,10 +16,11 @@ function createClipFromImage(imagePath, duration, outputClipPath, callback) {
...
@@ -30,10 +16,11 @@ function createClipFromImage(imagePath, duration, outputClipPath, callback) {
.
inputOptions
(
`-t
${
duration
}
`
)
.
inputOptions
(
`-t
${
duration
}
`
)
.
inputOptions
(
'-framerate 1'
)
.
inputOptions
(
'-framerate 1'
)
.
outputOptions
([
.
outputOptions
([
'-c:v libx264'
,
// Use H.264 codec
'-c:v libvpx'
,
// Use VP8 codec for video
// '-pix_fmt yuv420p', // Pixel format compatible with most devices
'-b:v 1M'
,
// Bitrate for video
'-crf 23'
,
// Constant Rate Factor that balances quality and file size
'-crf 10'
,
// Constant Rate Factor for quality
'-preset veryfast'
// Faster encoding with reasonable file size
'-auto-alt-ref 0'
,
// VP8 option to disable alternate reference frames
'-c:a libvorbis'
// Use Vorbis codec for audio
])
])
.
output
(
outputClipPath
)
.
output
(
outputClipPath
)
.
on
(
'end'
,
()
=>
{
.
on
(
'end'
,
()
=>
{
...
@@ -50,10 +37,10 @@ function concatenateClips(clips, outputPath, callback) {
...
@@ -50,10 +37,10 @@ function concatenateClips(clips, outputPath, callback) {
const
fileList
=
'filelist.txt'
;
const
fileList
=
'filelist.txt'
;
const
fileContent
=
clips
.
map
(
clip
=>
`file '
${
clip
}
'`
).
join
(
'
\
n'
);
const
fileContent
=
clips
.
map
(
clip
=>
`file '
${
clip
}
'`
).
join
(
'
\
n'
);
fs
.
writeFileSync
(
fileList
,
fileContent
);
fs
.
writeFileSync
(
fileList
,
fileContent
);
console
.
log
(
"created"
,
outputPath
,
'x'
)
console
.
log
(
"created"
,
outputPath
,
'x'
)
;
ffmpeg
()
ffmpeg
()
.
input
(
fileList
)
.
input
(
fileList
)
.
inputOptions
([
'-f concat'
,
'-safe 0'
])
// Corrected input options
.
inputOptions
([
'-f concat'
,
'-safe 0'
])
// Corrected input options
.
outputOptions
(
'-c copy'
)
.
outputOptions
(
'-c copy'
)
.
output
(
outputPath
)
.
output
(
outputPath
)
.
on
(
'end'
,
()
=>
{
.
on
(
'end'
,
()
=>
{
...
@@ -69,7 +56,6 @@ function concatenateClips(clips, outputPath, callback) {
...
@@ -69,7 +56,6 @@ function concatenateClips(clips, outputPath, callback) {
.
run
();
.
run
();
}
}
module
.
exports
.
createVideo
=
async
function
(
screenshots
,
outputPath
)
{
module
.
exports
.
createVideo
=
async
function
(
screenshots
,
outputPath
)
{
return
new
Promise
(
async
(
resolve
,
reject
)
=>
{
return
new
Promise
(
async
(
resolve
,
reject
)
=>
{
const
clips
=
[];
const
clips
=
[];
...
@@ -78,7 +64,7 @@ module.exports.createVideo = async function (screenshots, outputPath) {
...
@@ -78,7 +64,7 @@ module.exports.createVideo = async function (screenshots, outputPath) {
for
(
let
index
=
0
;
index
<
screenshots
.
length
;
index
++
)
{
for
(
let
index
=
0
;
index
<
screenshots
.
length
;
index
++
)
{
const
screenshot
=
screenshots
[
index
];
const
screenshot
=
screenshots
[
index
];
const
duration
=
screenshot
.
duration
||
3
;
const
duration
=
screenshot
.
duration
||
3
;
const
clipPath
=
`clip
${
index
}
.
mp4
`
;
// Temporary clip path
const
clipPath
=
`clip
${
index
}
.
webm
`
;
// Temporary clip path
const
clip
=
await
createClipFromImageAsync
(
screenshot
,
duration
,
clipPath
);
const
clip
=
await
createClipFromImageAsync
(
screenshot
,
duration
,
clipPath
);
clips
.
push
(
clip
);
clips
.
push
(
clip
);
...
@@ -119,42 +105,36 @@ function concatenateClipsAsync(clips, outputPath) {
...
@@ -119,42 +105,36 @@ function concatenateClipsAsync(clips, outputPath) {
});
});
}
}
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
)
=>
{
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
}
`
)
let
imagePathString
=
options
?.
imagePathString
;
let
imagePathString
=
options
?.
imagePathString
let
deleteImages
=
(
options
&&
options
?.
hasOwnProperty
(
'deleteImages'
))
?
(
!!
options
.
deleteImages
)
:
true
;
let
deleteImages
=
(
options
&&
options
?.
hasOwnProperty
(
'deleteImages'
))
?
(
!!
options
.
deleteImages
)
:
true
let
frameNumber
=
1
;
let
frames
=
[];
let
frameNumber
=
1
let
frames
=
[]
if
(
!
imagePathString
)
{
// if the path is not generated then generate the path
if
(
!
imagePathString
)
{
// if the path is not generated then generate the path
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
++
)
{
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
;
let
frameNum
=
0
let
frameNum
=
0
;
do
{
do
{
let
newFilePath
=
path
.
join
(
tempImageDir
,
`
${
options
.
outputFileName
}
_
${
frameNumber
++
}
.png`
)
let
newFilePath
=
path
.
join
(
tempImageDir
,
`
${
options
.
outputFileName
}
_
${
frameNumber
++
}
.png`
);
await
sharp
(
imageArr
[
i
].
filePath
).
toFile
(
newFilePath
)
await
sharp
(
imageArr
[
i
].
filePath
).
toFile
(
newFilePath
);
frames
.
push
(
newFilePath
)
frames
.
push
(
newFilePath
);
}
while
(
++
frameNum
<
limit
);
}
while
(
++
frameNum
<
limit
)
}
}
}
}
}
}
////// using ffmpeg creating video //////
////// using ffmpeg creating video //////
ffmpeg
()
ffmpeg
()
.
on
(
'end'
,
()
=>
{
.
on
(
'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 //////
if
(
deleteImages
)
if
(
deleteImages
)
...
@@ -168,34 +148,31 @@ module.exports.createVideoFromImages = async function (imageArr,options) {
...
@@ -168,34 +148,31 @@ module.exports.createVideoFromImages = async function (imageArr,options) {
};
};
});
});
});
});
})
})
.
on
(
'error'
,
(
err
)
=>
{
.
on
(
'error'
,
(
err
)
=>
{
console
.
error
(
'Error creating video:'
,
err
);
console
.
error
(
'Error creating video:'
,
err
);
rej
(
undefined
,
err
)
rej
(
undefined
,
err
)
;
})
})
// .videoFilters('format=yuv420p')
.
input
(
imagePathString
)
.
input
(
imagePathString
)
.
outputOptions
(
'-c:v libvpx'
,
'-b:v 1M'
,
'-crf 10'
,
'-auto-alt-ref 0'
,
'-c:a libvorbis'
)
// Added correct codecs
.
output
(
outputFilePath
)
.
output
(
outputFilePath
)
.
outputFPS
(
frameRate
)
// Set frames per second as needed
.
outputFPS
(
frameRate
)
// Set frames per second as needed
.
run
();
.
run
();
});
})
}
}
module
.
exports
.
joinAudioVideo
=
async
function
(
videoPath
,
audioPath
,
output
)
{
module
.
exports
.
joinAudioVideo
=
async
function
(
videoPath
,
audioPath
,
output
)
{
return
new
Promise
((
res
,
rej
)
=>
{
return
new
Promise
((
res
,
rej
)
=>
{
ffmpeg
()
ffmpeg
()
.
input
(
videoPath
)
.
input
(
videoPath
)
.
input
(
audioPath
)
.
input
(
audioPath
)
.
output
(
output
)
.
output
(
output
)
.
on
(
'end'
,
()
=>
{
.
on
(
'end'
,
()
=>
{
res
(
output
)
res
(
output
);
})
})
.
on
(
'error'
,
(
err
)
=>
{
.
on
(
'error'
,
(
err
)
=>
{
rej
(
err
)
rej
(
err
);
})
})
.
run
()
.
run
()
;
})
})
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment