如何把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

回到顶部