如何使用Java Media Framework(JMF)将BufferedImage数组生成视频
使用JMF将BufferedImage数组导出为视频的实现方案
首先确认项目已正确导入JMF依赖,且运行环境已配置JMF的native库(部分编码格式需要系统层面的编码支持)。
1. 配置可自定义的输出参数
首先定义你需要的分辨率、帧率、输出格式等可配置项,示例配置如下:
// 可自定义配置项 int targetWidth = 1280; // 输出视频宽度 int targetHeight = 720; // 输出视频高度 float frameRate = 30f; // 输出帧率 File outputFile = new File("output.avi"); // 输出文件路径,格式可根据需求修改为mov等JMF支持的格式
如果你的BufferedImage分辨率和目标分辨率不一致,需要先做缩放处理,可通过Graphics2D绘制缩放后的图像:
public BufferedImage resizeImage(BufferedImage source, int targetWidth, int targetHeight) { BufferedImage resized = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = resized.createGraphics(); g2d.drawImage(source, 0, 0, targetWidth, targetHeight, null); g2d.dispose(); return resized; }
2. 构造JMF可识别的视频格式
创建对应参数的VideoFormat对象,匹配你的输出配置:
VideoFormat videoFormat = new RGBFormat( new Dimension(targetWidth, targetHeight), // 分辨率 Format.NOT_SPECIFIED, byte[].class, frameRate, 24, // 位深 0xff0000, 0xff00, 0xff, // RGB掩码 1, // 像素步长 Format.NOT_SPECIFIED, Format.TRUE, Format.NOT_SPECIFIED );
3. 初始化JMF处理器与输出链路
通过JMF的Processor和DataSink创建输出链路,绑定输出文件:
Processor processor = Manager.createProcessor(new Format[]{videoFormat}); processor.configure(); // 等待处理器配置完成 while (processor.getState() != Processor.Configured) { Thread.sleep(10); } // 设置输出内容为纯视频 processor.setContentDescriptor(new FileTypeDescriptor(FileTypeDescriptor.MSVIDEO)); // 配置轨道格式 TrackControl[] trackControls = processor.getTrackControls(); if (trackControls != null && trackControls.length > 0) { trackControls[0].setFormat(videoFormat); } processor.realize(); while (processor.getState() != Processor.Realized) { Thread.sleep(10); } // 创建输出数据汇 DataSink dataSink = Manager.createDataSink(processor.getDataOutput(), new MediaLocator(outputFile.toURI().toURL())); dataSink.open(); processor.start(); dataSink.start();
4. 逐帧写入BufferedImage数组
遍历你存储的BufferedImage数组,将每个图像转换为JMF的Buffer对象写入处理器:
// 假设你的BufferedImage数组为frameArray for (BufferedImage frame : frameArray) { // 先缩放到目标分辨率 BufferedImage resizedFrame = resizeImage(frame, targetWidth, targetHeight); // 提取图像RGB数据 int[] rgbData = resizedFrame.getRGB(0, 0, targetWidth, targetHeight, null, 0, targetWidth); byte[] bufferData = new byte[targetWidth * targetHeight * 3]; int index = 0; for (int rgb : rgbData) { bufferData[index++] = (byte) (rgb >> 16); // R bufferData[index++] = (byte) (rgb >> 8); // G bufferData[index++] = (byte) rgb; // B } // 构造JMF Buffer Buffer buffer = new Buffer(); buffer.setData(bufferData); buffer.setFormat(videoFormat); buffer.setLength(bufferData.length); buffer.setOffset(0); // 按帧间隔计算时间戳,保证播放速度均匀,单位为微秒 buffer.setTimeStamp((long) (frameIndex * (1000000 / frameRate))); // 写入处理器 processor.getInputTrack(0).writeBuffer(buffer); } // 写入完成后关闭资源 processor.stop(); dataSink.stop(); dataSink.close(); processor.close();
注意事项
- 若需要更换输出格式,只需修改
FileTypeDescriptor的参数,JMF原生支持MSVIDEO(AVI)、QUICKTIME(MOV)、MPEG等格式,选择对应枚举值即可 - 若出现编码不支持的报错,可安装JMF的可选编码包扩展支持的格式范围
- JMF本身对高分辨率视频支持有限,建议分辨率设置在1920*1080以内避免编码错误
- 上述代码省略了异常捕获逻辑,实际使用时需要对JMF相关操作捕获
IOException、NoProcessorException、InterruptedException等受检异常
内容的提问来源于stack exchange,提问作者Armaan
相关产品推荐
相关产品推荐

