logo
Литература_1 / photon_old

Видеоверлей

Видеоверлейная пересчётная схема (video overlay scaler) – это аппаратная возможность, позволяющая на прямоугольной области видимого экрана менять масштабированные версии отличающегося рисунка. Предварительно отмасштабированные видеокадры обычно размещены во внеэкранной памяти, и они выбираются из памяти и накладываются сверху на экранный образ рабочего стола в реальном времени с помощью видеоверлейной пересчётной схемы.

Для контроля за тем, какая часть видеокадра видима, используется хромоключ. Обычно приложение отбирает цвет, являющийся цветом хроматического ключа, и рисует прямоугольник этого цвета там, где появляется видеосодержание. Когда другое окно приложения размещается сверху на приложении, воспроизводящем видео, окрашенный в хроматический цвет прямоугольник затеняется. Поскольку видеоаппаратное обеспечение запрограммировано на отображение видеосодержания экрана только тогда, когда рисуется цвет хромоключа, видео не демонстрируется, пока прямоугольник цвета хромоключа затемнён.

Следующие функции и типы данных имеют дело с видеоверлеем:

PgConfigScalerChannel()

Конфигурирование канала пересчётной схемы видеоверлея

PgCreateVideoChannel()

Создание канала для видеопотока

PgDestroyVideoChannel()

Освобождение ресурса, связанного с видеоканалом

PgGetOverlayChromaColor()

Возвращает цвет, используемый для оверлейных операций хромоключа

PgGetScalerCapabilities()

Получает характеристики пересчётной схемы видеоверлея

PgNextVideoFrame()

Получает индекс следующего видеобуфера для заполнения

PgScalerCaps_t()

Структура данных, описывающая характеристики пересчётной схемы видеоверлея

PgScalerProps_t()

Структура данных, описывающая свойства персчётной схемы видеоверлея

PgVideoChannel_t()

Структура данных, описывающая канал видеоверлея

          1. Пример

#include <stdio.h>

#include <Ph.h>

#define SRC_WIDTH 100

#define SRC_HEIGHT 100

#define DATA_FORMAT Pg_VIDEO_FORMAT_YV12

unsigned char *ybuf0, *ybuf1;

unsigned char *ubuf0, *ubuf1;

unsigned char *vbuf0, *vbuf1;

void grab_ptrs(PgVideoChannel_t *channel) {

/* Буферы перемещались, получить указатели снова */

ybuf0 = PdGetOffscreenContextPtr(channel->yplane1);

ybuf1 = PdGetOffscreenContextPtr(channel->yplane2);

ubuf0 = PdGetOffscreenContextPtr(channel->uplane1);

ubuf1 = PdGetOffscreenContextPtr(channel->uplane2);

vbuf0 = PdGetOffscreenContextPtr(channel->vplane1);

vbuf1 = PdGetOffscreenContextPtr(channel->vplane2);

if (channel->yplane1) fprintf(stderr, "ybuf0: %x, stride %d\n", ybuf0, channel->yplane1->pitch);

if (channel->uplane1) fprintf(stderr, "ubuf0: %x, stride %d\n", ubuf0, channel->uplane1->pitch);

if (channel->vplane1) fprintf(stderr, "vbuf0: %x, stride %d\n", vbuf0, channel->vplane1->pitch);

if (channel->yplane2) fprintf(stderr, "ybuf1: %x, stride %d\n", ybuf1, channel->yplane2->pitch);

if (channel->uplane2) fprintf(stderr, "ubuf1: %x, stride %d\n", ubuf1, channel->uplane2->pitch);

if (channel->vplane2) fprintf(stderr, "vbuf1: %x, stride %d\n", vbuf1, channel->vplane2->pitch);

}

