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.ts88
1 files changed, 64 insertions, 24 deletions
diff --git a/server/lib/video-transcoding.ts b/server/lib/video-transcoding.ts
index d6b6b251a..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, canDoQuickTranscode } 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'
@@ -23,13 +23,15 @@ async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFi
23 const videoInputPath = join(videosDirectory, video.getVideoFilename(inputVideoFile)) 23 const videoInputPath = join(videosDirectory, video.getVideoFilename(inputVideoFile))
24 const videoTranscodedPath = join(transcodeDirectory, video.id + '-transcoded' + newExtname) 24 const videoTranscodedPath = join(transcodeDirectory, video.id + '-transcoded' + newExtname)
25 25
26 const doQuickTranscode = await(canDoQuickTranscode(videoInputPath)) 26 const transcodeType: TranscodeOptionsType = await canDoQuickTranscode(videoInputPath)
27 ? 'quick-transcode'
28 : 'video'
27 29
28 const transcodeOptions = { 30 const transcodeOptions: TranscodeOptions = {
31 type: transcodeType as any, // FIXME: typing issue
29 inputPath: videoInputPath, 32 inputPath: videoInputPath,
30 outputPath: videoTranscodedPath, 33 outputPath: videoTranscodedPath,
31 resolution: inputVideoFile.resolution, 34 resolution: inputVideoFile.resolution
32 doQuickTranscode
33 } 35 }
34 36
35 // Could be very long! 37 // Could be very long!
@@ -39,19 +41,11 @@ async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFi
39 await remove(videoInputPath) 41 await remove(videoInputPath)
40 42
41 // 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
42 inputVideoFile.set('extname', newExtname) 44 inputVideoFile.extname = newExtname
43
44 const stats = await stat(videoTranscodedPath)
45 const fps = await getVideoFileFPS(videoTranscodedPath)
46 45
47 const videoOutputPath = video.getVideoFilePath(inputVideoFile) 46 const videoOutputPath = video.getVideoFilePath(inputVideoFile)
48 await move(videoTranscodedPath, videoOutputPath)
49 47
50 inputVideoFile.set('size', stats.size) 48 await onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath)
51 inputVideoFile.set('fps', fps)
52
53 await video.createTorrentAndSetInfoHash(inputVideoFile)
54 await inputVideoFile.save()
55 } catch (err) { 49 } catch (err) {
56 // Auto destruction... 50 // Auto destruction...
57 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 }))
@@ -81,6 +75,7 @@ async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoR
81 const videoTranscodedPath = join(transcodeDirectory, video.getVideoFilename(newVideoFile)) 75 const videoTranscodedPath = join(transcodeDirectory, video.getVideoFilename(newVideoFile))
82 76
83 const transcodeOptions = { 77 const transcodeOptions = {
78 type: 'video' as 'video',
84 inputPath: videoInputPath, 79 inputPath: videoInputPath,
85 outputPath: videoTranscodedPath, 80 outputPath: videoTranscodedPath,
86 resolution, 81 resolution,
@@ -89,19 +84,37 @@ async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoR
89 84
90 await transcode(transcodeOptions) 85 await transcode(transcodeOptions)
91 86
92 const stats = await stat(videoTranscodedPath) 87 return onVideoFileTranscoding(video, newVideoFile, videoTranscodedPath, videoOutputPath)
93 const fps = await getVideoFileFPS(videoTranscodedPath) 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()
94 96
95 await move(videoTranscodedPath, videoOutputPath) 97 const audioInputPath = join(videosDirectory, video.getVideoFilename(video.getOriginalFile()))
98 const videoTranscodedPath = join(transcodeDirectory, video.id + '-transcoded' + newExtname)
96 99
97 newVideoFile.set('size', stats.size) 100 const transcodeOptions = {
98 newVideoFile.set('fps', fps) 101 type: 'merge-audio' as 'merge-audio',
102 inputPath: video.getPreview().getPath(),
103 outputPath: videoTranscodedPath,
104 audioPath: audioInputPath,
105 resolution
106 }
99 107
100 await video.createTorrentAndSetInfoHash(newVideoFile) 108 await transcode(transcodeOptions)
101 109
102 await newVideoFile.save() 110 await remove(audioInputPath)
103 111
104 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)
105} 118}
106 119
107async function generateHlsPlaylist (video: VideoModel, resolution: VideoResolution, isPortraitMode: boolean) { 120async function generateHlsPlaylist (video: VideoModel, resolution: VideoResolution, isPortraitMode: boolean) {
@@ -112,6 +125,7 @@ async function generateHlsPlaylist (video: VideoModel, resolution: VideoResoluti
112 const outputPath = join(baseHlsDirectory, VideoStreamingPlaylistModel.getHlsPlaylistFilename(resolution)) 125 const outputPath = join(baseHlsDirectory, VideoStreamingPlaylistModel.getHlsPlaylistFilename(resolution))
113 126
114 const transcodeOptions = { 127 const transcodeOptions = {
128 type: 'hls' as 'hls',
115 inputPath: videoInputPath, 129 inputPath: videoInputPath,
116 outputPath, 130 outputPath,
117 resolution, 131 resolution,
@@ -140,8 +154,34 @@ async function generateHlsPlaylist (video: VideoModel, resolution: VideoResoluti
140 }) 154 })
141} 155}
142 156
157// ---------------------------------------------------------------------------
158
143export { 159export {
144 generateHlsPlaylist, 160 generateHlsPlaylist,
145 optimizeVideofile, 161 optimizeVideofile,
146 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
147} 187}