在透明的 JWindow 中播放 ARGB .mov 视频

Posted

技术标签:

【中文标题】在透明的 JWindow 中播放 ARGB .mov 视频【英文标题】:Play an ARGB .mov video in a transparent JWindow 【发布时间】:2021-04-10 06:22:29 【问题描述】:

我正在尝试为我的程序编写启动画面,因为它需要很长时间才能打开。

我设法用图像做到了,但我不知道如何用 ARGB 视频做到这一点。

首先,我尝试了一张图片: (在 JWindow 扩展类上)

JLabel l = new JLabel("");
JPanel p = new JPanel();

setSize(1024, 1024);
setBackground(new Color(0, 0, 0, 0));
setLocationRelativeTo(null);

l.setBounds(0, 0, 1024, 1024);
l.setIcon(new ImageIcon(ImageIO.read(getClass().getResourceAsStream("/" + splashName))));

p.setBounds(0, 0, 1024, 1024);
p.setBackground(new Color(0, 0, 0, 0));
p.add(l);

add(p);
setVisible(true);

原始启动图像: example.png

我执行代码时的屏幕截图: screenshot.png

效果很好。

之后,我使用 After Effects 制作了启动画面动画(相同的启动画面旋转)。是的,我肯定以 RGB + Alpha 格式导出了 .mov 视频,而 ffmpeg 告诉我同样的结果。

所以,我尝试使用 FFmpegFrameGrabber.grabImage(); 使用 JavaCV 库,但结果很奇怪。 (我知道代码不是很好,但我首先想让它工作)

JLabel l = new JLabel("");
JPanel p = new JPanel();

grabber = new FFmpegFrameGrabber(splashPath);

setSize(1024, 1024);
setLocationRelativeTo(null);

p.setBackground(new Color(0, 0, 0, 0));
p.setBounds(0, 0, 1024, 1024);

l.setIcon(new ImageIcon(ImageIO.read(getClass().getResourceAsStream("/icon4.png"))));
l.setBounds(0, 0, 1024, 1024);

p.add(l);

add(p);

grabber.start();

Frame frame;
BufferedImage bi = new BufferedImage(grabber.getImageWidth(), grabber.getImageHeight(), BufferedImage.TYPE_INT_ARGB);

while((frame = grabber.grabImage()) != null) 
    bi = new BufferedImage(grabber.getImageWidth(), grabber.getImageHeight(), BufferedImage.TYPE_INT_ARGB);
    Java2DFrameConverter.copy(frame, bi);
    showFrame(bi);
    Thread.sleep(16);

grabber.stop();




private void showFrame(BufferedImage frame) 
    p.removeAll();
    l.setIcon(new ImageIcon(frame));
    p.add(l);
    repaint();

我执行代码时的屏幕截图:screenshot2.png

从屏幕截图中,我们可以看到视频的大小已调整(宽度变小),并且出现了一些奇怪的透明蓝色线条,而其他颜色应该是这样的。

所以我的问题是:

    我该如何解决? 是 JavaCV 的问题吗? 还有其他方法可以在 java 中将透明视频播放为闪屏吗?

【问题讨论】:

javaCV 是一些人的无证垃圾 - 所以去想一想。当然,您知道电影是一系列图像。但是如果你想在你的 java 程序中播放一部电影,那么有一些......库 - ffmpeg 可以做到! @Marcinator FFmpeg 返回的帧的像素格式可能是 RGBA,而不是 ARGB。尝试通过调用Java2DFrameConverter.copy(frame, bi, 1.0, true, null) 来翻转频道。 @SamuelAudet 我刚试过但没有任何改变:( 它不可能改变什么。它一定是在改变一些东西,而不是正确的东西。您需要对齐 FFmpeg 和 Java2D 的像素格式。我们可以在使用 setPixelFormat() 调用 start() 之前更改 FFmpegFrameGrabber 的值,以及此处列表中的值之一:github.com/bytedeco/javacpp-presets/blob/master/ffmpeg/src/gen/… @SamuelAudet 好的,谢谢我通过使用 AV_PIX_FMT_ARGB 调用 setPixelFormat 并在不翻转通道的情况下恢复 .copy 方法来解决。再来一次,非常感谢!!!我对堆栈溢出很陌生,所以我应该创建一个解决我的问题的答案吗? 【参考方案1】:

感谢 Samuel Audet,我发现 FFmpeg 返回的帧的像素格式是 RGBA,而不是 ARGB。

我们可以通过在 start() 之前调用 setPixelFormat() 轻松更改 FFMpegFrameGrabber 的像素格式。

这里有每个可用像素格式的列表: list

就我而言,这是最终的解决方案:

grabber = new FFmpegFrameGrabber(splashPath);
grabber.setPixelFormat(avutil.AV_PIX_FMT_ARGB);
grabber.start();

【讨论】:

以上是关于在透明的 JWindow 中播放 ARGB .mov 视频的主要内容,如果未能解决你的问题,请参考以下文章

css 对 argb 的不透明度

ARGB与RGBRGBA的区别

透明 ARGB 十六进制值

如何从 ARGB_8888 位图绘制位图

如何设置一个获取灰度图像并输出 ARGB 的图层,使其中一种灰度颜色透明?

如何设置Android中控件的颜色透明度