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) {
let
imageDir
=
TEMP_IMAGE_DIR
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`
)
fileName
=
`
${
tutorShotData
.
_id
}
.webm`
thumbnailName
=
`
${
tutorShotData
.
_id
}
_thumbnail.png`
...
...
@@ -146,7 +146,6 @@ module.exports.generateVideo = async function (req, res) {
socketPayload
.
percent
=
100
socketPayload
.
complete
=
true
socket
.
emit
(
"videoGenerationProgress"
,
socketPayload
)
console
.
log
(
"socketon"
)
console
.
log
(
'---Tutor-shot-generated----'
,
tutorShotData
?.
_id
)
}
...
...
helper/ffmpeg-helper.js
View file @
5e21b37a
const
sharp
=
require
(
'sharp'
)
const
f
fmpeg
=
require
(
'fluent-ffmpeg'
)
const
fs
=
require
(
'fs'
)
const
path
=
require
(
'path'
)
const
ffmpeg
=
require
(
'fluent-ffmpeg'
);
const
f
s
=
require
(
'fs'
);
const
path
=
require
(
'path'
);
const
sharp
=
require
(
'sharp'
);
/**
*
* @param {[
* {
* filePath: 'String: path of the file you want',
* buffer: 'Buffer: buffer of the file you want',
* 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
* @param {string} imagePath - Path to the image file
* @param {number} duration - Duration in seconds to display the image
* @param {string} outputClipPath - Path to the output clip file
* @param {function} callback - Callback function
*/
function
createClipFromImage
(
imagePath
,
duration
,
outputClipPath
,
callback
)
{
ffmpeg
(
imagePath
)
...
...
@@ -30,10 +16,11 @@ function createClipFromImage(imagePath, duration, outputClipPath, callback) {
.
inputOptions
(
`-t
${
duration
}
`
)
.
inputOptions
(
'-framerate 1'
)
.
outputOptions
([
'-c:v libx264'
,
// Use H.264 codec
// '-pix_fmt yuv420p', // Pixel format compatible with most devices
'-crf 23'
,
// Constant Rate Factor that balances quality and file size
'-preset veryfast'
// Faster encoding with reasonable file size
'-c:v libvpx'
,
// Use VP8 codec for video
'-b:v 1M'
,
// Bitrate for video
'-crf 10'
,
// Constant Rate Factor for quality
'-auto-alt-ref 0'
,
// VP8 option to disable alternate reference frames
'-c:a libvorbis'
// Use Vorbis codec for audio
])
.
output
(
outputClipPath
)
.
on
(
'end'
,
()
=>
{
...
...
@@ -50,10 +37,10 @@ function concatenateClips(clips, outputPath, callback) {
const
fileList
=
'filelist.txt'
;
const
fileContent
=
clips
.
map
(
clip
=>
`file '
${
clip
}
'`
).
join
(
'
\
n'
);
fs
.
writeFileSync
(
fileList
,
fileContent
);
console
.
log
(
"created"
,
outputPath
,
'x'
)
console
.
log
(
"created"
,
outputPath
,
'x'
)
;
ffmpeg
()
.
input
(
fileList
)
.
inputOptions
([
'-f concat'
,
'-safe 0'
])
// Corrected input options
.
inputOptions
([
'-f concat'
,
'-safe 0'
])
// Corrected input options
.
outputOptions
(
'-c copy'
)
.
output
(
outputPath
)
.
on
(
'end'
,
()
=>
{
...
...
@@ -69,7 +56,6 @@ function concatenateClips(clips, outputPath, callback) {
.
run
();
}
module
.
exports
.
createVideo
=
async
function
(
screenshots
,
outputPath
)
{
return
new
Promise
(
async
(
resolve
,
reject
)
=>
{
const
clips
=
[];
...
...
@@ -78,7 +64,7 @@ module.exports.createVideo = async function (screenshots, outputPath) {
for
(
let
index
=
0
;
index
<
screenshots
.
length
;
index
++
)
{
const
screenshot
=
screenshots
[
index
];
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
);
clips
.
push
(
clip
);
...
...
@@ -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
)
=>
{
let
frameRate
=
options
?.
frameRate
?
options
.
frameRate
:
24
let
tempImageDir
=
path
.
join
(
__dirname
,
'..'
,
'temporary'
,
'images'
)
let
outputFilePath
=
path
.
join
(
options
.
outputFilePath
,
`
${
options
.
outputFileName
}
.
${
options
.
outputFormat
}
`
)
let
imagePathString
=
options
?.
imagePathString
let
deleteImages
=
(
options
&&
options
?.
hasOwnProperty
(
'deleteImages'
))
?
(
!!
options
.
deleteImages
)
:
true
let
frameNumber
=
1
let
frames
=
[]
let
frameRate
=
options
?.
frameRate
?
options
.
frameRate
:
24
;
let
tempImageDir
=
path
.
join
(
__dirname
,
'..'
,
'temporary'
,
'images'
);
let
outputFilePath
=
path
.
join
(
options
.
outputFilePath
,
`
${
options
.
outputFileName
}
.
${
options
.
outputFormat
}
`
);
let
imagePathString
=
options
?.
imagePathString
;
let
deleteImages
=
(
options
&&
options
?.
hasOwnProperty
(
'deleteImages'
))
?
(
!!
options
.
deleteImages
)
:
true
;
let
frameNumber
=
1
;
let
frames
=
[];
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 //////
for
(
let
i
=
0
;
i
<
imageArr
.
length
;
i
++
)
{
if
(
imageArr
[
i
].
filePath
)
{
let
limit
=
imageArr
[
i
]?.
duration
?
imageArr
[
i
].
duration
:
1
limit
=
limit
*
frameRate
let
frameNum
=
0
let
limit
=
imageArr
[
i
]?.
duration
?
imageArr
[
i
].
duration
:
1
;
limit
=
limit
*
frameRate
;
let
frameNum
=
0
;
do
{
let
newFilePath
=
path
.
join
(
tempImageDir
,
`
${
options
.
outputFileName
}
_
${
frameNumber
++
}
.png`
)
await
sharp
(
imageArr
[
i
].
filePath
).
toFile
(
newFilePath
)
frames
.
push
(
newFilePath
)
}
while
(
++
frameNum
<
limit
)
let
newFilePath
=
path
.
join
(
tempImageDir
,
`
${
options
.
outputFileName
}
_
${
frameNumber
++
}
.png`
);
await
sharp
(
imageArr
[
i
].
filePath
).
toFile
(
newFilePath
);
frames
.
push
(
newFilePath
);
}
while
(
++
frameNum
<
limit
);
}
}
}
////// using ffmpeg creating video //////
ffmpeg
()
.
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 //////
if
(
deleteImages
)
...
...
@@ -168,34 +148,31 @@ module.exports.createVideoFromImages = async function (imageArr,options) {
};
});
});
})
.
on
(
'error'
,
(
err
)
=>
{
console
.
error
(
'Error creating video:'
,
err
);
rej
(
undefined
,
err
)
rej
(
undefined
,
err
)
;
})
// .videoFilters('format=yuv420p')
.
input
(
imagePathString
)
.
outputOptions
(
'-c:v libvpx'
,
'-b:v 1M'
,
'-crf 10'
,
'-auto-alt-ref 0'
,
'-c:a libvorbis'
)
// Added correct codecs
.
output
(
outputFilePath
)
.
outputFPS
(
frameRate
)
// Set frames per second as needed
.
run
();
})
});
}
module
.
exports
.
joinAudioVideo
=
async
function
(
videoPath
,
audioPath
,
output
)
{
return
new
Promise
((
res
,
rej
)
=>
{
ffmpeg
()
.
input
(
videoPath
)
.
input
(
audioPath
)
.
output
(
output
)
.
on
(
'end'
,
()
=>
{
res
(
output
)
})
.
on
(
'error'
,
(
err
)
=>
{
rej
(
err
)
})
.
run
()
})
.
input
(
videoPath
)
.
input
(
audioPath
)
.
output
(
output
)
.
on
(
'end'
,
()
=>
{
res
(
output
);
})
.
on
(
'error'
,
(
err
)
=>
{
rej
(
err
);
})
.
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