Fix resolution for portrait videos
authorChocobozzz <me@florianbigard.com>
Tue, 27 Feb 2018 14:57:28 +0000 (15:57 +0100)
committerChocobozzz <me@florianbigard.com>
Tue, 27 Feb 2018 14:57:43 +0000 (15:57 +0100)
server/controllers/api/videos/index.ts
server/helpers/ffmpeg-utils.ts
server/initializers/migrations/0075-video-resolutions.ts
server/lib/job-queue/handlers/video-file.ts
server/models/video/video.ts

index c3d3acd26fb9cca844f2c2266465fed724d2b37a..10b309cd183588539a541dd71d46b1ba65247d1c 100644 (file)
@@ -3,7 +3,7 @@ import { extname, join } from 'path'
 import { VideoCreate, VideoPrivacy, VideoUpdate } from '../../../../shared'
 import { renamePromise } from '../../../helpers/core-utils'
 import { retryTransactionWrapper } from '../../../helpers/database-utils'
-import { getVideoFileHeight } from '../../../helpers/ffmpeg-utils'
+import { getVideoFileResolution } from '../../../helpers/ffmpeg-utils'
 import { processImage } from '../../../helpers/image-utils'
 import { logger } from '../../../helpers/logger'
 import { createReqFiles, getFormattedObjects, getServerActor, resetSequelizeInstance } from '../../../helpers/utils'
@@ -187,11 +187,11 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi
   const video = new VideoModel(videoData)
   video.url = getVideoActivityPubUrl(video)
 
-  const videoFileHeight = await getVideoFileHeight(videoPhysicalFile.path)
+  const { videoFileResolution } = await getVideoFileResolution(videoPhysicalFile.path)
 
   const videoFileData = {
     extname: extname(videoPhysicalFile.filename),
-    resolution: videoFileHeight,
+    resolution: videoFileResolution,
     size: videoPhysicalFile.size
   }
   const videoFile = new VideoFileModel(videoFileData)
index b0f95797cbeb6aca71b20e460c7ea07208fccee9..4f75ba5a82606b5089a59b6693242207bd25b1c3 100644 (file)
@@ -6,9 +6,13 @@ import { unlinkPromise } from './core-utils'
 import { processImage } from './image-utils'
 import { logger } from './logger'
 
