bytedeco / javacv

Java interface to OpenCV, FFmpeg, and more
Other
7.58k stars 1.58k forks source link

`setVideoQuality(…)` and libx264 crash based on locale #1670

Open McPringle opened 3 years ago

McPringle commented 3 years ago

In my application I use the FFmpegFrameRecorder with the following configuration:

recorder.setFormat("matroska"); // mp4 doesn't support streaming
recorder.setAudioCodec(AV_CODEC_ID_NONE);
recorder.setVideoCodec(AV_CODEC_ID_H264);
recorder.setPixelFormat(AV_PIX_FMT_YUV420P);
recorder.setFormat("mp4");
recorder.setVideoQuality(24);
recorder.setFrameRate(fps);

Setting the video quality (recorder.setVideoQuality(24);) works or crashes based on the locale of the user. The error message states the reason very clearly:

[libx264 @ 0x7fad69fb2e00] [Eval @ 0x306975170] Invalid chars '.0' at the end of expression '24.0'
[libx264 @ 0x7fad69fb2e00] Unable to parse option value "24.0"
[libx264 @ 0x7fad69fb2e00] Error setting option crf to value 24.0.

I JavaCV, the parameter of setVideoQuality is of type double. libx264 parses the double value which works with an English locale, because an English locate uses the period . character as a decimal separator. In other locales, like mine, the comma , character is used as a decimal separator and the period separates the thousands (like 1.234,56).

I'm using JavaCV 1.5.5 with Java 16.0.1 on macOS 11.4.

Steps to reproduce using the GPX Animator project:

git clone https://github.com/zdila/gpx-animator.git
cd gpx-animator
LANG="en_US.UTF-8" ./gradlew clean it
LANG="de_CH.UTF-8" ./gradlew clean it

Using the steps to reproduce above, the first run uses the English locale and is successful. The second run uses the Swiss-German locale and fails. The it target is my integration test. Don't omit the clean, because Gradle caches the results and we don't change the source during the runs.

If you need more information, please ask and I'm happy to provide any helpful answers.

saudet commented 3 years ago

That seems to be a bug in libx264? In any case, we can set the string value directly to whatever libx264 needs with, for example, FFmpegFrameRecorder.setVideoOption("crf", "24"),

McPringle commented 3 years ago

Thank you very much, for GPX Animator this setter solved the problem.