| QuickTranscodeOptions
function transcode (options: TranscodeOptions) {
+ logger.debug('Will run transcode.', { options })
+
return new Promise<void>(async (res, rej) => {
try {
let command = getFFmpeg(options.inputPath)
})
}
-function runLiveTranscoding (rtmpUrl: string, outPath: string, resolutions: number[], deleteSegments: boolean) {
+function runLiveTranscoding (rtmpUrl: string, outPath: string, resolutions: number[], fps, deleteSegments: boolean) {
const command = getFFmpeg(rtmpUrl)
command.inputOption('-fflags nobuffer')
}))
])
- const liveFPS = VIDEO_TRANSCODING_FPS.AVERAGE
-
- command.withFps(liveFPS)
-
command.outputOption('-b_strategy 1')
command.outputOption('-bf 16')
command.outputOption('-preset superfast')
command.outputOption('-level 3.1')
command.outputOption('-map_metadata -1')
command.outputOption('-pix_fmt yuv420p')
+ command.outputOption('-max_muxing_queue_size 1024')
+ command.outputOption('-g ' + (fps * 2))
for (let i = 0; i < resolutions.length; i++) {
const resolution = resolutions[i]
command.outputOption(`-map [vout${resolution}]`)
command.outputOption(`-c:v:${i} libx264`)
- command.outputOption(`-b:v:${i} ${getTargetBitrate(resolution, liveFPS, VIDEO_TRANSCODING_FPS)}`)
+ command.outputOption(`-b:v:${i} ${getTargetBitrate(resolution, fps, VIDEO_TRANSCODING_FPS)}`)
command.outputOption(`-map a:0`)
command.outputOption(`-c:a:${i} aac`)
return command
}
+async function hlsPlaylistToFragmentedMP4 (hlsDirectory: string, segmentFiles: string[], outputPath: string) {
+ const concatFilePath = join(hlsDirectory, 'concat.txt')
+
+ function cleaner () {
+ remove(concatFilePath)
+ .catch(err => logger.error('Cannot remove concat file in %s.', hlsDirectory, { err }))
+ }
+
+ // First concat the ts files to a mp4 file
+ const content = segmentFiles.map(f => 'file ' + f)
+ .join('\n')
+
+ await writeFile(concatFilePath, content + '\n')
+
+ const command = getFFmpeg(concatFilePath)
+ command.inputOption('-safe 0')
+ command.inputOption('-f concat')
+
+ command.outputOption('-c:v copy')
+ command.audioFilter('aresample=async=1:first_pts=0')
+ command.output(outputPath)
+
+ return runCommand(command, cleaner)
+}
+
+async function runCommand (command: ffmpeg.FfmpegCommand, onEnd?: Function) {
+ command.run()
+
+ return new Promise<string>((res, rej) => {
+ command.on('error', err => {
+ if (onEnd) onEnd()
+
+ rej(err)
+ })
+
+ command.on('end', () => {
+ if (onEnd) onEnd()
+
+ res()
+ })
+ })
+}
+
// ---------------------------------------------------------------------------
export {
getVideoFileFPS,
computeResolutionsToTranscode,
audio,
+ hlsPlaylistToFragmentedMP4,
getVideoFileBitrate,
canDoQuickTranscode
}
}
function addDefaultLiveHLSParams (command: ffmpeg.FfmpegCommand, outPath: string, deleteSegments: boolean) {
- command.outputOption('-hls_time ' + VIDEO_LIVE.SEGMENT_TIME)
+ command.outputOption('-hls_time ' + VIDEO_LIVE.SEGMENT_TIME_SECONDS)
command.outputOption('-hls_list_size ' + VIDEO_LIVE.SEGMENTS_LIST_SIZE)
if (deleteSegments === true) {
command.outputOption('-hls_flags delete_segments')
}
- command.outputOption(`-hls_segment_filename ${join(outPath, '%v-%d.ts')}`)
+ command.outputOption(`-hls_segment_filename ${join(outPath, '%v-%04d.ts')}`)
command.outputOption('-master_pl_name master.m3u8')
command.outputOption(`-f hls`)