void overlay_example() {

PgVideoChannel_t *channel;

PgScalerCaps_t vcaps;

PgScalerProps_t props;

unsigned char *ptr;

unsigned short *ptr16;

int i = 0, j, k, index;

int color;

PhDrawContext_t *old;

int rc;

if ((channel = PgCreateVideoChannel(Pg_VIDEO_CHANNEL_SCALER, 0)) = = NULL) {

perror("PgCreateVideoChannel");

exit(1);

}

/* Проход по доступным форматом в поисках интересующего */

vcaps.size = sizeof (vcaps);

while (PgGetScalerCapabilities(channel, i++, &vcaps) == 0) {

if (vcaps.format == DATA_FORMAT) break;

vcaps.size = sizeof (vcaps);

}

if (vcaps.format != DATA_FORMAT) {

fprintf(stderr, "Формат не поддерживается?\n");

exit(1);

}

props.size = sizeof (props);

props.format = DATA_FORMAT;

props.viewport.ul.x = 20;

props.viewport.ul.y = 20;

props.viewport.lr.x = 600;

props.viewport.lr.y = 440;

props.src_dim.w = SRC_WIDTH;

props.src_dim.h = SRC_HEIGHT;

props.flags =

Pg_SCALER_PROP_SCALER_ENABLE |

Pg_SCALER_PROP_DOUBLE_BUFFER |

Pg_SCALER_PROP_DISABLE_FILTERING;

if (PgConfigScalerChannel(channel, &props) == -1) {

fprintf(stderr, "Не удалось сконфигурировать канал\n");

exit(1);

}

grab_ptrs(channel);

for (i = 0; i < 100; i++) {

index = PgNextVideoFrame(channel);

delay(50);

ptr = (void *)(index ? ybuf1 : ybuf0);

color = rand() & 0xff;

for (k = 0; k < props.src_dim.h; k++) {

memset(ptr, color, channel->yplane1->pitch);

ptr += channel->yplane1->pitch;

}

}

props.flags &= ~Pg_SCALER_PROP_DISABLE_FILTERING;

switch (PgConfigScalerChannel(channel, &props)) {

case -1:

fprintf(stderr, " Не удалось сконфигурировать канал \n");

exit(1);

break;

case 1:

grab_ptrs(channel);

break;

case 0:

default:

break;

}

fprintf(stderr, "\"TV показ\" эффект\n");

for (i = 0; i < 1000; i++) {

index = PgNextVideoFrame(channel);

ptr = (void *)(index ? ybuf1 : ybuf0);

for (k = 0; k < props.src_dim.h; k++) {

for (j = 0; j < channel->yplane1->pitch; j++) *(ptr + j) = rand() & 0xff;

ptr = (void *)((char *)ptr + channel->yplane1->pitch);

}

/* Установка хроматичности для монохромности в нейтральное */

ptr = ubuf0;

for (i = 0; i < props.src_dim.h; i++) {

memset(ptr, 128, props.src_dim.w / 2);

ptr += channel->uplane1->pitch;

}

ptr = vbuf0;

for (i = 0; i < props.src_dim.h; i++) {

memset(ptr, 128, props.src_dim.w / 2);

ptr += channel->vplane1->pitch;

}

if (rand() % 200 == 23) {

props.viewport.ul.x = rand() % 400;

props.viewport.ul.y = rand() % 300;

props.viewport.lr.x = props.viewport.ul.x + SRC_WIDTH + rand() % 200;

props.viewport.lr.y = props.viewport.ul.y + SRC_HEIGHT + rand() % 200;

if (PgConfigScalerChannel(channel, &props) == 1) grab_ptrs(channel);

}

}

/*

* В действительности это не нужно, поскольку видеоресурсы будут освобождены

* автоматически при завершении приложения

*/

PgDestroyVideoChannel(channel);

}

int main(int argc, char *argv[]) {

PhAttach(NULL, NULL);

overlay_example();

fprintf(stderr, "Нормальное завершение\n");

}

    1. Слои

Некоторые графические адаптеры позволяют вам накладывать множество «экранов» на один. Каждый такой накладываемый экран называется «слой».

Слои могут использоваться для совмещения независимых отображаемых элементов. Поскольку такое наложение осуществляется аппаратурой графического адаптера, оно может оказаться более эффективным, чем рисование всех необходимых элементов на одном слое. Так например, быстрый навигационный интерфейс может быть реализован как «прокручивающаяся» карта, отображаемая на одном слое – в «подложке», и всплывающие элементы графического интерфейса пользователя, такие как меню или Web-браузер – на другом слое.

Возможности отображения слоев отличаются в зависимости от графического контроллера и драйвера. Некоторые графические контроллеры не поддерживают слои. Различные слои на одном и том же дисплее могут иметь разные возможности. Следует использовать функцию PgGetLayerCaps() для того, чтобы определить, существует ли слой и каковы его возможности.

Слои нумеруются для каждого адаптера в отдельности начиная с нуля по возрастающей. Нумерация начинается со слоя, находящегося ниже всех остальных на данном адаптере.

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

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

Yandex.RTB R-A-252273-3
Yandex.RTB R-A-252273-4