如何把rgba图片像素数组传递给ffmpeg?
我有一张1920x1080像素的图片,内存中保存的该图片的像素数组,rgba格式,四个字节为一个像素,也就是一个1920x1080x4的字节数组.
我想把这个数组传递给ffmpeg,并希望ffmpeg正确解析数据格式和图片宽高,我应该如何描述数据格式或者像素格式。
我使用的pipe在java端做的数据的输入和输出,下边是我把像素数组转mjpeg后,使用ffmpeg生成avi格式视频的命令,可以正确生成视频.
ProcessBuilder extractBuilder = new ProcessBuilder(
ffmpeg
, "-f", "image2pipe"
, "-y", "-framerate", "5.0"
, "-codec", "mjpeg"
// , "-codec", "bmp"
, "-i", "pipe:0"
, "-y"
, "-loglevel"
, "quiet"
, "-f", "avi"
, "pipe:1"
);
.
.
省略一些中间过程
.
OutputStream ffmpegInput = process.getOutputStream();
BufferedImage img = "像素数组转成的img";
ImageIO.write(image, "jpg", ffmpegInput);
使用jpg虽然可以,但是ImageIO.write一次耗时30毫秒左右,所有我想直接把原始的像素数组传递给ffmpeg,但是不知道如何让ffmpegg知道数据格式以及一张图片的宽和高.
回答:
今天用chatgpt,突然想到以前问过的问题,结果真的给我了更好的方案。
把原来的"-f", "image2pipe"
改成
"-f", "rawvideo""-video_size", " 1920x1080"
"-pixel_format", "rgb24"
然后输入就是一个个1920x1080x3的字节数组
public class ImageToVideo2 { static String ffmpeg = "D:\\tools\\ffmpeg-n5.0-latest-win64-gpl-5.0\\bin\\ffmpeg.exe";
public static void main(String[] args) {
ProcessBuilder extractBuilder =
new ProcessBuilder(
ffmpeg
, "-f", "rawvideo"
, "-video_size", " 1920x1080"
, "-pixel_format", "rgb24"
// , "-framerate", "30.0"
, "-vsync", "vfr"
, "-i", "pipe:0"
, "-loglevel"
, "quiet"
, "-c:v", "libx264"
// ,"-pix_fmt", "yuv420p"
// ,"-preset" ,"ultrafast"
// ,"-pix_fmt","bgr24"
, "-y"
, "output.mkv"
);
System.out.println(extractBuilder.command().toString());
extractBuilder.redirectErrorStream(true);
extractBuilder.redirectInput(ProcessBuilder.Redirect.PIPE);
try {
Process process = extractBuilder.start();
OutputStream ffmpegInput = process.getOutputStream();
RobotPeer robotPeer = getRobotPeer();
BlockingDeque<byte[]> blockingDeque = new LinkedBlockingDeque<byte[]>();
AtomicBoolean hashImg = new AtomicBoolean(true);
new Thread(() -> {
while (hashImg.get()) {
try {
byte[] bmpPixels = blockingDeque.take();
ffmpegInput.write(bmpPixels);
} catch (InterruptedException | IOException e) {
throw new RuntimeException(e);
}
}
try {
ffmpegInput.close();
} catch (Exception e) {
}
}).start();
for (int i = 0; i < 30; i++) {
byte[] bmpPixels = screenToBmp(robotPeer);
blockingDeque.add(bmpPixels);
}
hashImg.set(false);
} catch (Exception e) {
e.printStackTrace();
}
}
public static RobotPeer getRobotPeer() {
try {
Robot robot = new Robot();
Field peerField = robot.getClass().getDeclaredField("peer");
peerField.setAccessible(true);
RobotPeer peer = (RobotPeer) peerField.get(robot);
return peer;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static byte[] screenToBmp(RobotPeer peer) {
//这个头中包含了视频是 1920 * 1080 * 3的格式了
Rectangle screenRect = new Rectangle(0, 0, 1920, 1080);
//截图
int[] pixels = peer.getRGBPixels(screenRect);
//解析像素,返回的是bgr格式
int length = screenRect.width * screenRect.height;
byte[] imgBytes = new byte[length * 3];
int byteIndex = 0;
for (int i = 0, pixel = 0; i < length; i++) {
pixel = pixels[i];
imgBytes[byteIndex + 2] = (byte) (pixel);
pixel = pixel >> 8;
imgBytes[byteIndex + 1] = (byte) (pixel);
imgBytes[byteIndex] = (byte) (pixel >> 8);
byteIndex += 3;
}
return imgBytes;
}
}
回答:
你要想通过管道给ffmpeg喂数据,那么必须转成已知的数据流,那么ffmpeg支持的解码器可以用命令ffmpeg -decoders
你必须将数据流转成上述命令列出来的数据类型的任意一种。
另外你用jpg
显然不是一个好的选择,你的原始数据是rgba类型,jpg直接就扔掉了Alpha通道,并且对其他数据做有损压缩处理,当然会慢。如果你想保留原始数据类型,那么你首先应该考虑的是bmp或png数据类型,如果对速度有要求,那么bmp是你唯一的选择,它是无损不压缩的数据类型,理论上会比转换成jpg快。
另外-codec mjpeg
这个参数可以删了,理论上适用于AVI最佳的格式是ffmpeg默认使用的XVID,让他用默认的这个编码即可
以上是 如何把rgba图片像素数组传递给ffmpeg? 的全部内容, 来源链接: utcz.com/p/944888.html