JavaCV FFmpegFrameRecorder存图像为视频报错及码率设置咨询
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:
Incorrect Recorder Initialization
You usednew 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.Invalid
recordImageParameters- You passed
0for the pixel format, which maps toAV_PIX_FMT_NONE— FFmpeg can't interpret your image data with this setting. For 8-bit single-channel grayscale, useAV_PIX_FMT_GRAY8(value8in JavaCV'savutilconstants). - The
strideparameter is set to0. 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 of0forces FFmpeg to guess, which almost always leads to out-of-bounds memory reads.
- You passed
Array Index Out-of-Bounds in Debug Logic
Your loop to modifymyimagehas a fatal error: wheni >= 1,myimage.length * iequals20000 * 1 = 20000, which is exactly the array's length. Trying to accessmyimage[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) orAV_PIX_FMT_GRAY16BE(big-endian) depending on yourshort[]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

