我正在开发一个记录视频的应用程序。我希望在录制视频时,每一帧也保存在一个RGB值的数组列表中,以便从中提取特定信息。我知道这两个过程(视频录制和帧提取)是异步的,但这不是问题:提取过程可以在视频录制后完成。
有谁能告诉我如何从视频中提取帧?
非常感谢!
有谁能告诉我如何从视频中提取帧?
非常感谢!
setPreviewCallback
。从那个函数中,您将获得一个字节数组。您可以将其转换为位图或将其保存在数组中。假设您扩展了SurfaceView
并实现了SurfaceHolder.Callback
,mCamera.setPreviewCallback(new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
//do some operations using data
}
});
static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width,
int height) {
final int frameSize = width * height;
for (int j = 0, yp = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++, yp++) {
int y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0)
y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0)
r = 0;
else if (r > 262143)
r = 262143;
if (g < 0)
g = 0;
else if (g > 262143)
g = 262143;
if (b < 0)
b = 0;
else if (b > 262143)
b = 262143;
rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000)
| ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
}
}
}
static public void calculateColor(int[] rgb, int[] color,
int width, int height, int component) {
for (int bin = 0; bin < 256; bin++) {
color[bin] = 0;
} // bin
int start = 0;
int end = width * height;
if (component == 0) // red
{
for (int pix = start; pix < end; pix += 3) {
int pixVal = (rgb[pix] >> 16) & 0xff;
color[pixVal]++;
} // pix
} else if (component == 1) // green
{
for (int pix = start; pix < end; pix += 3) {
int pixVal = (rgb[pix] >> 8) & 0xff;
color[pixVal]++;
} // pix
} else // blue
{
for (int pix = start; pix < end; pix += 3) {
int pixVal = rgb[pix] & 0xff;
color[pixVal]++;
} // pix
}
}
从 .mp4 文件中提取帧的示例代码可以在 bigflake site 上找到。它使用 API 16+ 上可用的 MediaCodec。如果您需要在旧设备上运行,则最好使用 ffmpeg。
RGB 数据每像素需要 3 个字节。30 fps 的 720p 视频的 10 秒将需要 1280*720*3*30*10 = 791 兆字节。除非您的视频帧相当小,否则保留大量帧可能不切实际(或不可能)。