DirectShow: рендеринг для YV12 - PullRequest
0 голосов
/ 23 октября 2018

Я пытаюсь понять, как работает рендеринг для формата YV12.Например, я взял простой образец.Смотрите этот график: enter image description here

Веб-камера создает кадры размером 640x480 в RGB24 или MJPEG.После этого LAV-декодер преобразует кадры в YV12 и отправляет их в DS-рендерер (EVR или VMR9).

Декодер изменяет ширину кадра (шаг) 640 на 1024. Следовательно, выходной размер кадра будет1,5 *1024* 640 = 737280.Нормальный размер для YV12 составляет 1,5 * 640 * 480 = 460800.Я знаю, что шаг может превышать ширину реального кадра (https://docs.microsoft.com/en-us/windows/desktop/medfound/image-stride). Мой первый вопрос - почему средство визуализации выбрало это значение (1024), а не другое? Могу ли я получить его программно?

КогдаЯ заменяю LAV-декодер своим фильтром для преобразования RGB24 / YV12 (https://gist.github.com/thedeemon/8052fb98f8ba154510d7),, средство визуализации показывает мне смещенное изображение, хотя все параметры такие же, как для первого графика:

enter image description here

Почему? Я заметил, что VIDEOINFOHEADER2 имеет установленный флаг чересстрочной развертки dwInterlaceFlags. Поэтому мой следующий вопрос: нужно ли добавлять чередование в мой фильтр для нормальной работы рендерера?

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

Мое решение:

Я должен скопировать правый кадр YV12 в видеобуфер тремя его поверхностями: Y = 4x4, U = 1x2, V = 1x2.Вот код для размера кадра 640x480:

CVideoGrabberFilter::Transform(IMediaSample *pIn, IMediaSample *pOut)
{

BYTE* pSrcBuf = 0;
pIn->GetPointer(&pSrcBuf);
BYTE* pDstBuf = 0;
pOut->GetPointer(&pDstBuf);
SIZE size;
size.cx = 640;
size.cy = 480;
int nLen = pOut->GetActualDataLength();

BYTE* pDstTmp = new BYTE[nLen];
YV12ConverterFromRGB24(pSrcBufEnd, pDstTmp, size.cx, size.cy);
BYTE* pDst = pDstTmp;
int stride = 1024; //the real video stride for 640x480. For other  resolutions you need to use pOut->GetMediaType() for the stride defining.
//Y 
for (int y = 0; y < size.cy; ++y)
{
    memcpy(pDstBuf, pDst, size.cx);
    pDst += size.cx;
    pDstBuf += stride;
}
stride /= 2;
size.cy /= 2;
size.cx /= 2;
//U and V 
for (int y = 0; y < size.cy; y++ )
{ 
    memcpy(pDstBuf, pDst, size.cx );
    pDst += size.cx;
    pDstBuf += stride;

    memcpy(pDstBuf, pDst, size.cx);
    pDst += size.cx;
    pDstBuf += stride;
}
delete[] pDstTmp;
}
0 голосов
/ 23 октября 2018

Мой первый вопрос - почему средство визуализации выбрало это значение (1024), а не другое?Могу ли я получить это программно?

Видео рендерер использует Direct3D текстуру в качестве носителя для изображения.Когда текстура отображается в системную память для обеспечения доступа ЦП к записи, такой расширенный шаг может быть применен из-за особенностей реализации видеооборудования.Вы получаете значение 1024 посредством согласования динамического типа мультимедиа, как описано в Обработка изменений формата с помощью Video Renderer .

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

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

Когда я заменяю LAV-декодер своим фильтром для преобразования RGB24 / YV12, рендерер показывает мне смещенное изображение, хотя все параметры такие же, как и для первого графика ... Почему?

Ваш фильтр не обрабатывает правильное обновление шага.

... Я заметил, что VIDEOINFOHEADER2 имеет установленный флаг чередования dwInterlaceFlags.Поэтому мой следующий вопрос: мне нужно добавить чересстрочную развертку в мой фильтр для нормальной работы рендерера?

У вас нет чересстрочного видео здесь.Проблема не связана с чересстрочным видео.

...