X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fhelpers%2Fffmpeg-utils.ts;h=02c66cd014cc89b60651336f83445a6f87b44e1c;hb=110d463fece85e87a26aca48a6048ae0017a27b3;hp=084516e553fd1a0395f24ced3ae8340e3fdcd622;hpb=338eb9d33af690db716805fd2277bf68f473b58f;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index 084516e55..02c66cd01 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts @@ -7,6 +7,7 @@ import { logger } from './logger' import { checkFFmpegEncoders } from '../initializers/checker-before-init' import { readFile, remove, writeFile } from 'fs-extra' import { CONFIG } from '../initializers/config' +import { VideoFileMetadata } from '@shared/models/videos/video-file-metadata' /** * A toolbox to play with audio @@ -73,7 +74,7 @@ namespace audio { } } -function computeResolutionsToTranscode (videoFileHeight: number) { +function computeResolutionsToTranscode (videoFileResolution: number) { const resolutionsEnabled: number[] = [] const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS @@ -89,7 +90,7 @@ function computeResolutionsToTranscode (videoFileHeight: number) { ] for (const resolution of resolutions) { - if (configResolutions[resolution + 'p'] === true && videoFileHeight > resolution) { + if (configResolutions[resolution + 'p'] === true && videoFileResolution > resolution) { resolutionsEnabled.push(resolution) } } @@ -124,7 +125,8 @@ async function getVideoStreamCodec (path: string) { baseProfile = baseProfileMatrix['High'] // Fallback } - const level = videoStream.level.toString(16) + let level = videoStream.level.toString(16) + if (level.length === 1) level = `0${level}` return `${videoCodec}.${baseProfile}${level}` } @@ -169,24 +171,26 @@ async function getVideoFileFPS (path: string) { return 0 } -async function getVideoFileBitrate (path: string) { - return new Promise((res, rej) => { +async function getMetadataFromFile (path: string, cb = metadata => metadata) { + return new Promise((res, rej) => { ffmpeg.ffprobe(path, (err, metadata) => { if (err) return rej(err) - return res(metadata.format.bit_rate) + return res(cb(new VideoFileMetadata(metadata))) }) }) } +async function getVideoFileBitrate (path: string) { + return getMetadataFromFile(path, metadata => metadata.format.bit_rate) +} + function getDurationFromVideoFile (path: string) { - return new Promise((res, rej) => { - ffmpeg.ffprobe(path, (err, metadata) => { - if (err) return rej(err) + return getMetadataFromFile(path, metadata => Math.floor(metadata.format.duration)) +} - return res(Math.floor(metadata.format.duration)) - }) - }) +function getVideoStreamFromFile (path: string) { + return getMetadataFromFile(path, metadata => metadata.streams.find(s => s.codec_type === 'video') || null) } async function generateImageFromVideoFile (fromPath: string, folder: string, imageName: string, size: { width: number, height: number }) { @@ -266,7 +270,8 @@ type TranscodeOptions = function transcode (options: TranscodeOptions) { return new Promise(async (res, rej) => { try { - let command = ffmpeg(options.inputPath, { niceness: FFMPEG_NICE.TRANSCODING }) + // we set cwd explicitly because ffmpeg appears to create temporary files when trancoding which fails in read-only file systems + let command = ffmpeg(options.inputPath, { niceness: FFMPEG_NICE.TRANSCODING, cwd: CONFIG.STORAGE.TMP_DIR }) .output(options.outputPath) if (options.type === 'quick-transcode') { @@ -334,13 +339,32 @@ function getClosestFramerateStandard (fps: number, type: 'HD_STANDARD' | 'STANDA .sort((a, b) => fps % a - fps % b)[0] } +function convertWebPToJPG (path: string, destination: string): Promise { + return new Promise(async (res, rej) => { + try { + const command = ffmpeg(path).output(destination) + + command.on('error', (err, stdout, stderr) => { + logger.error('Error in ffmpeg webp convert process.', { stdout, stderr }) + return rej(err) + }) + .on('end', () => res()) + .run() + } catch (err) { + return rej(err) + } + }) +} + // --------------------------------------------------------------------------- export { getVideoStreamCodec, getAudioStreamCodec, + convertWebPToJPG, getVideoStreamSize, getVideoFileResolution, + getMetadataFromFile, getDurationFromVideoFile, generateImageFromVideoFile, TranscodeOptions, @@ -418,6 +442,7 @@ async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: HLSTrans const videoPath = getHLSVideoPath(options) if (options.copyCodecs) command = presetCopy(command) + else if (options.resolution === VideoResolution.H_NOVIDEO) command = presetOnlyAudio(command) else command = await buildx264Command(command, options) command = command.outputOption('-hls_time 4') @@ -450,17 +475,6 @@ async function fixHLSPlaylistIfNeeded (options: TranscodeOptions) { await writeFile(options.outputPath, newContent) } -function getVideoStreamFromFile (path: string) { - return new Promise((res, rej) => { - ffmpeg.ffprobe(path, (err, metadata) => { - if (err) return rej(err) - - const videoStream = metadata.streams.find(s => s.codec_type === 'video') - return res(videoStream || null) - }) - }) -} - /** * A slightly customised version of the 'veryfast' x264 preset *