octoprint-docker icon indicating copy to clipboard operation
octoprint-docker copied to clipboard

Support to encode timelapse videos with H.265 / HEVC

Open epheterson opened this issue 2 years ago • 8 comments

Describe the solution you'd like To have smaller timelapse video files to share when the print is done, it'd be great if we could start encoding with H.265 / HEVC. This will result in essentially the same quality video, but much smaller file size.

I understand the ffmpeg command line is now editable, but don't believe the Octoprint docker package ships with ffmpeg capable of h.265 encoding, so it would have to be re-compiled. Ideally H.265 could be a simple selection in the drop-down of advanced timelapse settings.

Additional context Asked on OctoPrint github and was directed to send the request here: https://github.com/OctoPrint/OctoPrint/issues/4538

epheterson avatar Jun 10 '22 01:06 epheterson

we're installing ffmpeg from the ubuntu repositories, which winds up being 4.1.9. According to the ffmpeg wiki

fmpeg needs to be built with the --enable-gpl --enable-libx265 configuration flags and requires x265 to be installed on your system

These flags do appear to be part of the ffmpeg configuration in the octoprint image:

docker run -it --rm --entrypoint /bin/sh octoprint/octoprint:latest 
# ffmpeg -version
ffmpeg version 4.1.9-0+deb10u1 Copyright (c) 2000-2022 the FFmpeg developers
built with gcc 8 (Debian 8.3.0-6)
configuration: --prefix=/usr --extra-version=0+deb10u1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
libavutil      56. 22.100 / 56. 22.100
libavcodec     58. 35.100 / 58. 35.100
libavformat    58. 20.100 / 58. 20.100
libavdevice    58.  5.100 / 58.  5.100
libavfilter     7. 40.101 /  7. 40.101
libavresample   4.  0.  0 /  4.  0.  0
libswscale      5.  3.100 /  5.  3.100
libswresample   3.  3.100 /  3.  3.100
libpostproc    55.  3.100 / 55.  3.100

I'm not up to speed on actually running ffmpeg with this output option, but I'm wondering if it requires gpu access? That may mean you'd need additional configuration with docker to enable that capability.

Have you actually tried to run ffmpeg with those encoding options in the image? If so, what errors or output did you get?

I believe the ffmpeg in the image is configured correctly according to ffmpeg documentation, so this may just be more of a documentation isssue once we figure this out. This is the first time this has come up, so we appreciate any information you can provide beyond the feature request, in regards to what you've tried, and what you're results were with those attempts (including error messages or logs when relevant).

LongLiveCHIEF avatar Jun 15 '22 14:06 LongLiveCHIEF

Actually, i missed the part where it said x265 needs to be installed on the system, and that's easy enough to fix by adding that package to the apt install step of the Dockerfile. I can definitely add that.

LongLiveCHIEF avatar Jun 15 '22 14:06 LongLiveCHIEF

I've merged and deployed a new image with x265 dependency in the image. That should be all that was mising. Once the new image finishes building and deploying, can you pull it down and give this a shot?

Thanks!

LongLiveCHIEF avatar Jun 15 '22 20:06 LongLiveCHIEF

Thanks, giving it a shot. I'm not positive what the best command is to use, some considerations:

  • Setting a constant bitrate will result in not necessarily saving any on the filesize. (To workaround this, I removed bitrate altogether to utilize default crf.)
  • Built-in variables for container format and filters may not be compatible
  • I can only test once per print

Do you know of a way to re-run the timelapse rendering so I can test multiple settings? Also do you know how to add the codec to the drop-down list for easy user selection? (I'd prefer to not have to use a custom ffmpeg command)

Starting with: {ffmpeg} -framerate {fps} -i "{input}" -vcodec libx265 -threads {threads} -f {containerformat} -y {filters} "{output}"

Think I might want to try something closer to what the docs suggest, though: ffmpeg -i input -c:v libx265 -crf 26 -preset fast -c:a aac -b:a 128k output.mp4

For us this would be something like: {ffmpeg} -framerate {fps} -i "{input}" -c:v libx265 -crf 26 -preset fast -threads {threads} -f {containerformat} -y {filters} "{output}"

Unrelated, but to further save on unnecessary filesize I may want to reduce the resolution (no need for 1080p timelapse videos) using something like: -vf scale=-1:720

epheterson avatar Jun 16 '22 00:06 epheterson

Well, my first one made a file, and the file size is ~45% of MP4 size, but it doesn't play in Quicktime, though does play in VLC.

ffmpeg -i shows it's HEVC, correct framerate/resolution and 4092 kb/s (vs. default of 10000 kb/s): Stream #0:0[0x1](und): Video: hevc (Main) (hev1 / 0x31766568), yuv420p(tv, progressive), 1920x1080, 4092 kb/s, 25 fps, 25 tbr, 12800 tbn (default)

Going to see if I can figure out why Quicktime / browser won't play it.

epheterson avatar Jun 16 '22 04:06 epheterson

Got it! For hevc this must be included: -vtag hvc1

So the full modified line, with bitrate removed and -vtag hvc1 added is: {ffmpeg} -framerate {fps} -i "{input}" -vcodec libx265 -vtag hvc1 -threads {threads} -f {containerformat} -y {filters} "{output}"

Thanks for adding the codec support! Do you know how we can go about making this an "official" option that's easy to select?

epheterson avatar Jun 16 '22 06:06 epheterson

Well, if you're interested in doing a PR, then here's what I'd probably do.

  • create an env var for CAMERA_H265
  • modify the mjpg-streamer service script so it tests for this variable, and if set, then uses those args to start instead of the default

This is the basic approach mind you, there might be more logic needed there.

If this isn't something you can contribute, go ahead and open a feature request issue for add CAMERA_H265 env var start option, and link to this video, and I'll try to get to it.

LongLiveCHIEF avatar Jun 20 '22 15:06 LongLiveCHIEF

Hey @LongLiveCHIEF thanks for the steps though I'm totally sure how to go about it. I've filed a new issue as you suggested: https://github.com/OctoPrint/octoprint-docker/issues/228

epheterson avatar Jun 20 '22 22:06 epheterson