Создание экземпляра YUVFormat

Я хотел бы создать jmf/fmj YUVFormat экземпляр для динамически создаваемого CaptureDevice используя YUV420. Я не понимаю, какие значения должны быть для strideY, strideUV, offsetY, offsetU и offsetV. Только следующие конструкторы доступны в YUVFormat учебный класс:

1. YUVFormat()
2. YUVFormat(int yuvType)
3. YUVFormat(размер java.awt.Dimension, int maxDataLength, java.lang.Class dataType, float frameRate, int yuvType, int strideY, int strideUV, int offsetY, int offsetU, int offsetV)

Использование #1 или #2 не позволяет мне устанавливать размер, частоту кадров или тип данных после факта; поэтому я не могу их использовать. Использование #3 требует от меня знать пять дополнительных параметров. Я прочитал все следующие сообщения из моего поиска Google, но я все еще не понимаю, какие значения должны быть. Я думаю, что могу смело предположить, что шириной кадра являются strideY и strideUV, но я не уверен на 100%.

Javadoc: http://fmj-sf.net/doc/fmj/javax/media/format/YUVFormat.html

MediaWiki: http://wiki.multimedia.cx/index.php?title=PIX_FMT_YUV420P

FourCC: http://www.fourcc.org/yuv.php

Вот мой код до сих пор:

int strideY = ширина, strideUV = ширина / 2;
int offsetY = 0, offsetU = 0, offsetV = 0;
YUVFormat yuv = новый YUVFormat(новое измерение (ширина, высота), Format.NOT_SPECIFIED, Format.byteArray, frameRate, YUVFormat.YUV_420, strideY, strideUV, offsetY, offsetU, offsetV);

2 ответа

Решение

В прошлый раз, когда я использовал эти классы, у меня были проблемы с памятью изнутри.

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

Я бы посоветовал обрабатывать байты в массивах, если это возможно.

Подумайте о данных RGBA. Каждое слово в памяти составляет 4 пикселя. [RGBA][RGBA]... И, как правило, сначала записывается внизу слева, а заканчивается справа вверху. Размер данных легко узнать, а конкретные пиксели легко манипулировать.

YUV - это плоский или полуплоскостной формат с 12 битами на пиксель в среднем, а не 32 битами. Это достигается наличием 8 битов Y и 8 битов U и V с двойным размером U и V. 8 битов U и V покрывают 4 пикселя плоскости Y.

Таким образом, если размер изображения составляет 320 на 240, первые 320 * 240 байт будут данными Y-плоскости.

Следующие байты в памяти - это чередующиеся линии U/V как полуплоскостные или все планарные с сначала всеми U, затем всеми V данными.

Шаг Y - это ширина. Шаг U/V составляет половину ширины. Смещение Y - это количество байтов между рядами / шагами пикселей. Смещение U - это количество байтов между рядами / шагами пикселей. Смещение V - это количество байтов между рядами / шагами пикселей.

У них также есть "базовый адрес", который не представлен в Java. Адрес памяти данных первого пикселя Y.

В системах, которые могут выделить как минимум 32-битные слова памяти, изображения, использующие 12-битную глубину цвета или нечетные размеры пикселей, могут заставить хост-систему вести себя по-разному в отношении того, где данные пикселей находятся в адресной памяти.

например, запишите все упакованные данные Y, они будут иметь нулевое смещение. Затем запишите одну горизонтальную линию данных U. Затем запишите одну горизонтальную линию данных V. Затем запишите одну горизонтальную линию данных U. Затем запишите одну горизонтальную линию данных V.

Шаг U и V - половина шага Y.

В Java вы должны иметь возможность использовать нулевые смещения, записывая пиксельные данные без пропусков между U и V данными.

Другой формат yuv записывает все U, а затем все данные V в виде целых блоков.

Смещение соответствует количеству байтов между одиночными строками Y/U/V.

Базовый адрес будет соответствовать начальному адресу самолетов U/V.

данные начинаются "здесь (основа)", это "широкий (шаг)" со следующей строкой, начинающейся там (смещение)

С Java базовый адрес, скорее всего, дан.

Вероятно, не ответил на вопрос LOL

{
    unsigned int planeSize;
    unsigned int halfWidth;

    unsigned char * yplane;
    unsigned char * uplane;
    unsigned char * vplane;
    const unsigned char * rgbIndex;

    int x, y;
    unsigned char * yline;
    unsigned char * uline;
    unsigned char * vline;

    planeSize = srcFrameWidth * srcFrameHeight;
    halfWidth = srcFrameWidth >> 1;

    // get pointers to the data
    yplane = yuv;
    uplane = yuv + planeSize;
    vplane = yuv + planeSize + (planeSize >> 2);
    rgbIndex = rgb;

        for (y = 0; y < srcFrameHeight; y++)
        {
        yline = yplane + (y * srcFrameWidth);
        uline = uplane + ((y >> 1) * halfWidth);
        vline = vplane + ((y >> 1) * halfWidth);

        if (flip)
        rgbIndex = rgb + (srcFrameWidth*(srcFrameHeight-1-y)*rgbIncrement);

            for (x = 0; x < (int) srcFrameWidth; x+=2)
            {
                rgbtoyuv(rgbIndex[0], rgbIndex[1], rgbIndex[2], *yline, *uline, *vline);
                rgbIndex += rgbIncrement;
                yline++;
                rgbtoyuv(rgbIndex[0], rgbIndex[1], rgbIndex[2], *yline, *uline, *vline);
                rgbIndex += rgbIncrement;
                yline++;
                uline++;
                vline++;
}
}
}

В Яве..

public static byte[] YV12toYUV420Planar(byte[] input, byte[] output, int width, int height) {
    final int frameSize = width * height;
    final int qFrameSize = frameSize/4;

    System.arraycopy(input, 0, output, 0, frameSize); // Y
    System.arraycopy(input, frameSize, output, frameSize + qFrameSize, qFrameSize); // Cr (V)
    System.arraycopy(input, frameSize + qFrameSize, output, frameSize, qFrameSize); // Cb (U)

    return output;
}

Шаг и смещение зависят от структуры памяти кадра, размеров видеокадра и возможного заполнения.

  • В общем случае шаг ( объясненный здесь) - это количество байтов, которое необходимо добавить к указателю для перехода от одной плоской линии к следующей.
  • Смещение - это количество байтов, которое нужно добавить для перемещения от начала кадра к определенной плоскости (Y, U или V).
  • См. Эту статью Microsoft, объясняющую различные структуры памяти YUV Frame.
  • Также см. Этот источник Android, где шаги и смещения рассчитываются в зависимости от FOURCC (только для поддерживаемых форматов Android).
Другие вопросы по тегам