Извлечение кадров из видео в режиме реального времени

Я делаю приложение для записи видео. Мне бы хотелось, чтобы при записи приложения видео каждый кадр также сохранялся в arraylist из значений RGB, чтобы извлечь из него определенную информацию. Я знаю, что два процесса (видеозапись и извлечение кадров) являются асинхронными, но это не проблема: процесс извлечения может завершиться после видеозаписи.

Может кто-нибудь сказать мне, как я могу извлечь кадры из видео?

Большое спасибо.

3 ответа

С помощью объекта камеры вы можете переопределить функцию setPreviewCallback. из этой функции вы получите массив байтовых данных. Что вы можете преобразовать в растровое изображение, или вы можете сохранить их в массиве массива.

Предполагая, что вы продолжаете SurfaceView и реализуете SurfaceHolder.Callback

Код выглядит так:

mCamera.setPreviewCallback(new PreviewCallback() {
 public void onPreviewFrame(byte[] data, Camera camera) {
 //do some operations using data
 }
});

Если вы хотите получить значение RGB, вы можете использовать эту функцию,

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. Он использует MediaCodec, доступный по API 16+. Если вам нужно работать на более старых устройствах, лучшим вариантом является ffmpeg.

Для данных RGB требуется 3 байта на пиксель. 10 секунд видео 720p при 30 кадрах в секунду потребуют 1280 * 720 * 3 * 30 * 10 = 791 мегабайт. Если ваши видеокадры не являются достаточно маленькими, удержание большого числа из них может быть непрактичным (или возможным).


Мне кажется, вы хотите получить изображение во время видеозаписи.

В этом случае вам нужно будет заглянуть в Создать приложение для вашей камеры. На этой странице описано, как записывать видео с использованием класса камеры Android.

Затем вы можете получить изображения yuv через Обратный вызов предварительного просмотра камеры.

licensed under cc by-sa 3.0 with attribution.