-async function getVideoFileHeight (path: string) {
+async function getVideoFileResolution (path: string) {
   const videoStream = await getVideoFileStream(path)
-  return videoStream.height
+
+  return {
+    videoFileResolution: Math.min(videoStream.height, videoStream.width),
+    isPortraitMode: videoStream.height > videoStream.width
+  }
 }
 
 async function getVideoFileFPS (path: string) {
@@ -74,6 +78,7 @@ type TranscodeOptions = {
   inputPath: string
   outputPath: string
   resolution?: VideoResolution
+  isPortraitMode?: boolean
 }
 
 function transcode (options: TranscodeOptions) {
@@ -90,7 +95,8 @@ function transcode (options: TranscodeOptions) {
     if (fps > MAX_VIDEO_TRANSCODING_FPS) command = command.withFPS(MAX_VIDEO_TRANSCODING_FPS)
 
     if (options.resolution !== undefined) {
-      const size = `?x${options.resolution}` // '?x720' for example
+      // '?x720' or '720x?' for example
+      const size = options.isPortraitMode === true ? `${options.resolution}x?` : `?x${options.resolution}`
       command = command.size(size)
     }
 
@@ -103,7 +109,7 @@ function transcode (options: TranscodeOptions) {
 // ---------------------------------------------------------------------------
 
 export {
-  getVideoFileHeight,
+  getVideoFileResolution,
   getDurationFromVideoFile,
   generateImageFromVideoFile,
   transcode,
index e7d8a287609dc8e8ebf893d13c872652d5439c95..54ea852b1aadf846f453a4019ace98a953387e55 100644 (file)
@@ -3,7 +3,7 @@ import { join } from 'path'
 
 import { readdirPromise, renamePromise } from '../../helpers/core-utils'
 import { CONFIG } from '../../initializers/constants'
-import { getVideoFileHeight } from '../../helpers/ffmpeg-utils'
+import { getVideoFileResolution } from '../../helpers/ffmpeg-utils'
 
 function up (utils: {
   transaction: Sequelize.Transaction,
@@ -27,7 +27,7 @@ function up (utils: {
         const uuid = matches[1]
         const ext = matches[2]
 
-        const p = getVideoFileHeight(join(videoFileDir, videoFile))
+        const p = getVideoFileResolution(join(videoFileDir, videoFile))
           .then(height => {
             const oldTorrentName = uuid + '.torrent'
             const newTorrentName = uuid + '-' + height + '.torrent'
index 5294483bda3fe1412fc4edbe35d960199063e3e9..bd9412290ac1c34582b8bafe1b1392541cdb4784 100644 (file)
@@ -11,7 +11,8 @@ import { JobQueue } from '../job-queue'
 
 export type VideoFilePayload = {
   videoUUID: string
-  resolution?: VideoResolution
+  resolution?: VideoResolution,
+  isPortraitMode?: boolean
 }
 
 async function processVideoFile (job: kue.Job) {
@@ -27,7 +28,7 @@ async function processVideoFile (job: kue.Job) {
 
   // Transcoding in other resolution
   if (payload.resolution) {
-    await video.transcodeOriginalVideofile(payload.resolution)
+    await video.transcodeOriginalVideofile(payload.resolution, payload.isPortraitMode)
     await onVideoFileTranscoderSuccess(video)
   } else {
     await video.optimizeOriginalVideofile()
@@ -66,12 +67,12 @@ async function onVideoFileOptimizerSuccess (video: VideoModel) {
     await shareVideoByServerAndChannel(video, undefined)
   }
 
-  const originalFileHeight = await videoDatabase.getOriginalFileHeight()
+  const { videoFileResolution } = await videoDatabase.getOriginalFileResolution()
 
   // Create transcoding jobs if there are enabled resolutions
-  const resolutionsEnabled = computeResolutionsToTranscode(originalFileHeight)
+  const resolutionsEnabled = computeResolutionsToTranscode(videoFileResolution)
   logger.info(
-    'Resolutions computed for video %s and origin file height of %d.', videoDatabase.uuid, originalFileHeight,
+    'Resolutions computed for video %s and origin file height of %d.', videoDatabase.uuid, videoFileResolution,
     { resolutions: resolutionsEnabled }
   )
 
index 4e065e377dd9bcd0ba3e29299d2efe28b1f8c185..80ca513bf8263bba59b311277faef0f5e4015133 100644 (file)
@@ -42,7 +42,7 @@ import {
   isVideoNameValid,
   isVideoPrivacyValid, isVideoSupportValid
 } from '../../helpers/custom-validators/videos'
-import { generateImageFromVideoFile, getVideoFileHeight, transcode } from '../../helpers/ffmpeg-utils'
+import { generateImageFromVideoFile, getVideoFileResolution, transcode } from '../../helpers/ffmpeg-utils'
 import { logger } from '../../helpers/logger'
 import { getServerActor } from '../../helpers/utils'
 import {
@@ -1140,7 +1140,7 @@ export class VideoModel extends Model<VideoModel> {
     }
   }
 
-  transcodeOriginalVideofile = async function (resolution: VideoResolution) {
+  transcodeOriginalVideofile = async function (resolution: VideoResolution, isPortraitMode: boolean) {
     const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
     const extname = '.mp4'
 
@@ -1158,7 +1158,8 @@ export class VideoModel extends Model<VideoModel> {
     const transcodeOptions = {
       inputPath: videoInputPath,
       outputPath: videoOutputPath,
-      resolution
+      resolution,
+      isPortraitMode
     }
 
     await transcode(transcodeOptions)
@@ -1174,10 +1175,10 @@ export class VideoModel extends Model<VideoModel> {
     this.VideoFiles.push(newVideoFile)
   }
 
-  getOriginalFileHeight () {
+  getOriginalFileResolution () {
     const originalFilePath = this.getVideoFilePath(this.getOriginalFile())
 
-    return getVideoFileHeight(originalFilePath)
+    return getVideoFileResolution(originalFilePath)
   }
 
   getDescriptionPath () {