【问题标题】:VideoSurfaceView - render to fileVideoSurfaceView - 渲染到文件
【发布时间】:2013-10-31 09:50:54
【问题描述】:

我正在使用VideoSurfaceView 来渲染过滤后的视频。我正在根据我的需要购买更改片段着色器。现在我想在更改为相同格式的文件(例如 mp4 - h264)后保存/渲染视频,但找不到如何做到这一点。

PS - 将纹理保存为位图并将位图保存到文件很容易,但我可以找到如何处理视频..

这里有专家吗?

【问题讨论】:

  • 我没听懂?您是要一帧一帧地保存视频,还是将整个视频保存到一个新文件中?
  • 整个视频到一个文件,如果我可以在后台使用 openGl 来处理我的片段着色器的视频,但 openGl 不能在后台播放,那就太好了。正如我现在所看到的,我需要其他知道将视频提取到帧的库(不是 FFmpeg 龙)
  • 我回答了您的问题,希望这将帮助您进一步了解您正在尝试做的事情。

标签: android opengl-es surfaceview glsurfaceview


【解决方案1】:

正如您在 cmets 中已经发现并说的那样,OpenGL 不能将多个帧导出为视频。

虽然如果您只是想过滤/处理视频的每一帧,那么您根本不需要 OpenGL,也不需要片段着色器,您可以简单地自己循环遍历所有像素。

现在假设您一次处理一帧视频,每一帧都是一个BufferedImage您当然可以使用任何您想要或提供的内容,只要您可以选择获取和设置像素。

我只是为您提供一种计算和应用过滤器的方法,您必须自己对视频文件进行解码和编码。

但回到BufferedImage,首先我们要获取BufferedImage 中的所有像素,我们使用以下方法来实现。

BufferedImage bi = ...; // Here you would get a frame from the video

int width = bi.getWidth();
int height = bi.getHeight();

int[] pixels = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData();

请注意,根据图像的类型,如果图像包含透明度,DataBuffer 可能会在 DataBufferIntDataBufferByte 之间变化,等等。您可以阅读不同的DataBuffers 在 Oracle 文档中,click here

现在只需循环遍历图像中的像素,我们就可以应用和创建任何类型的效果和过滤。

假设我们要创建一个grayscale 效果,也称为black-and-white 效果,您可以通过以下方式进行。

for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
        final int index = x + y * width;

        final int pixel = pixels[index];

        final int alpha = (pixel >> 24) & 0xFF;
        final int red = (pixel >> 16) & 0xFF;
        final int green = (pixel >> 8) & 0xFF;
        final int blue = pixel & 0xFF;

        final int gray = (red + green + blue) / 3;

        pixels[index] = alpha << 24 | gray << 16 | gray << 8 | gray;
    }
}

现在您可以简单地再次保存图像,或做任何您想做的事情。虽然你也可以使用和绘制BufferedImage,因为BufferedImage提供的像素数组当然也会改变BufferedImage

重要如果要执行模糊效果,则在计算每个像素后将其存储到另一个数组中,因为执行模糊效果需要周围的像素。因此,如果在计算所有像素时替换旧的一次,某些像素将使用计算值而不是实际值。

上面的代码当然也适用于图片。

额外

如果您想获取存储在单个 int 中的 RGBA 值,则可以执行以下操作。

int pixel = 0xFFFF8040; // This is a random testing value

int alpha = (pixel >> 24) & 0xFF; // Would equal 255 using the testing value
int red = (pixel >> 16) & 0xFF; // ... 255 ...
int green = (pixel >> 8) & 0xFF; // ... 128 ...
int blue = pixel & 0xFF; // ... 64 ...

如果您有 RGBA 值并希望将它们组合成一个 int,那么您可以执行以下操作。

int alpha = 255;
int red = 255;
int green = 128;
int blue = 64;

int pixel = alpha << 24 | red << 16 | green << 8 | blue;

如果您只有 RGB 值,那么您就可以,red &lt;&lt; 16 | green &lt;&lt; 8 | blue255 &lt;&lt; 24 | red &lt;&lt; 16 | green &lt;&lt; 8 | blue

【讨论】:

  • 嗨,我不认为你的方法是正确的方法。首先 - 每个视频都经过编码,例如。带有 h264 的 MP4 容器,以及由音频/视频/元数据框构建的每个视频。您不能只获取像素并从中创建图像。您需要使用解码器对它们进行解码,通常是 FFmpeg 或 jCodec 等第三方库。其次 - BufferedImage 不是 Android SDK 的一部分
  • @powerX 正如我在问题中指出的那样,“假设”这是一个BufferedImage,我们在解码视频时得到回报/创建。您必须自己进行解码和编码(除非您找到可以执行此操作的库),我只是为您提供了计算和应用过滤器的方法。
  • 你能解释一下这行吗:BufferedImage bi = ...; // 这里是从视频流中获取的,你有没有想过获取视频的所有字节并将它们放入 BufferedImage 中?
  • @powerX 基本上你会从视频中得到一帧(当然是解码视频等),但如果你可以简单地解码视频并将帧作为像素数组得到会更好,因为这样您就不必使用BufferedImage
  • 它可能适用于一帧(还没有尝试过)但是我怎样才能为视频的所有帧做到这一点?
猜你喜欢
  • 1970-01-01
  • 2014-10-06
  • 2011-08-26
  • 2012-07-23
  • 1970-01-01
  • 1970-01-01
  • 2014-03-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多