aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/video-transcoding.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/lib/video-transcoding.ts')
-rw-r--r--server/lib/video-transcoding.ts97
1 files changed, 76 insertions, 21 deletions
diff --git a/server/lib/video-transcoding.ts b/server/lib/video-transcoding.ts
index 0fe0ff12a..8d786e0ef 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 } from '../initializers/constants'
2import { join } from 'path' 2import { join } from 'path'
3import { getVideoFileFPS, transcode } from '../helpers/ffmpeg-utils' 3import { canDoQuickTranscode, getVideoFileFPS, transcode, TranscodeOptions, TranscodeOptionsType } 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'
@@ -11,15 +11,24 @@ import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-pla
11import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type' 11import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type'
12import { CONFIG } from '../initializers/config' 12import { CONFIG } from '../initializers/config'
13 13
14/**
15 * Optimize the original video file and replace it. The resolution is not changed.
16 */
14async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFileModel) { 17async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFileModel) {
15 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR 18 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
19 const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
16 const newExtname = '.mp4' 20 const newExtname = '.mp4'
17 21
18 const inputVideoFile = inputVideoFileArg ? inputVideoFileArg : video.getOriginalFile() 22 const inputVideoFile = inputVideoFileArg ? inputVideoFileArg : video.getOriginalFile()
19 const videoInputPath = join(videosDirectory, video.getVideoFilename(inputVideoFile)) 23 const videoInputPath = join(videosDirectory, video.getVideoFilename(inputVideoFile))
20 const videoTranscodedPath = join(videosDirectory, video.id + '-transcoded' + newExtname) 24 const videoTranscodedPath = join(transcodeDirectory, video.id + '-transcoded' + newExtname)
21 25
22 const transcodeOptions = { 26 const transcodeType: TranscodeOptionsType = await canDoQuickTranscode(videoInputPath)
27 ? 'quick-transcode'
28 : 'video'
29
30 const transcodeOptions: TranscodeOptions = {
31 type: transcodeType as any, // FIXME: typing issue
23 inputPath: videoInputPath, 32 inputPath: videoInputPath,
24 outputPath: videoTranscodedPath, 33 outputPath: videoTranscodedPath,
25 resolution: inputVideoFile.resolution 34 resolution: inputVideoFile.resolution
@@ -32,18 +41,11 @@ async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFi
32 await remove(videoInputPath) 41 await remove(videoInputPath)
33 42
34 // Important to do this before getVideoFilename() to take in account the new file extension 43 // Important to do this before getVideoFilename() to take in account the new file extension
35 inputVideoFile.set('extname', newExtname) 44 inputVideoFile.extname = newExtname
36 45
37 const videoOutputPath = video.getVideoFilePath(inputVideoFile) 46 const videoOutputPath = video.getVideoFilePath(inputVideoFile)
38 await move(videoTranscodedPath, videoOutputPath)
39 const stats = await stat(videoOutputPath)
40 const fps = await getVideoFileFPS(videoOutputPath)
41 47
42 inputVideoFile.set('size', stats.size) 48 await onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath)
43 inputVideoFile.set('fps', fps)
44
45 await video.createTorrentAndSetInfoHash(inputVideoFile)
46 await inputVideoFile.save()
47 } catch (err) { 49 } catch (err) {
48 // Auto destruction... 50 // Auto destruction...
49 video.destroy().catch(err => logger.error('Cannot destruct video after transcoding failure.', { err })) 51 video.destroy().catch(err => logger.error('Cannot destruct video after transcoding failure.', { err }))
@@ -52,8 +54,12 @@ async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFi
52 } 54 }
53} 55}
54 56
57/**
58 * Transcode the original video file to a lower resolution.
59 */
55async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoResolution, isPortrait: boolean) { 60async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoResolution, isPortrait: boolean) {
56 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR 61 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
62 const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
57 const extname = '.mp4' 63 const extname = '.mp4'
58 64
59 // We are sure it's x264 in mp4 because optimizeOriginalVideofile was already executed 65 // We are sure it's x264 in mp4 because optimizeOriginalVideofile was already executed
@@ -66,27 +72,49 @@ async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoR
66 videoId: video.id 72 videoId: video.id
67 }) 73 })
68 const videoOutputPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename(newVideoFile)) 74 const videoOutputPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename(newVideoFile))
75 const videoTranscodedPath = join(transcodeDirectory, video.getVideoFilename(newVideoFile))
69 76
70 const transcodeOptions = { 77 const transcodeOptions = {
78 type: 'video' as 'video',
71 inputPath: videoInputPath, 79 inputPath: videoInputPath,
72 outputPath: videoOutputPath, 80 outputPath: videoTranscodedPath,
73 resolution, 81 resolution,
74 isPortraitMode: isPortrait 82 isPortraitMode: isPortrait
75 } 83 }
76 84
77 await transcode(transcodeOptions) 85 await transcode(transcodeOptions)
78 86
79 const stats = await stat(videoOutputPath) 87 return onVideoFileTranscoding(video, newVideoFile, videoTranscodedPath, videoOutputPath)
80 const fps = await getVideoFileFPS(videoOutputPath) 88}
89
90async function mergeAudioVideofile (video: VideoModel, resolution: VideoResolution) {
91 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
92 const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
93 const newExtname = '.mp4'
94
95 const inputVideoFile = video.getOriginalFile()
81 96
82 newVideoFile.set('size', stats.size) 97 const audioInputPath = join(videosDirectory, video.getVideoFilename(video.getOriginalFile()))
83 newVideoFile.set('fps', fps) 98 const videoTranscodedPath = join(transcodeDirectory, video.id + '-transcoded' + newExtname)
84 99
85 await video.createTorrentAndSetInfoHash(newVideoFile) 100 const transcodeOptions = {
101 type: 'merge-audio' as 'merge-audio',
102 inputPath: video.getPreview().getPath(),
103 outputPath: videoTranscodedPath,
104 audioPath: audioInputPath,
105 resolution
106 }
107
108 await transcode(transcodeOptions)
86 109
87 await newVideoFile.save() 110 await remove(audioInputPath)
88 111
89 video.VideoFiles.push(newVideoFile) 112 // Important to do this before getVideoFilename() to take in account the new file extension
113 inputVideoFile.extname = newExtname
114
115 const videoOutputPath = video.getVideoFilePath(inputVideoFile)
116
117 return onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath)
90} 118}
91 119
92async function generateHlsPlaylist (video: VideoModel, resolution: VideoResolution, isPortraitMode: boolean) { 120async function generateHlsPlaylist (video: VideoModel, resolution: VideoResolution, isPortraitMode: boolean) {
@@ -97,6 +125,7 @@ async function generateHlsPlaylist (video: VideoModel, resolution: VideoResoluti
97 const outputPath = join(baseHlsDirectory, VideoStreamingPlaylistModel.getHlsPlaylistFilename(resolution)) 125 const outputPath = join(baseHlsDirectory, VideoStreamingPlaylistModel.getHlsPlaylistFilename(resolution))
98 126
99 const transcodeOptions = { 127 const transcodeOptions = {
128 type: 'hls' as 'hls',
100 inputPath: videoInputPath, 129 inputPath: videoInputPath,
101 outputPath, 130 outputPath,
102 resolution, 131 resolution,
@@ -125,8 +154,34 @@ async function generateHlsPlaylist (video: VideoModel, resolution: VideoResoluti
125 }) 154 })
126} 155}
127 156
157// ---------------------------------------------------------------------------
158
128export { 159export {
129 generateHlsPlaylist, 160 generateHlsPlaylist,
130 optimizeVideofile, 161 optimizeVideofile,
131 transcodeOriginalVideofile 162 transcodeOriginalVideofile,
163 mergeAudioVideofile
164}
165
166// ---------------------------------------------------------------------------
167
168async function onVideoFileTranscoding (video: VideoModel, videoFile: VideoFileModel, transcodingPath: string, outputPath: string) {
169 const stats = await stat(transcodingPath)
170 const fps = await getVideoFileFPS(transcodingPath)
171
172 await move(transcodingPath, outputPath)
173
174 videoFile.set('size', stats.size)
175 videoFile.set('fps', fps)
176
177 await video.createTorrentAndSetInfoHash(videoFile)
178
179 const updatedVideoFile = await videoFile.save()
180
181 // Add it if this is a new created file
182 if (video.VideoFiles.some(f => f.id === videoFile.id) === false) {
183 video.VideoFiles.push(updatedVideoFile)
184 }
185
186 return video
132} 187}