Накладывайте на видео определенную информацию, такую как данные точечной матрицы, прямые линии, прямоугольные рамки, прямоугольные перекрытия, данные изображения и т. д.
Работа с изображениями модуля IPU в основном включает в себя модуль OSD и модуль CSC.
Модуль OSD в основном накладывает на видеокадры линии кадра, прямоугольные перекрытия, изображения и другие данные.
Модуль CSC в основном преобразует входные видеокадры в изображения, поддерживаемые аппаратным обеспечением, такие как формат HSV, NV12, NV21, RGB32 и ARGB.
Информация данных, наложенная на видеоданные, называется областью OSD (Регион). Модуль устройства OSD используется в системе для управления этими областями OSD. Модуль устройства OSD поддерживает создание региона и настройку типа региона через атрибут региона. интерфейс настройки.
(Например, настройка свойств отображения области, координат положения, цвета переднего плана и цвета фона и т. д.) Поддержка действий по разрушению области и т. д.
После завершения создания, регистрации, настройки атрибутов и других операций области OSD, IPU будет единообразно вызываться внутри области OSD для рисования.
Первый — это процесс инициализации:
1) Создайте группу OSD, используйте IMP_OSD_CreateGroup для создания группы OSD;
2) Создайте область OSD, используйте IMP_OSD_CreateRgn для создания области;
3) Зарегистрировать область OSD в группе OSD и зарегистрировать созданную область в группе OSD через IMP_OSD_RegisterRgn
в группе OSD;
4) Установите атрибуты области группы OSD и атрибуты области, а также установите атрибуты области через IMP_OSD_SetRgnAttr,
Установите атрибуты группы областей через IMP_OSD_SetGrpRgnAttr;
5) Установите переключатель отображения функции OSD и включите отображение OSD через IMP_OSD_ShowRgn;
6) Привязываем группу OSD к системе и привязываем модуль OSD к другим модулям через IMP_System_Bind
Конечно.
Далее идет процесс выхода:
1) Отвязать через IMP_System_UnBind;
2) Выключите переключатель функции отображения экранного меню, IMP_OSD_ShowRgn выключает отображение экранного меню;
3) Отмените регистрацию области OSD в группе OSD и отмените регистрацию области через IMP_OSD_UnRegisterRgn.
4) Уничтожить область OSD через IMP_OSD_DestroyRgn
5) Уничтожьте группу OSD и окончательно уничтожьте группу через IMP_OSD_DestroyGroup.
В демо-версии в основном инициализируются четыре различных дескриптора OSD. Каждый дескриптор на самом деле является типом каждого OSD.
Это изображения временного типа, изображения, окклюзии и прямоугольного типа, которые также соответствуют четырем типам, поддерживаемым нашим чипом Ingenic.
int ret;
IMPRgnHandle *prHander;
IMPRgnHandle rHanderFont;
IMPRgnHandle rHanderLogo;
IMPRgnHandle rHanderCover;
IMPRgnHandle rHanderRect;
prHander = malloc(4 * sizeof(IMPRgnHandle));
if (prHander <= 0) {
IMP_LOG_ERR(TAG, "malloc() error !\n");
return NULL;
}
Эта функция используется для создания нашей области OSD.
Например, если вы хотите добавить некоторую информацию OSD в видеопоток, вам необходимо вызвать эту функцию и выделить для нее некоторые ресурсы. Если она выделена успешно, возвращаемым значением будет дескриптор созданной вами области OSD.
/**
* @fn IMPRgnHandle IMP_OSD_CreateRgn(IMPOSDRgnAttr *prAttr)
*
* создаватьOSDобласть *
* @param[in] prAttr Свойства области экранного меню
*
* @retval Больше или равно 0 успех
* @retval меньше 0 неудача
*
* @remarks никто.
*
* @attention никто.
*/
IMPRgnHandle IMP_OSD_CreateRgn(IMPOSDRgnAttr *prAttr);
Зарегистрируйте дескриптор группы OSD, которую мы только что создали выше, в этой функции, чтобы уведомить чип Ingenic T31 о том, что мы только что зарегистрировали информацию об области OSD.
/**
* @fn int IMP_OSD_RegisterRgn(IMPRgnHandle handle, int grpNum, IMPOSDGrpRgnAttr *pgrAttr)
*
* зарегистрироватьсяOSDобласть *
* @param[in] handle Дескриптор региона, возвращаемое значение IMP_OSD_CreateRgn
* @param[in] grpNum Номер группы экранного меню
* @param[in] pgrAttr Свойства отображения группы OSD
*
* @retval 0 успех
* @retval не-0 неудача
*
* @remarks При вызове этого API необходимо создать соответствующую группу OSD.
*
* @attention никто.
*/
int IMP_OSD_RegisterRgn(IMPRgnHandle handle, int grpNum, IMPOSDGrpRgnAttr *pgrAttr);
Это атрибут региона метки времени, которую мы хотим отобразить, сначала мы устанавливаем его на изображение OSD_REG_PIC.
Затем мы устанавливаем информацию о размере этой области экранного меню, а информацию о начальной точке координат составляет (10,10).
Тогда сколько места нам нужно? Например, 1970-02-20:13-23-23, для этого требуется около 19 цифр.
Поэтому мы используем OSD_REGION_WIDTH, умноженную на 20-кратное значение.
Конкретный размер определяется на основе файла, предоставленного нам нашей демонстрацией.
IMPOSDRgnAttr rAttrFont;
memset(&rAttrFont, 0, sizeof(IMPOSDRgnAttr));
rAttrFont.type = OSD_REG_PIC;
rAttrFont.rect.p0.x = 10;
rAttrFont.rect.p0.y = 10;
rAttrFont.rect.p1.x = rAttrFont.rect.p0.x + 20 * OSD_REGION_WIDTH- 1; //p0 is start,and p1 well be epual p0+width(or heigth)-1
rAttrFont.rect.p1.y = rAttrFont.rect.p0.y + OSD_REGION_HEIGHT - 1;
#ifdef SUPPORT_RGB555LE
rAttrFont.fmt = PIX_FMT_RGB555LE;
#else
rAttrFont.fmt = PIX_FMT_BGRA;
#endif
rAttrFont.data.picData.pData = NULL;
ret = IMP_OSD_SetRgnAttr(rHanderFont, &rAttrFont);
if (ret < 0) {
IMP_LOG_ERR(TAG, "IMP_OSD_SetRgnAttr TimeStamp error !\n");
return NULL;
}
/**
* Свойства области группы экранного меню
*/
typedef struct {
int show; /**< Отображать ли */
IMPPoint offPos; /**< Показать начальные координаты */
float scalex; /**< параметр масштаба x */
float scaley; /**< масштабировать параметр y */
int gAlphaEn; /**< Альфа-переключатель */
int fgAlhpa; /**< Альфа переднего плана */
int bgAlhpa; /**< Фон Альфа */
int layer; /**< слой отображения */
} IMPOSDGrpRgnAttr;
IMPOSDGrpRgnAttr grAttrFont;
if (IMP_OSD_GetGrpRgnAttr(rHanderFont, grpNum, &grAttrFont) < 0) {
IMP_LOG_ERR(TAG, "IMP_OSD_GetGrpRgnAttr Logo error !\n");
return NULL;
}
memset(&grAttrFont, 0, sizeof(IMPOSDGrpRgnAttr));
grAttrFont.show = 0;
/* Disable Font global alpha, only use pixel alpha. */
grAttrFont.gAlphaEn = 1;
grAttrFont.fgAlhpa = 0xff;
grAttrFont.layer = 3;
if (IMP_OSD_SetGrpRgnAttr(rHanderFont, grpNum, &grAttrFont) < 0) {
IMP_LOG_ERR(TAG, "IMP_OSD_SetGrpRgnAttr Logo error !\n");
return NULL;
}
/**
* @fn int IMP_OSD_Start(int grpNum)
*
* настройки Начать отображение группы OSD
*
* @param[in] grpNum Номер группы экранного меню
*
* @retval 0 успех
* @retval не-0 неудача
*
* @remarks При вызове этого API необходимо создать соответствующую группу OSD.
*
* @attention никто.
*/
int IMP_OSD_Start(int grpNum);
/* Step.5 Bind */
IMPCell osdcell = {DEV_ID_OSD, grpNum, 0};
ret = IMP_System_Bind(&chn[0].framesource_chn, &osdcell);
if (ret < 0) {
IMP_LOG_ERR(TAG, "Bind FrameSource channel0 and OSD failed\n");
return -1;
}
ret = IMP_System_Bind(&osdcell, &chn[0].imp_encoder);
if (ret < 0) {
IMP_LOG_ERR(TAG, "Bind OSD and Encoder failed\n");
return -1;
}
/* Step.7 Stream On */
IMP_FrameSource_SetFrameDepth(0, 0);
ret = sample_framesource_streamon();
if (ret < 0) {
IMP_LOG_ERR(TAG, "ImpStreamOn failed\n");
return -1;
}
/* Step.6 Get stream */
if (byGetFd) {
ret = sample_get_video_stream_byfd();
if (ret < 0) {
IMP_LOG_ERR(TAG, "Get video stream byfd failed\n");
return -1;
}
} else {
ret = sample_get_video_stream();
if (ret < 0) {
IMP_LOG_ERR(TAG, "Get video stream failed\n");
return -1;
}
}
Если нам просто нужно встроить картинку или задать область окклюзии, а также некоторые OSD, например неподвижные изображения, то этот шаг совершенно не нужен, но наша временная метка должна меняться со временем. Вносите изменения.
Поэтому в настоящее время мы должны динамически отображать информацию OSD о временной метке в соответствии с изменениями во времени.
Основная цель — получить текущее время системы на основе системной функции localtime, а затем записать содержимое данных, которое OSD должно отображать в соответствии с текущим временем.
static void *update_thread(void *p)
{
int ret;
/*generate time*/
char DateStr[40];
time_t currTime;
struct tm *currDate;
unsigned i = 0, j = 0;
void *dateData = NULL;
uint32_t *data = p;
IMPOSDRgnAttrData rAttrData;
ret = osd_show();
if (ret < 0) {
IMP_LOG_ERR(TAG, "OSD show error\n");
return NULL;
}
while(1) {
int penpos_t = 0;
int fontadv = 0;
time(&currTime);
currDate = localtime(&currTime);
memset(DateStr, 0, 40);
strftime(DateStr, 40, "%Y-%m-%d %I:%M:%S", currDate);
for (i = 0; i < OSD_LETTER_NUM; i++) {
switch(DateStr[i]) {
case '0' ... '9':
dateData = (void *)gBgramap[DateStr[i] - '0'].pdata;
fontadv = gBgramap[DateStr[i] - '0'].width;
penpos_t += gBgramap[DateStr[i] - '0'].width;
break;
case '-':
dateData = (void *)gBgramap[10].pdata;
fontadv = gBgramap[10].width;
penpos_t += gBgramap[10].width;
break;
case ' ':
dateData = (void *)gBgramap[11].pdata;
fontadv = gBgramap[11].width;
penpos_t += gBgramap[11].width;
break;
case ':':
dateData = (void *)gBgramap[12].pdata;
fontadv = gBgramap[12].width;
penpos_t += gBgramap[12].width;
break;
default:
break;
}
#ifdef SUPPORT_RGB555LE
for (j = 0; j < OSD_REGION_HEIGHT; j++) {
memcpy((void *)((uint16_t *)data + j*OSD_LETTER_NUM*OSD_REGION_WIDTH + penpos_t),
(void *)((uint16_t *)dateData + j*fontadv), fontadv*sizeof(uint16_t));
}
#else
for (j = 0; j < OSD_REGION_HEIGHT; j++) {
memcpy((void *)((uint32_t *)data + j*OSD_LETTER_NUM*OSD_REGION_WIDTH + penpos_t),
(void *)((uint32_t *)dateData + j*fontadv), fontadv*sizeof(uint32_t));
}
#endif
}
rAttrData.picData.pData = data;
IMP_OSD_UpdateRgnAttrData(prHander[0], &rAttrData);
sleep(1);
}
return NULL;
}
Это то же самое, что и предыдущие уроки, поэтому больше объяснять не буду, просто некоторые функции деинициализации и тому подобное.