Closed Civlac closed 1 year ago
Thanks for the detailed report! These should be fixed now.
added
-hls_flags split_by_time
to the command, and it correctly created multiple .ts files in the output directory
https://github.com/pulsejet/go-vod/commit/58ac632839537f5c8b16124c7ab5c81a52869f76
Removing the
:passthrough=0
from the command appears to let it run.
https://github.com/pulsejet/go-vod/commit/8d46582c11e3f3598ebf0ad89cb8e79169a842bf
Additionally, do we want the browser making requests to the server for lower resolution videos, even if the end user has selected a specific resolution? As discovered, if a user requests a 1080p video, but it is not supplied, why does it request for the 720p video?
On "Auto", videojs often requests different streams to check the bandwidth for adaptive streaming. But if a single resolution is selected, it should generally only request the video file for the selected resolution, not the others. It will often request the playlists for the other resolutions; this is not an issue since we don't invoke ffmpeg to generate the playlists.
So I built Memories from git to try out your changes, and they appear to all be functional. CUDA & NPP scalers are creating segments, and the folder scrollbar works lovely on desktop and android. 👍
Despite the HW accel transcoding pumping out segments faster, I'm still having issues with playback.
You say it shouldn't be requesting the other playlists, but it seems it still is. The video is set to only 720p, and the Memories default playback setting is direct.
VIDEOJS: WARN: Problem encountered with playlist 2-720p.m3u8. Excessive main segment downloading detected. Switching to playlist 0-360p.m3u8.
(anonymous) @ video.es.js:218
log.warn @ video.es.js:391
excludePlaylist @ video.es.js:47380
checkSegmentDownloads_ @ video.es.js:48279
updateend @ video.es.js:48125
data.dispatcher @ video.es.js:2144
trigger @ video.es.js:2275
trigger @ video.es.js:2621
handleAppendsDone_ @ video.es.js:42802
checkAppendsDone_ @ video.es.js:42707
(anonymous) @ video.es.js:43144
shiftQueue @ video.es.js:43082
(anonymous) @ video.es.js:43254
And FFmpeg is definitely being invoked to render all these other resolutions, as seen in nvtop
in Ubuntu, and the fact all the browser requests have response data.
For some reason, it appears the video will play for the first few seconds, but then freeze & buffer, despite the console showing 200 response status for all the following *.ts files of the requested resolution... This does not happen with CPU transcoding.
Edit: If a shorter video is played (29s), the buffer bar will fully fill once all the .ts files arrive. This appears to happen because all segments of the m3u8 file are fulfilled, however it still doesn't play the video fully through. It also looks like short videos don't surpass the 'excessive main segment downloading' threshold, so it doesn't invoke the playlist-switch. Because of this, it is impossible to fully view short videos. However, longer videos eventually play because the playlist reverts to direct.
If a 3s video is played, only one segment needs to be sent, the playlist is fulfilled and everything plays smoothly. On a 5s video, the first playthrough only plays the first segment (3s of the video). However clicking play again will play the entire 5s from the beginning. On an 11s video, the same effect is seen as the above 5s video, however the second play doesn't show the entire video, instead will only play 6 seconds of the video, aka only two segments, despite successfully receiving 3 segments. A 24s video has the same outcome as the 11s video, but of course receives more segments in total.
Bottom line is that the video freezes after 2 segments, but audio is heard through the entire clip.
Disclaimer: I don't have a NVIDIA card so can't really test anything.
Guessing from having to specify split_by_time
, I think forcing keyframes isn't working as it should be. Can you try this patch on go-vod and see what happens?
diff --git a/stream.go b/stream.go
index 5c09ee6..42efc14 100644
--- a/stream.go
+++ b/stream.go
@@ -519,7 +519,8 @@ func (s *Stream) transcode(startId int) {
"-hls_time", fmt.Sprintf("%d", s.c.ChunkSize),
"-hls_segment_type", "mpegts",
"-hls_segment_filename", s.getTsPath(-1),
- "-force_key_frames", fmt.Sprintf("expr:gte(t,n_forced*%d)", s.c.ChunkSize),
+ "-g:v:0", fmt.Sprintf("%d", s.c.ChunkSize*s.m.probe.FrameRate),
+ "-keyint_min:v:0", fmt.Sprintf("%d", s.c.ChunkSize*s.m.probe.FrameRate),
"-start_number", fmt.Sprintf("%d", startId),
"-",
}...)
BTW can you share the 720p.m3u8
being generated (see the preview tab) and the sizes of the ts
files being downloaded (collapse the side bar and possibly need to add columns)
Took me a minute to figure it out, but I was able to clone go-vod, manually make the edits, and build it. Once I directed Memories to use my custom library, videos are successfully loading on the client. 👍👍
Here's the 720p.m3u8
:
#EXTM3U
#EXT-X-VERSION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:3
#EXTINF:3.000, nodesc
720p-000000.ts
#EXTINF:3.000, nodesc
720p-000001.ts
#EXTINF:3.000, nodesc
720p-000002.ts
#EXTINF:3.000, nodesc
720p-000003.ts
#EXTINF:3.000, nodesc
720p-000004.ts
#EXTINF:3.000, nodesc
720p-000005.ts
#EXTINF:3.000, nodesc
720p-000006.ts
#EXTINF:3.000, nodesc
720p-000007.ts
#EXTINF:3.000, nodesc
720p-000008.ts
#EXTINF:3.000, nodesc
720p-000009.ts
#EXTINF:3.000, nodesc
720p-000010.ts
#EXTINF:3.000, nodesc
720p-000011.ts
#EXTINF:3.000, nodesc
720p-000012.ts
#EXTINF:3.000, nodesc
720p-000013.ts
#EXTINF:3.000, nodesc
720p-000014.ts
#EXTINF:3.000, nodesc
720p-000015.ts
#EXTINF:1.758, nodesc
720p-000016.ts
#EXT-X-ENDLIST
So can you confirm,
force_key_frames
works on CPU transcodingforce_key_frames
does NOT work correctly with NVENC-g
and -keyint_min
works correctly with NVENCYes, force_key_frames
works on CPU, but causes issues with NVENC. Replacing force_key_frames
with '-g' and '-keyint_min' allows the client to play the video.
I built an additional copy of go-vod without any changes, just to confirm enabling external transcoder doesn't impact the outcome.
My compiled go-vod has the exact same functionality as the included go-vod-amd64
when placed in the exiftool-bin
folder and updated in the memories settings page.
The modified go-vod bin then works for both NVENC and CPU transcoding. 🎉
Hopefully my experience applies to other CPU/GPU hardware as well. My configuration is: Intel Xeon E5-2470v2 (x2) Nvidia GTX 1070
Is there any other information you would like?
The bug NVENC accelerated transcoding succeeds, but the client's video will not play since the files are not sliced at all. When a video is requested from the client, transcoding begins, however it creates a single .ts file. Due to the size of transcoding an entire video, the browser appears to timeout, and sends a request for a lower resolution, repeating the process.
To Reproduce Enable NVENC accelerated encoding. Temporal AQ is disabled, using the CUDA scaler. Play a video through memories with a quality setting making use of transcoding. Check the size of the .ts file created (/tmp/go-vod//.ts).
To Fix After pulling the command from the log file (/tmp/go-vod/*.log), I was able to recreate the issue (successfully transcode the file, but only output a single .ts file. FFmpeg reported EXT-X-TARGETDURATION:246 once complete). I added
-hls_flags split_by_time
to the command, and it correctly created multiple .ts files in the output directory, and FFmpeg logged EXT-X-TARGETDURATION:3. CPU transcoding worked from the beginning, and I had no issue transcoding files with libx264 and the split_by_time flag.Platform:
Additional info Unsure if this is a separate bug, but the NPP scaler throws the following error:
Removing the
:passthrough=0
from the command appears to let it run. Again, this results in a single large .ts file unless-hls_flags split_by_time
is added. Please let me know if this NPP filter is due to a forgotten flag when building FFmpeg.Additionally, do we want the browser making requests to the server for lower resolution videos, even if the end user has selected a specific resolution? As discovered, if a user requests a 1080p video, but it is not supplied, why does it request for the 720p video?