aboutsummaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
authorFelix Ableitner <me@nutomic.com>2019-04-24 20:27:05 +0200
committerFelix Ableitner <me@nutomic.com>2019-05-04 03:19:49 +0200
commit5ba49f268deb76b168559fe5fe2506b0bd5af9a8 (patch)
tree120968fffb7cd14ee4028344523c453bcdd7fe4b /server
parentc342726ad4ccbb90b8ff29f1cc1c89f9f7e8d98f (diff)
downloadPeerTube-5ba49f268deb76b168559fe5fe2506b0bd5af9a8.tar.gz
PeerTube-5ba49f268deb76b168559fe5fe2506b0bd5af9a8.tar.zst
PeerTube-5ba49f268deb76b168559fe5fe2506b0bd5af9a8.zip
Dont transcode videos when it is not required (fixes #1780)
Diffstat (limited to 'server')
-rw-r--r--server/helpers/ffmpeg-utils.ts52
-rw-r--r--server/lib/video-transcoding.ts9
2 files changed, 52 insertions, 9 deletions
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts
index 76b744de8..13bb2e894 100644
--- a/server/helpers/ffmpeg-utils.ts
+++ b/server/helpers/ffmpeg-utils.ts
@@ -1,6 +1,6 @@
1import * as ffmpeg from 'fluent-ffmpeg' 1import * as ffmpeg from 'fluent-ffmpeg'
2import { dirname, join } from 'path' 2import { dirname, join } from 'path'
3import { getTargetBitrate, VideoResolution } from '../../shared/models/videos' 3import { getTargetBitrate, getMaxBitrate, VideoResolution } from '../../shared/models/videos'
4import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants' 4import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants'
5import { processImage } from './image-utils' 5import { processImage } from './image-utils'
6import { logger } from './logger' 6import { logger } from './logger'
@@ -31,7 +31,7 @@ function computeResolutionsToTranscode (videoFileHeight: number) {
31} 31}
32 32
33async function getVideoFileSize (path: string) { 33async function getVideoFileSize (path: string) {
34 const videoStream = await getVideoFileStream(path) 34 const videoStream = await getVideoStreamFromFile(path)
35 35
36 return { 36 return {
37 width: videoStream.width, 37 width: videoStream.width,
@@ -49,7 +49,7 @@ async function getVideoFileResolution (path: string) {
49} 49}
50 50
51async function getVideoFileFPS (path: string) { 51async function getVideoFileFPS (path: string) {
52 const videoStream = await getVideoFileStream(path) 52 const videoStream = await getVideoStreamFromFile(path)
53 53
54 for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { 54 for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) {
55 const valuesText: string = videoStream[key] 55 const valuesText: string = videoStream[key]
@@ -122,6 +122,7 @@ type TranscodeOptions = {
122 outputPath: string 122 outputPath: string
123 resolution: VideoResolution 123 resolution: VideoResolution
124 isPortraitMode?: boolean 124 isPortraitMode?: boolean
125 doQuickTranscode?: Boolean
125 126
126 hlsPlaylist?: { 127 hlsPlaylist?: {
127 videoFilename: string 128 videoFilename: string
@@ -134,7 +135,17 @@ function transcode (options: TranscodeOptions) {
134 let command = ffmpeg(options.inputPath, { niceness: FFMPEG_NICE.TRANSCODING }) 135 let command = ffmpeg(options.inputPath, { niceness: FFMPEG_NICE.TRANSCODING })
135 .output(options.outputPath) 136 .output(options.outputPath)
136 137
137 if (options.hlsPlaylist) { 138 if (options.doQuickTranscode) {
139 if (options.hlsPlaylist) {
140 throw(Error("Quick transcode and HLS can't be used at the same time"))
141 }
142 command
143 .format('mp4')
144 .addOption('-c:v copy')
145 .addOption('-c:a copy')
146 .outputOption('-map_metadata -1') // strip all metadata
147 .outputOption('-movflags faststart')
148 } else if (options.hlsPlaylist) {
138 command = await buildHLSCommand(command, options) 149 command = await buildHLSCommand(command, options)
139 } else { 150 } else {
140 command = await buildx264Command(command, options) 151 command = await buildx264Command(command, options)
@@ -162,6 +173,34 @@ function transcode (options: TranscodeOptions) {
162 }) 173 })
163} 174}
164 175
176async function canDoQuickTranscode (path: string) {
177 // NOTE: This could be optimized by running ffprobe only once (but it runs fast anyway)
178 const videoStream = await getVideoStreamFromFile(path)
179 const parsedAudio = await audio.get(path)
180 const fps = await getVideoFileFPS(path)
181 const bitRate = await getVideoFileBitrate(path)
182 const resolution = await getVideoFileResolution(path)
183
184 // check video params
185 if (videoStream[ 'codec_name' ] !== 'h264')
186 return false
187 if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX)
188 return false
189 if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS))
190 return false
191
192 // check audio params (if audio stream exists)
193 if (parsedAudio.audioStream) {
194 if (parsedAudio.audioStream[ 'codec_name' ] !== 'aac')
195 return false
196 const maxAudioBitrate = audio.bitrate[ 'aac' ](parsedAudio.audioStream[ 'bit_rate' ])
197 if (maxAudioBitrate != -1 && parsedAudio.audioStream[ 'bit_rate' ] > maxAudioBitrate)
198 return false
199 }
200
201 return true
202}
203
165// --------------------------------------------------------------------------- 204// ---------------------------------------------------------------------------
166 205
167export { 206export {
@@ -173,7 +212,8 @@ export {
173 getVideoFileFPS, 212 getVideoFileFPS,
174 computeResolutionsToTranscode, 213 computeResolutionsToTranscode,
175 audio, 214 audio,
176 getVideoFileBitrate 215 getVideoFileBitrate,
216 canDoQuickTranscode
177} 217}
178 218
179// --------------------------------------------------------------------------- 219// ---------------------------------------------------------------------------
@@ -243,7 +283,7 @@ async function onTranscodingSuccess (options: TranscodeOptions) {
243 await writeFile(options.outputPath, newContent) 283 await writeFile(options.outputPath, newContent)
244} 284}
245 285
246function getVideoFileStream (path: string) { 286function getVideoStreamFromFile (path: string) {
247 return new Promise<any>((res, rej) => { 287 return new Promise<any>((res, rej) => {
248 ffmpeg.ffprobe(path, (err, metadata) => { 288 ffmpeg.ffprobe(path, (err, metadata) => {
249 if (err) return rej(err) 289 if (err) return rej(err)
diff --git a/server/lib/video-transcoding.ts b/server/lib/video-transcoding.ts
index 0fe0ff12a..05afb44d1 100644
--- a/server/lib/video-transcoding.ts
+++ b/server/lib/video-transcoding.ts
@@ -1,6 +1,6 @@
1import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION, WEBSERVER } from '../initializers/constants' 1import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION, WEBSERVER, VIDEO_TRANSCODING_FPS } from '../initializers/constants'
2import { join } from 'path' 2import { join } from 'path'
3import { getVideoFileFPS, transcode } from '../helpers/ffmpeg-utils' 3import { getVideoFileFPS, transcode, canDoQuickTranscode } from '../helpers/ffmpeg-utils'
4import { ensureDir, move, remove, stat } from 'fs-extra' 4import { ensureDir, move, remove, stat } from 'fs-extra'
5import { logger } from '../helpers/logger' 5import { logger } from '../helpers/logger'
6import { VideoResolution } from '../../shared/models/videos' 6import { VideoResolution } from '../../shared/models/videos'
@@ -19,10 +19,13 @@ async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFi
19 const videoInputPath = join(videosDirectory, video.getVideoFilename(inputVideoFile)) 19 const videoInputPath = join(videosDirectory, video.getVideoFilename(inputVideoFile))
20 const videoTranscodedPath = join(videosDirectory, video.id + '-transcoded' + newExtname) 20 const videoTranscodedPath = join(videosDirectory, video.id + '-transcoded' + newExtname)
21 21
22 const doQuickTranscode = await(canDoQuickTranscode(videoInputPath))
23
22 const transcodeOptions = { 24 const transcodeOptions = {
23 inputPath: videoInputPath, 25 inputPath: videoInputPath,
24 outputPath: videoTranscodedPath, 26 outputPath: videoTranscodedPath,
25 resolution: inputVideoFile.resolution 27 resolution: inputVideoFile.resolution,
28 doQuickTranscode
26 } 29 }
27 30
28 // Could be very long! 31 // Could be very long!