diff options
author | Chocobozzz <me@florianbigard.com> | 2021-06-08 11:28:51 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-06-08 11:28:51 +0200 |
commit | 318b0bd0c2ff575f35d51d97327f77abfecd6b86 (patch) | |
tree | 095a464dc053c06bc7a9c1e6a50a18ac9a7e4dce | |
parent | 5982ffc4b5c926ea51f5bb3ca48f0f2f8f5bd621 (diff) | |
download | PeerTube-318b0bd0c2ff575f35d51d97327f77abfecd6b86.tar.gz PeerTube-318b0bd0c2ff575f35d51d97327f77abfecd6b86.tar.zst PeerTube-318b0bd0c2ff575f35d51d97327f77abfecd6b86.zip |
Fix "height not divisible by 2" ffmpeg error
-rw-r--r-- | server/helpers/core-utils.ts | 17 | ||||
-rw-r--r-- | server/helpers/ffmpeg-utils.ts | 15 | ||||
-rw-r--r-- | server/lib/transcoding/video-transcoding.ts | 7 |
3 files changed, 31 insertions, 8 deletions
diff --git a/server/helpers/core-utils.ts b/server/helpers/core-utils.ts index b5bf2c92c..f7e6fdddc 100644 --- a/server/helpers/core-utils.ts +++ b/server/helpers/core-utils.ts | |||
@@ -243,6 +243,18 @@ function execShell (command: string, options?: ExecOptions) { | |||
243 | 243 | ||
244 | // --------------------------------------------------------------------------- | 244 | // --------------------------------------------------------------------------- |
245 | 245 | ||
246 | function isOdd (num: number) { | ||
247 | return (num % 2) !== 0 | ||
248 | } | ||
249 | |||
250 | function toEven (num: number) { | ||
251 | if (isOdd) return num + 1 | ||
252 | |||
253 | return num | ||
254 | } | ||
255 | |||
256 | // --------------------------------------------------------------------------- | ||
257 | |||
246 | function promisify0<A> (func: (cb: (err: any, result: A) => void) => void): () => Promise<A> { | 258 | function promisify0<A> (func: (cb: (err: any, result: A) => void) => void): () => Promise<A> { |
247 | return function promisified (): Promise<A> { | 259 | return function promisified (): Promise<A> { |
248 | return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => { | 260 | return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => { |
@@ -310,5 +322,8 @@ export { | |||
310 | execPromise, | 322 | execPromise, |
311 | pipelinePromise, | 323 | pipelinePromise, |
312 | 324 | ||
313 | parseSemVersion | 325 | parseSemVersion, |
326 | |||
327 | isOdd, | ||
328 | toEven | ||
314 | } | 329 | } |
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index e328c49ac..d20ca5d56 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts | |||
@@ -5,11 +5,12 @@ import { dirname, join } from 'path' | |||
5 | import { FFMPEG_NICE, VIDEO_LIVE } from '@server/initializers/constants' | 5 | import { FFMPEG_NICE, VIDEO_LIVE } from '@server/initializers/constants' |
6 | import { AvailableEncoders, EncoderOptionsBuilder, EncoderOptions, EncoderProfile, VideoResolution } from '../../shared/models/videos' | 6 | import { AvailableEncoders, EncoderOptionsBuilder, EncoderOptions, EncoderProfile, VideoResolution } from '../../shared/models/videos' |
7 | import { CONFIG } from '../initializers/config' | 7 | import { CONFIG } from '../initializers/config' |
8 | import { execPromise, promisify0 } from './core-utils' | 8 | import { execPromise, isOdd, promisify0 } from './core-utils' |
9 | import { computeFPS, getAudioStream, getVideoFileFPS } from './ffprobe-utils' | 9 | import { computeFPS, getAudioStream, getVideoFileFPS } from './ffprobe-utils' |
10 | import { processImage } from './image-utils' | 10 | import { processImage } from './image-utils' |
11 | import { logger } from './logger' | 11 | import { logger } from './logger' |
12 | import { FilterSpecification } from 'fluent-ffmpeg' | 12 | import { FilterSpecification } from 'fluent-ffmpeg' |
13 | import { findCommentId } from '@shared/extra-utils' | ||
13 | 14 | ||
14 | /** | 15 | /** |
15 | * | 16 | * |
@@ -133,7 +134,7 @@ interface BaseTranscodeOptions { | |||
133 | availableEncoders: AvailableEncoders | 134 | availableEncoders: AvailableEncoders |
134 | profile: string | 135 | profile: string |
135 | 136 | ||
136 | resolution: VideoResolution | 137 | resolution: number |
137 | 138 | ||
138 | isPortraitMode?: boolean | 139 | isPortraitMode?: boolean |
139 | 140 | ||
@@ -407,8 +408,7 @@ async function buildx264VODCommand (command: ffmpeg.FfmpegCommand, options: Tran | |||
407 | async function buildAudioMergeCommand (command: ffmpeg.FfmpegCommand, options: MergeAudioTranscodeOptions) { | 408 | async function buildAudioMergeCommand (command: ffmpeg.FfmpegCommand, options: MergeAudioTranscodeOptions) { |
408 | command = command.loop(undefined) | 409 | command = command.loop(undefined) |
409 | 410 | ||
410 | // Avoid "height not divisible by 2" error | 411 | const scaleFilterValue = getScaleCleanerValue() |
411 | const scaleFilterValue = 'trunc(iw/2)*2:trunc(ih/2)*2' | ||
412 | command = await presetVideo({ command, input: options.audioPath, transcodeOptions: options, scaleFilterValue }) | 412 | command = await presetVideo({ command, input: options.audioPath, transcodeOptions: options, scaleFilterValue }) |
413 | 413 | ||
414 | command.outputOption('-preset:v veryfast') | 414 | command.outputOption('-preset:v veryfast') |
@@ -542,7 +542,7 @@ async function getEncoderBuilderResult (options: { | |||
542 | } | 542 | } |
543 | } | 543 | } |
544 | 544 | ||
545 | const result = await builder({ input, resolution: resolution, fps, streamNum }) | 545 | const result = await builder({ input, resolution, fps, streamNum }) |
546 | 546 | ||
547 | return { | 547 | return { |
548 | result, | 548 | result, |
@@ -727,6 +727,11 @@ async function runCommand (options: { | |||
727 | }) | 727 | }) |
728 | } | 728 | } |
729 | 729 | ||
730 | // Avoid "height not divisible by 2" error | ||
731 | function getScaleCleanerValue () { | ||
732 | return 'trunc(iw/2)*2:trunc(ih/2)*2' | ||
733 | } | ||
734 | |||
730 | // --------------------------------------------------------------------------- | 735 | // --------------------------------------------------------------------------- |
731 | 736 | ||
732 | export { | 737 | export { |
diff --git a/server/lib/transcoding/video-transcoding.ts b/server/lib/transcoding/video-transcoding.ts index 5df192575..1ad63baf3 100644 --- a/server/lib/transcoding/video-transcoding.ts +++ b/server/lib/transcoding/video-transcoding.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import { Job } from 'bull' | 1 | import { Job } from 'bull' |
2 | import { copyFile, ensureDir, move, remove, stat } from 'fs-extra' | 2 | import { copyFile, ensureDir, move, remove, stat } from 'fs-extra' |
3 | import { basename, extname as extnameUtil, join } from 'path' | 3 | import { basename, extname as extnameUtil, join } from 'path' |
4 | import { toEven } from '@server/helpers/core-utils' | ||
4 | import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' | 5 | import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' |
5 | import { MStreamingPlaylistFilesVideo, MVideoFile, MVideoFullLight } from '@server/types/models' | 6 | import { MStreamingPlaylistFilesVideo, MVideoFile, MVideoFullLight } from '@server/types/models' |
6 | import { VideoResolution } from '../../../shared/models/videos' | 7 | import { VideoResolution } from '../../../shared/models/videos' |
@@ -35,6 +36,8 @@ async function optimizeOriginalVideofile (video: MVideoFullLight, inputVideoFile | |||
35 | ? 'quick-transcode' | 36 | ? 'quick-transcode' |
36 | : 'video' | 37 | : 'video' |
37 | 38 | ||
39 | const resolution = toEven(inputVideoFile.resolution) | ||
40 | |||
38 | const transcodeOptions: TranscodeOptions = { | 41 | const transcodeOptions: TranscodeOptions = { |
39 | type: transcodeType, | 42 | type: transcodeType, |
40 | 43 | ||
@@ -44,7 +47,7 @@ async function optimizeOriginalVideofile (video: MVideoFullLight, inputVideoFile | |||
44 | availableEncoders: VideoTranscodingProfilesManager.Instance.getAvailableEncoders(), | 47 | availableEncoders: VideoTranscodingProfilesManager.Instance.getAvailableEncoders(), |
45 | profile: CONFIG.TRANSCODING.PROFILE, | 48 | profile: CONFIG.TRANSCODING.PROFILE, |
46 | 49 | ||
47 | resolution: inputVideoFile.resolution, | 50 | resolution, |
48 | 51 | ||
49 | job | 52 | job |
50 | } | 53 | } |
@@ -57,7 +60,7 @@ async function optimizeOriginalVideofile (video: MVideoFullLight, inputVideoFile | |||
57 | 60 | ||
58 | // Important to do this before getVideoFilename() to take in account the new filename | 61 | // Important to do this before getVideoFilename() to take in account the new filename |
59 | inputVideoFile.extname = newExtname | 62 | inputVideoFile.extname = newExtname |
60 | inputVideoFile.filename = generateVideoFilename(video, false, inputVideoFile.resolution, newExtname) | 63 | inputVideoFile.filename = generateVideoFilename(video, false, resolution, newExtname) |
61 | 64 | ||
62 | const videoOutputPath = getVideoFilePath(video, inputVideoFile) | 65 | const videoOutputPath = getVideoFilePath(video, inputVideoFile) |
63 | 66 | ||