You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaCV FFmpegFrameRecorder存图像为视频报错及码率设置咨询

Troubleshooting JavaCV FFmpegFrameRecorder Crash & 16-bit Video Encoding Guide

Let's break down the issues in your code and fix the crash first, then address the bitrate question for 16-bit images.

Why You're Getting the EXCEPTION_ACCESS_VIOLATION

This crash stems from invalid memory access in the FFmpeg JNI layer, caused by several critical mistakes in your code:

  1. Incorrect Recorder Initialization
    You used new FFmpegFrameRecorder(dest, 0) — the second parameter here expects the video width, not 0. This misconfiguration throws off all subsequent video parameter setup, leading to memory misalignment later.

  2. Invalid recordImage Parameters

    • You passed 0 for the pixel format, which maps to AV_PIX_FMT_NONE — FFmpeg can't interpret your image data with this setting. For 8-bit single-channel grayscale, use AV_PIX_FMT_GRAY8 (value 8 in JavaCV's avutil constants).
    • The stride parameter is set to 0. Stride is the number of bytes per row in your image; for 8-bit single-channel content, this should equal your image width (200). A stride of 0 forces FFmpeg to guess, which almost always leads to out-of-bounds memory reads.
  3. Array Index Out-of-Bounds in Debug Logic
    Your loop to modify myimage has a fatal error: when i >= 1, myimage.length * i equals 20000 * 1 = 20000, which is exactly the array's length. Trying to access myimage[20000] triggers an array out-of-bounds exception, corrupting the buffer data passed to FFmpeg.

Fixed Code Example

Here's the corrected version that should run without crashing:

package ffmpeg;

import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameRecorder;

import java.io.File;
import java.nio.ByteBuffer;

public class VideoRecorder {
    public static void main(String[] args) {
        try {
            // Image parameters
            int width = 200;
            int height = 100;
            int channels = 1;
            int depth = 8;
            int frameCount = 100;
            double frameRate = 0.04;

            // Output file
            File dest = new File("C:\\out.mp4");

            // Initialize recorder correctly with width and height
            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(dest, width, height);
            recorder.setFrameRate(frameRate);
            recorder.setVideoCodec(avutil.AV_CODEC_ID_H264); // Use explicit constant instead of magic number 13
            recorder.setFormat("mp4");
            recorder.setPixelFormat(avutil.AV_PIX_FMT_GRAY8); // Correct 8-bit grayscale format
            recorder.setVideoBitrate(1000000);
            recorder.start();

            for (int i = 0; i < frameCount; i++) {
                // Create a new image buffer for each frame to avoid array out-of-bounds
                byte[] imageData = new byte[width * height];
                // Fill with varying test data: set first i rows to 127, rest to -128
                int rowsToModify = Math.min(i, height);
                for (int row = 0; row < rowsToModify; row++) {
                    int startIdx = row * width;
                    for (int col = 0; col < width; col++) {
                        imageData[startIdx + col] = 127;
                    }
                }
                for (int j = rowsToModify * width; j < imageData.length; j++) {
                    imageData[j] = -128;
                }

                // Record with correct stride (width for 8-bit single-channel)
                recorder.recordImage(width, height, depth, channels, width, avutil.AV_PIX_FMT_GRAY8, ByteBuffer.wrap(imageData));
            }

            recorder.stop();
            recorder.close();
            System.out.println("Video saved successfully!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Handling 2048x2048 16-bit Single-Channel Images

For 16-bit grayscale content, adjust these parameters:

  • Depth: 16
  • Pixel Format: Use avutil.AV_PIX_FMT_GRAY16LE (little-endian) or AV_PIX_FMT_GRAY16BE (big-endian) depending on your short[] data's byte order.
  • Stride: width * 2 (each 16-bit pixel takes 2 bytes)
  • Buffer: Wrap your short[] into a properly formatted byte buffer:
    short[] sixteenBitImage = new short[width * height];
    // Populate your 16-bit data here
    ByteBuffer byteBuffer = ByteBuffer.allocate(width * height * 2);
    byteBuffer.asShortBuffer().put(sixteenBitImage);
    recorder.recordImage(width, height, 16, 1, width * 2, avutil.AV_PIX_FMT_GRAY16LE, byteBuffer);
    

Bitrate Selection for 2048x2048 16-bit Video

Bitrate depends on content complexity and desired quality:

  • Low-motion/static content (e.g., medical scans): 5–10 Mbps is sufficient, balancing file size and quality without noticeable artifacts.
  • High-motion content: 15–30 Mbps ensures sharp details are preserved.
  • Better alternative: Use CRF (Constant Rate Factor)
    Instead of fixed bitrate, use CRF to let FFmpeg automatically adjust bitrate for consistent quality. A CRF value of 23 is the default (good balance); lower values (18–22) mean higher quality/larger files, while higher values (24–28) mean smaller files with minor quality loss. Set it like this:
    recorder.setVideoOption("crf", "23");
    // You can remove setVideoBitrate if using CRF
    

内容的提问来源于stack exchange,提问作者Learning from masters

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:06:36