X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Flib%2Fvideo-transcoding.ts;h=37a4f3019b0ab6499bee27ba4d29c6ffeb5395ad;hb=1896bca09e088b0da9d5e845407ecebae330618c;hp=890b23a449b75e4aede4139938198b065762ae60;hpb=2650d6d489f775a38c5c3fdb65daabc7d55c15b5;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/lib/video-transcoding.ts b/server/lib/video-transcoding.ts index 890b23a44..37a4f3019 100644 --- a/server/lib/video-transcoding.ts +++ b/server/lib/video-transcoding.ts @@ -1,4 +1,5 @@ -import { copyFile, ensureDir, move, remove, stat, writeFile } from 'fs-extra' +import { Job } from 'bull' +import { copyFile, ensureDir, move, remove, stat } from 'fs-extra' import { basename, extname as extnameUtil, join } from 'path' import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' import { MStreamingPlaylistFilesVideo, MVideoFile, MVideoWithAllFiles, MVideoWithFile } from '@server/types/models' @@ -13,7 +14,7 @@ import { VideoFileModel } from '../models/video/video-file' import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' import { updateMasterHLSPlaylist, updateSha256VODSegments } from './hls' import { generateVideoStreamingPlaylistName, getVideoFilename, getVideoFilePath } from './video-paths' -import { availableEncoders } from './video-transcoding-profiles' +import { VideoTranscodingProfilesManager } from './video-transcoding-profiles' /** * @@ -23,11 +24,10 @@ import { availableEncoders } from './video-transcoding-profiles' */ // Optimize the original video file and replace it. The resolution is not changed. -async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFileArg?: MVideoFile) { +async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFile: MVideoFile, job?: Job) { const transcodeDirectory = CONFIG.STORAGE.TMP_DIR const newExtname = '.mp4' - const inputVideoFile = inputVideoFileArg || video.getMaxQualityFile() const videoInputPath = getVideoFilePath(video, inputVideoFile) const videoTranscodedPath = join(transcodeDirectory, video.id + '-transcoded' + newExtname) @@ -41,10 +41,12 @@ async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFileA inputPath: videoInputPath, outputPath: videoTranscodedPath, - availableEncoders, - profile: 'default', + availableEncoders: VideoTranscodingProfilesManager.Instance.getAvailableEncoders(), + profile: CONFIG.TRANSCODING.PROFILE, - resolution: inputVideoFile.resolution + resolution: inputVideoFile.resolution, + + job } // Could be very long! @@ -58,7 +60,9 @@ async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFileA const videoOutputPath = getVideoFilePath(video, inputVideoFile) - await onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath) + await onWebTorrentVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath) + + return transcodeType } catch (err) { // Auto destruction... video.destroy().catch(err => logger.error('Cannot destruct video after transcoding failure.', { err })) @@ -68,7 +72,7 @@ async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFileA } // Transcode the original video file to a lower resolution. -async function transcodeNewResolution (video: MVideoWithFile, resolution: VideoResolution, isPortrait: boolean) { +async function transcodeNewWebTorrentResolution (video: MVideoWithFile, resolution: VideoResolution, isPortrait: boolean, job: Job) { const transcodeDirectory = CONFIG.STORAGE.TMP_DIR const extname = '.mp4' @@ -91,30 +95,34 @@ async function transcodeNewResolution (video: MVideoWithFile, resolution: VideoR inputPath: videoInputPath, outputPath: videoTranscodedPath, - availableEncoders, - profile: 'default', + availableEncoders: VideoTranscodingProfilesManager.Instance.getAvailableEncoders(), + profile: CONFIG.TRANSCODING.PROFILE, + + resolution, - resolution + job } : { type: 'video' as 'video', inputPath: videoInputPath, outputPath: videoTranscodedPath, - availableEncoders, - profile: 'default', + availableEncoders: VideoTranscodingProfilesManager.Instance.getAvailableEncoders(), + profile: CONFIG.TRANSCODING.PROFILE, resolution, - isPortraitMode: isPortrait + isPortraitMode: isPortrait, + + job } await transcode(transcodeOptions) - return onVideoFileTranscoding(video, newVideoFile, videoTranscodedPath, videoOutputPath) + return onWebTorrentVideoFileTranscoding(video, newVideoFile, videoTranscodedPath, videoOutputPath) } // Merge an image with an audio file to create a video -async function mergeAudioVideofile (video: MVideoWithAllFiles, resolution: VideoResolution) { +async function mergeAudioVideofile (video: MVideoWithAllFiles, resolution: VideoResolution, job: Job) { const transcodeDirectory = CONFIG.STORAGE.TMP_DIR const newExtname = '.mp4' @@ -134,11 +142,13 @@ async function mergeAudioVideofile (video: MVideoWithAllFiles, resolution: Video inputPath: tmpPreviewPath, outputPath: videoTranscodedPath, - availableEncoders, - profile: 'default', + availableEncoders: VideoTranscodingProfilesManager.Instance.getAvailableEncoders(), + profile: CONFIG.TRANSCODING.PROFILE, audioPath: audioInputPath, - resolution + resolution, + + job } try { @@ -160,56 +170,35 @@ async function mergeAudioVideofile (video: MVideoWithAllFiles, resolution: Video video.duration = await getDurationFromVideoFile(videoTranscodedPath) await video.save() - return onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath) + return onWebTorrentVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath) } // Concat TS segments from a live video to a fragmented mp4 HLS playlist -async function generateHlsPlaylistFromTS (options: { +async function generateHlsPlaylistResolutionFromTS (options: { video: MVideoWithFile - replayDirectory: string - segmentFiles: string[] + concatenatedTsFilePath: string resolution: VideoResolution isPortraitMode: boolean + isAAC: boolean }) { - const concatFilePath = join(options.replayDirectory, 'concat.txt') - - function cleaner () { - remove(concatFilePath) - .catch(err => logger.error('Cannot remove concat file in %s.', options.replayDirectory, { err })) - } - - // First concat the ts files to a mp4 file - const content = options.segmentFiles.map(f => 'file ' + f) - .join('\n') - - await writeFile(concatFilePath, content + '\n') - - try { - const outputPath = await generateHlsPlaylistCommon({ - video: options.video, - resolution: options.resolution, - isPortraitMode: options.isPortraitMode, - inputPath: concatFilePath, - type: 'hls-from-ts' as 'hls-from-ts' - }) - - cleaner() - - return outputPath - } catch (err) { - cleaner() - - throw err - } + return generateHlsPlaylistCommon({ + video: options.video, + resolution: options.resolution, + isPortraitMode: options.isPortraitMode, + inputPath: options.concatenatedTsFilePath, + type: 'hls-from-ts' as 'hls-from-ts', + isAAC: options.isAAC + }) } // Generate an HLS playlist from an input file, and update the master playlist -function generateHlsPlaylist (options: { +function generateHlsPlaylistResolution (options: { video: MVideoWithFile videoInputPath: string resolution: VideoResolution copyCodecs: boolean isPortraitMode: boolean + job?: Job }) { return generateHlsPlaylistCommon({ video: options.video, @@ -217,23 +206,40 @@ function generateHlsPlaylist (options: { copyCodecs: options.copyCodecs, isPortraitMode: options.isPortraitMode, inputPath: options.videoInputPath, - type: 'hls' as 'hls' + type: 'hls' as 'hls', + job: options.job }) } +function getEnabledResolutions (type: 'vod' | 'live') { + const transcoding = type === 'vod' + ? CONFIG.TRANSCODING + : CONFIG.LIVE.TRANSCODING + + return Object.keys(transcoding.RESOLUTIONS) + .filter(key => transcoding.ENABLED && transcoding.RESOLUTIONS[key] === true) + .map(r => parseInt(r, 10)) +} + // --------------------------------------------------------------------------- export { - generateHlsPlaylist, - generateHlsPlaylistFromTS, + generateHlsPlaylistResolution, + generateHlsPlaylistResolutionFromTS, optimizeOriginalVideofile, - transcodeNewResolution, - mergeAudioVideofile + transcodeNewWebTorrentResolution, + mergeAudioVideofile, + getEnabledResolutions } // --------------------------------------------------------------------------- -async function onVideoFileTranscoding (video: MVideoWithFile, videoFile: MVideoFile, transcodingPath: string, outputPath: string) { +async function onWebTorrentVideoFileTranscoding ( + video: MVideoWithFile, + videoFile: MVideoFile, + transcodingPath: string, + outputPath: string +) { const stats = await stat(transcodingPath) const fps = await getVideoFileFPS(transcodingPath) const metadata = await getMetadataFromFile(transcodingPath) @@ -258,9 +264,12 @@ async function generateHlsPlaylistCommon (options: { inputPath: string resolution: VideoResolution copyCodecs?: boolean + isAAC?: boolean isPortraitMode: boolean + + job?: Job }) { - const { type, video, inputPath, resolution, copyCodecs, isPortraitMode } = options + const { type, video, inputPath, resolution, copyCodecs, isPortraitMode, isAAC, job } = options const baseHlsDirectory = join(HLS_STREAMING_PLAYLIST_DIRECTORY, video.uuid) await ensureDir(join(HLS_STREAMING_PLAYLIST_DIRECTORY, video.uuid)) @@ -274,16 +283,20 @@ async function generateHlsPlaylistCommon (options: { inputPath, outputPath, - availableEncoders, - profile: 'default', + availableEncoders: VideoTranscodingProfilesManager.Instance.getAvailableEncoders(), + profile: CONFIG.TRANSCODING.PROFILE, resolution, copyCodecs, isPortraitMode, + isAAC, + hlsPlaylist: { videoFilename - } + }, + + job } await transcode(transcodeOptions)