X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fhelpers%2Fffmpeg-utils.ts;h=133b1b03b0ac75e82afa0e648491b9d01d8c4cb4;hb=4c280004ce62bf11ddb091854c28f1e1d54a54d6;hp=a108d46a098c754050ada4706b11a9de3ce015c6;hpb=cdf4cb9eaf5f6bc71f7c1e1963c07575f1d2593d;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index a108d46a0..133b1b03b 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts @@ -1,7 +1,7 @@ import * as ffmpeg from 'fluent-ffmpeg' -import { join } from 'path' +import { dirname, join } from 'path' import { getTargetBitrate, VideoResolution } from '../../shared/models/videos' -import { CONFIG, FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers' +import { CONFIG, FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants' import { processImage } from './image-utils' import { logger } from './logger' import { checkFFmpegEncoders } from '../initializers/checker-before-init' @@ -29,19 +29,28 @@ function computeResolutionsToTranscode (videoFileHeight: number) { return resolutionsEnabled } -async function getVideoFileResolution (path: string) { +async function getVideoFileSize (path: string) { const videoStream = await getVideoFileStream(path) return { - videoFileResolution: Math.min(videoStream.height, videoStream.width), - isPortraitMode: videoStream.height > videoStream.width + width: videoStream.width, + height: videoStream.height + } +} + +async function getVideoFileResolution (path: string) { + const size = await getVideoFileSize(path) + + return { + videoFileResolution: Math.min(size.height, size.width), + isPortraitMode: size.height > size.width } } async function getVideoFileFPS (path: string) { const videoStream = await getVideoFileStream(path) - for (const key of [ 'r_frame_rate' , 'avg_frame_rate' ]) { + for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { const valuesText: string = videoStream[key] if (!valuesText) continue @@ -110,8 +119,12 @@ async function generateImageFromVideoFile (fromPath: string, folder: string, ima type TranscodeOptions = { inputPath: string outputPath: string - resolution?: VideoResolution + resolution: VideoResolution isPortraitMode?: boolean + + hlsPlaylist?: { + videoFilename: string + } } function transcode (options: TranscodeOptions) { @@ -150,6 +163,18 @@ function transcode (options: TranscodeOptions) { command = command.withFPS(fps) } + if (options.hlsPlaylist) { + const videoPath = `${dirname(options.outputPath)}/${options.hlsPlaylist.videoFilename}` + + command = command.outputOption('-hls_time 4') + .outputOption('-hls_list_size 0') + .outputOption('-hls_playlist_type vod') + .outputOption('-hls_segment_filename ' + videoPath) + .outputOption('-hls_segment_type fmp4') + .outputOption('-f hls') + .outputOption('-hls_flags single_file') + } + command .on('error', (err, stdout, stderr) => { logger.error('Error in transcoding job.', { stdout, stderr }) @@ -166,6 +191,7 @@ function transcode (options: TranscodeOptions) { // --------------------------------------------------------------------------- export { + getVideoFileSize, getVideoFileResolution, getDurationFromVideoFile, generateImageFromVideoFile, @@ -184,7 +210,7 @@ function getVideoFileStream (path: string) { if (err) return rej(err) const videoStream = metadata.streams.find(s => s.codec_type === 'video') - if (!videoStream) throw new Error('Cannot find video stream of ' + path) + if (!videoStream) return rej(new Error('Cannot find video stream of ' + path)) return res(videoStream) }) @@ -310,6 +336,7 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, resolution: VideoResol .outputOption('-level 3.1') // 3.1 is the minimal ressource allocation for our highest supported resolution .outputOption('-b_strategy 1') // NOTE: b-strategy 1 - heuristic algorythm, 16 is optimal B-frames for it .outputOption('-bf 16') // NOTE: Why 16: https://github.com/Chocobozzz/PeerTube/pull/774. b-strategy 2 -> B-frames<16 + .outputOption('-pix_fmt yuv420p') // allows import of source material with incompatible pixel formats (e.g. MJPEG video) .outputOption('-map_metadata -1') // strip all metadata .outputOption('-movflags faststart') @@ -327,10 +354,10 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, resolution: VideoResol const audioCodecName = parsedAudio.audioStream[ 'codec_name' ] let bitrate: number if (audio.bitrate[ audioCodecName ]) { - bitrate = audio.bitrate[ audioCodecName ](parsedAudio.audioStream[ 'bit_rate' ]) + localCommand = localCommand.audioCodec('aac') - if (bitrate === -1) localCommand = localCommand.audioCodec('copy') - else if (bitrate !== undefined) localCommand = localCommand.audioBitrate(bitrate) + bitrate = audio.bitrate[ audioCodecName ](parsedAudio.audioStream[ 'bit_rate' ]) + if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate) } }