diff --git a/.gitignore b/.gitignore index a31da70a9..681004527 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ /config/local* /ffmpeg/ /ffmpeg-4/ +/ffmpeg-3/ /thumbnails/ /torrents/ /videos/ diff --git a/config/default.yaml b/config/default.yaml index 5a83b271e..7af615a82 100644 --- a/config/default.yaml +++ b/config/default.yaml @@ -140,12 +140,12 @@ transcoding: 720p: false 1080p: false # /!\ EXPERIMENTAL /!\ - # /!\ Requires ffmpeg >= 3.4 - # Generate HLS playlist/segments. Better playback than with WebTorrent: + # /!\ Requires ffmpeg >= 4 + # Generate HLS playlists and fragmented MP4 files. Better playback than with WebTorrent: # * Resolution change is smoother # * Faster playback in particular with long videos # * More stable playback (less bugs/infinite loading) - # /!\ Multiply videos storage by two /!\ + # /!\ Multiply videos storage by 2 /!\ hls: enabled: false diff --git a/config/production.yaml.example b/config/production.yaml.example index c54e1a516..413e3c478 100644 --- a/config/production.yaml.example +++ b/config/production.yaml.example @@ -153,12 +153,12 @@ transcoding: 720p: false 1080p: false # /!\ EXPERIMENTAL /!\ - # /!\ Requires ffmpeg >= 3.4 - # Generate HLS playlist/segments. Better playback than with WebTorrent: + # /!\ Requires ffmpeg >= 4 + # Generate HLS playlists and fragmented MP4 files. Better playback than with WebTorrent: # * Resolution change is smoother # * Faster playback in particular with long videos # * More stable playback (less bugs/infinite loading) - # /!\ Multiply videos storage by two /!\ + # /!\ Multiply videos storage by 2 /!\ hls: enabled: false diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index 133b1b03b..b6b64de3f 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts @@ -5,7 +5,7 @@ import { CONFIG, FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/cons import { processImage } from './image-utils' import { logger } from './logger' import { checkFFmpegEncoders } from '../initializers/checker-before-init' -import { remove } from 'fs-extra' +import { remove, readFile, writeFile } from 'fs-extra' function computeResolutionsToTranscode (videoFileHeight: number) { const resolutionsEnabled: number[] = [] @@ -164,7 +164,7 @@ function transcode (options: TranscodeOptions) { } if (options.hlsPlaylist) { - const videoPath = `${dirname(options.outputPath)}/${options.hlsPlaylist.videoFilename}` + const videoPath = getHLSVideoPath(options) command = command.outputOption('-hls_time 4') .outputOption('-hls_list_size 0') @@ -180,7 +180,11 @@ function transcode (options: TranscodeOptions) { logger.error('Error in transcoding job.', { stdout, stderr }) return rej(err) }) - .on('end', res) + .on('end', () => { + return onTranscodingSuccess(options) + .then(() => res()) + .catch(err => rej(err)) + }) .run() } catch (err) { return rej(err) @@ -204,6 +208,25 @@ export { // --------------------------------------------------------------------------- +function getHLSVideoPath (options: TranscodeOptions) { + return `${dirname(options.outputPath)}/${options.hlsPlaylist.videoFilename}` +} + +async function onTranscodingSuccess (options: TranscodeOptions) { + if (!options.hlsPlaylist) return + + // Fix wrong mapping with some ffmpeg versions + const fileContent = await readFile(options.outputPath) + + const videoFileName = options.hlsPlaylist.videoFilename + const videoFilePath = getHLSVideoPath(options) + + const newContent = fileContent.toString() + .replace(`#EXT-X-MAP:URI="${videoFilePath}",`, `#EXT-X-MAP:URI="${videoFileName}",`) + + await writeFile(options.outputPath, newContent) +} + function getVideoFileStream (path: string) { return new Promise((res, rej) => { ffmpeg.ffprobe(path, (err, metadata) => {