bytedeco / javacv

Java interface to OpenCV, FFmpeg, and more
Other
7.39k stars 1.56k forks source link

Low video quality from #2215

Closed procura-interna closed 2 months ago

procura-interna commented 2 months ago

I am trying to use JavaCV to create a video from animations I'm generating. The frames are generated as instances of BufferImages. I am not very familiar with the technicalities of working with encoders, so I apologize in advance if this is not the place for these questions.

I'm currently using some test animations. For reference this is what a portion of one of those images looks like:

image

I have a method that receives the images from an Iterator and produces the video using FFmpegFrameRecorder and Java2DFrameConverter.

public void encode(final Iterator<BufferedImage> frames) {
  try (final Java2DFrameConverter converter = new Java2DFrameConverter();
        final FFmpegFrameRecorder recorder = FFmpegFrameRecorder.createDefault(outputPath.toFile(), width,
            height)) {

    recorder.setVideoBitrate(20_000_000);
    recorder.setVideoOption("preset", "slow");
    recorder.setVideoQuality(1);
    recorder.setPixelFormat(org.bytedeco.ffmpeg.global.avutil.AV_PIX_FMT_YUV420P);
    recorder.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4);
    recorder.setFormat("mp4");
    recorder.setFrameRate(fps);
    recorder.start();

    while (frames.hasNext()) {
      final BufferedImage img = frames.next();
      final Frame frame = converter.convert(img);

      recorder.record(frame);
    }

    recorder.stop();
    recorder.release();

  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}

Where "fps" is 60.

Result observed

With codec AV_CODEC_ID_MPEG4

image
  1. The color seems off
  2. Detail seems lower than that of the source images
  3. Having bit rate set to 200_000_000 or 200 seems to produce the identical files

With codec AV_CODEC_ID_H264

image
  1. The color seems off
  2. Detail seems lower than that of the source images
  3. There are very distracting artifacts throughout the video
  4. Console outputs the following: [libopenh264 @ 000002115ff1c680] [OpenH264] this = 0x000002115ff1cd70, Warning:layerId(0) doesn't support profile(578), change to UNSPECIFIC profile
  5. Console outputs the following: [libopenh264 @ 000002115ff1c680] [OpenH264] this = 0x000002115ff1cd70, Warning:bEnableFrameSkip = 0,bitrate can't be controlled for RC_QUALITY_MODE,RC_BITRATE_MODE and RC_TIMESTAMP_MODE without enabling skip frame.

Already tried

Adding recorder.setVideoOption("bEnableFrameSkip", "1") for H264

But the warning persists. From what I understood, I would prefer to not enable frame skip.

Adding recorder.setVideoOption("profile", "baseline") for both codecs

But the program hangs. When I terminate it manually, the following is displayed on the console:

[mpeg4 @ 0000022a7fd6c680] [Eval @ 0000003bb3cfe640] Undefined constant or missing '(' in 'baseline'
[mpeg4 @ 0000022a7fd6c680] Unable to parse option value "baseline"
[mpeg4 @ 0000022a7fd6c680] Error setting option profile to value baseline.

I also tried setting it to "Baseline", "High" but got similar results. Setting it to "high" allowed the program to execute normally, without associated error or stalls, but the output doesn't seem different.

saudet commented 2 months ago

If you're looking for quality you'll need to use a better codec like libx264