aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2020-11-06 09:09:36 +0100
committerChocobozzz <chocobozzz@cpy.re>2020-11-09 15:33:04 +0100
commit3bc68dfd6183078fb56b53e24e74f889c85c4ae0 (patch)
treeeac38175bf815227f39bf0327c7399b85b05ad08
parentf8c00564e7e66c7c9d65ea044a4c1485df0e4c7c (diff)
downloadPeerTube-3bc68dfd6183078fb56b53e24e74f889c85c4ae0.tar.gz
PeerTube-3bc68dfd6183078fb56b53e24e74f889c85c4ae0.tar.zst
PeerTube-3bc68dfd6183078fb56b53e24e74f889c85c4ae0.zip
Fix audio sync after saving replay
hls.js seems to not correctly handle audio gaps with fragmented mp4 (but can with a ts playlist)
-rw-r--r--client/package.json2
-rw-r--r--client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts4
-rw-r--r--client/yarn.lock8
-rw-r--r--server.ts4
-rw-r--r--server/helpers/ffmpeg-utils.ts30
-rw-r--r--server/lib/job-queue/handlers/video-live-ending.ts4
6 files changed, 27 insertions, 25 deletions
diff --git a/client/package.json b/client/package.json
index cb6f77166..152f8445f 100644
--- a/client/package.json
+++ b/client/package.json
@@ -80,7 +80,7 @@
80 "extract-text-webpack-plugin": "4.0.0-beta.0", 80 "extract-text-webpack-plugin": "4.0.0-beta.0",
81 "file-loader": "^6.0.0", 81 "file-loader": "^6.0.0",
82 "focus-visible": "^5.0.2", 82 "focus-visible": "^5.0.2",
83 "hls.js": "^0.14.9", 83 "hls.js": "^0.14.16",
84 "html-loader": "^1.0.0", 84 "html-loader": "^1.0.0",
85 "html-webpack-plugin": "^4.0.3", 85 "html-webpack-plugin": "^4.0.3",
86 "https-browserify": "^1.0.0", 86 "https-browserify": "^1.0.0",
diff --git a/client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts b/client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts
index 18b4a2f3c..321f7b09f 100644
--- a/client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts
+++ b/client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts
@@ -93,7 +93,7 @@ export class VideoActionsDropdownComponent implements OnChanges {
93 ngOnChanges () { 93 ngOnChanges () {
94 if (this.loaded) { 94 if (this.loaded) {
95 this.loaded = false 95 this.loaded = false
96 this.playlistAdd.reload() 96 if (this.playlistAdd) this.playlistAdd.reload()
97 } 97 }
98 98
99 this.buildActions() 99 this.buildActions()
@@ -277,7 +277,7 @@ export class VideoActionsDropdownComponent implements OnChanges {
277 { 277 {
278 label: $localize`Display live information`, 278 label: $localize`Display live information`,
279 handler: ({ video }) => this.showLiveInfoModal(video), 279 handler: ({ video }) => this.showLiveInfoModal(video),
280 isDisplayed: () => this.isVideoLiveInfoAvailable(), 280 isDisplayed: () => this.displayOptions.liveInfo && this.isVideoLiveInfoAvailable(),
281 iconName: 'live' 281 iconName: 'live'
282 }, 282 },
283 { 283 {
diff --git a/client/yarn.lock b/client/yarn.lock
index cdafe1458..d3603a4a9 100644
--- a/client/yarn.lock
+++ b/client/yarn.lock
@@ -5586,10 +5586,10 @@ hex-color-regex@^1.1.0:
5586 resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" 5586 resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
5587 integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== 5587 integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
5588 5588
5589hls.js@^0.14.9: 5589hls.js@^0.14.16:
5590 version "0.14.9" 5590 version "0.14.16"
5591 resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-0.14.9.tgz#e85be87d94385ed9947155716578f7c568957d15" 5591 resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-0.14.16.tgz#4ff68a1fa7260a43d316270e9bc7f7bdf93c5731"
5592 integrity sha512-5j1ONTvIzcIxCtg2eafikFbZ3b/9fDhR6u871LmK7jZ44/Qdc2G4xaSBCwcVK61gz7kTyiobaAhB++2M4J58rQ== 5592 integrity sha512-VACiO99DQFBpflR4fI+6GVHUZn35R0SGGQo0XTDZOm2BUXbeuDHTghTC/k2/3wGln6KBmG8/bXIcDIzDsY2UEg==
5593 dependencies: 5593 dependencies:
5594 eventemitter3 "^4.0.3" 5594 eventemitter3 "^4.0.3"
5595 url-toolkit "^2.1.6" 5595 url-toolkit "^2.1.6"
diff --git a/server.ts b/server.ts
index e2ff6327b..6963bbf23 100644
--- a/server.ts
+++ b/server.ts
@@ -142,14 +142,14 @@ if (isTestInstance()) {
142} 142}
143 143
144// For the logger 144// For the logger
145morgan.token('remote-addr', req => { 145morgan.token('remote-addr', (req: express.Request) => {
146 if (CONFIG.LOG.ANONYMIZE_IP === true || req.get('DNT') === '1') { 146 if (CONFIG.LOG.ANONYMIZE_IP === true || req.get('DNT') === '1') {
147 return anonymize(req.ip, 16, 16) 147 return anonymize(req.ip, 16, 16)
148 } 148 }
149 149
150 return req.ip 150 return req.ip
151}) 151})
152morgan.token('user-agent', req => { 152morgan.token('user-agent', (req: express.Request) => {
153 if (req.get('DNT') === '1') { 153 if (req.get('DNT') === '1') {
154 return useragent.parse(req.get('user-agent')).family 154 return useragent.parse(req.get('user-agent')).family
155 } 155 }
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts
index 3b794b8a2..7a54b4642 100644
--- a/server/helpers/ffmpeg-utils.ts
+++ b/server/helpers/ffmpeg-utils.ts
@@ -1,5 +1,5 @@
1import * as ffmpeg from 'fluent-ffmpeg' 1import * as ffmpeg from 'fluent-ffmpeg'
2import { readFile, remove, writeFile } from 'fs-extra' 2import { outputFile, readFile, remove, writeFile } from 'fs-extra'
3import { dirname, join } from 'path' 3import { dirname, join } from 'path'
4import { VideoFileMetadata } from '@shared/models/videos/video-file-metadata' 4import { VideoFileMetadata } from '@shared/models/videos/video-file-metadata'
5import { getMaxBitrate, getTargetBitrate, VideoResolution } from '../../shared/models/videos' 5import { getMaxBitrate, getTargetBitrate, VideoResolution } from '../../shared/models/videos'
@@ -423,8 +423,14 @@ function runLiveMuxing (rtmpUrl: string, outPath: string, deleteSegments: boolea
423} 423}
424 424
425async function hlsPlaylistToFragmentedMP4 (hlsDirectory: string, segmentFiles: string[], outputPath: string) { 425async function hlsPlaylistToFragmentedMP4 (hlsDirectory: string, segmentFiles: string[], outputPath: string) {
426 const concatFile = 'concat.txt' 426 const concatFilePath = join(hlsDirectory, 'concat.txt')
427 const concatFilePath = join(hlsDirectory, concatFile) 427
428 function cleaner () {
429 remove(concatFilePath)
430 .catch(err => logger.error('Cannot remove concat file in %s.', hlsDirectory, { err }))
431 }
432
433 // First concat the ts files to a mp4 file
428 const content = segmentFiles.map(f => 'file ' + f) 434 const content = segmentFiles.map(f => 'file ' + f)
429 .join('\n') 435 .join('\n')
430 436
@@ -434,25 +440,25 @@ async function hlsPlaylistToFragmentedMP4 (hlsDirectory: string, segmentFiles: s
434 command.inputOption('-safe 0') 440 command.inputOption('-safe 0')
435 command.inputOption('-f concat') 441 command.inputOption('-f concat')
436 442
437 command.outputOption('-c copy') 443 command.outputOption('-c:v copy')
444 command.audioFilter('aresample=async=1:first_pts=0')
438 command.output(outputPath) 445 command.output(outputPath)
439 446
440 command.run() 447 return runCommand(command, cleaner)
448}
441 449
442 function cleaner () { 450async function runCommand (command: ffmpeg.FfmpegCommand, onEnd?: Function) {
443 remove(concatFilePath) 451 command.run()
444 .catch(err => logger.error('Cannot remove concat file in %s.', hlsDirectory, { err }))
445 }
446 452
447 return new Promise<string>((res, rej) => { 453 return new Promise<string>((res, rej) => {
448 command.on('error', err => { 454 command.on('error', err => {
449 cleaner() 455 if (onEnd) onEnd()
450 456
451 rej(err) 457 rej(err)
452 }) 458 })
453 459
454 command.on('end', () => { 460 command.on('end', () => {
455 cleaner() 461 if (onEnd) onEnd()
456 462
457 res() 463 res()
458 }) 464 })
@@ -501,7 +507,7 @@ function addDefaultLiveHLSParams (command: ffmpeg.FfmpegCommand, outPath: string
501 command.outputOption('-hls_flags delete_segments') 507 command.outputOption('-hls_flags delete_segments')
502 } 508 }
503 509
504 command.outputOption(`-hls_segment_filename ${join(outPath, '%v-%d.ts')}`) 510 command.outputOption(`-hls_segment_filename ${join(outPath, '%v-%04d.ts')}`)
505 command.outputOption('-master_pl_name master.m3u8') 511 command.outputOption('-master_pl_name master.m3u8')
506 command.outputOption(`-f hls`) 512 command.outputOption(`-f hls`)
507 513
diff --git a/server/lib/job-queue/handlers/video-live-ending.ts b/server/lib/job-queue/handlers/video-live-ending.ts
index 2b900998a..3892260c4 100644
--- a/server/lib/job-queue/handlers/video-live-ending.ts
+++ b/server/lib/job-queue/handlers/video-live-ending.ts
@@ -70,10 +70,6 @@ async function saveLive (video: MVideo, live: MVideoLive) {
70 const segmentFiles = files.filter(f => f.startsWith(shouldStartWith) && f.endsWith('.ts')) 70 const segmentFiles = files.filter(f => f.startsWith(shouldStartWith) && f.endsWith('.ts'))
71 await hlsPlaylistToFragmentedMP4(hlsDirectory, segmentFiles, mp4TmpPath) 71 await hlsPlaylistToFragmentedMP4(hlsDirectory, segmentFiles, mp4TmpPath)
72 72
73 for (const file of segmentFiles) {
74 await remove(join(hlsDirectory, file))
75 }
76
77 if (!duration) { 73 if (!duration) {
78 duration = await getDurationFromVideoFile(mp4TmpPath) 74 duration = await getDurationFromVideoFile(mp4TmpPath)
79 } 75 }