#include "basic_include.h" #include "lib/multimedia/msi.h" #include "lib/heap/av_heap.h" #include "lib/heap/av_psram_heap.h" #include "stream_define.h" #include "user_work/user_work.h" /*************************************************************************************** * 这个模块主要是添加水印,比较特殊,会涉及修改源数据,所以从软件逻辑一定要明确,只有它可以接收 * 这个yuv数据,然后重新输出,这样才能保证其他msi接收到的yuv是有水印的 * 水印简单添加水印,没有进行运算 **************************************************************************************/ // data申请空间函数 #define STREAM_MALLOC av_psram_malloc #define STREAM_FREE av_psram_free #define STREAM_ZALLOC av_psram_zalloc // 结构体申请空间函数 #define STREAM_LIBC_MALLOC av_malloc #define STREAM_LIBC_FREE av_free #define STREAM_LIBC_ZALLOC av_zalloc struct watermark_msi_s { struct os_work work; struct msi *msi; uint8_t filter; uint8_t output_en; }; #define WATERMARK_X (50) #define WATERMARK_Y (50) #define WATERMARK_COLOR (0x0) // 设置水印亮度 #define FONT_W 16 #define FONT_H 32 // clang-format off const uint8_t font_data[][64] = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x06, 0x20, 0x0C, 0x30, 0x18, 0x18, 0x18, 0x18, 0x18, 0x08, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x18, 0x08, 0x18, 0x18, 0x18, 0x18, 0x0C, 0x30, 0x06, 0x20, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x1F, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x03, 0xC0, 0x1F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x08, 0x38, 0x10, 0x18, 0x20, 0x0C, 0x20, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x02, 0x00, 0x04, 0x04, 0x08, 0x04, 0x10, 0x04, 0x20, 0x0C, 0x3F, 0xF8, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x18, 0x60, 0x30, 0x30, 0x30, 0x18, 0x30, 0x18, 0x30, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, 0x03, 0xC0, 0x00, 0x70, 0x00, 0x18, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x08, 0x30, 0x18, 0x18, 0x30, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xE0, 0x01, 0x60, 0x01, 0x60, 0x02, 0x60, 0x04, 0x60, 0x04, 0x60, 0x08, 0x60, 0x08, 0x60, 0x10, 0x60, 0x30, 0x60, 0x20, 0x60, 0x40, 0x60, 0x7F, 0xFC, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, 0x0F, 0xFC, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x13, 0xE0, 0x14, 0x30, 0x18, 0x18, 0x10, 0x08, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x20, 0x18, 0x20, 0x18, 0x18, 0x30, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xE0, 0x06, 0x18, 0x0C, 0x18, 0x08, 0x18, 0x18, 0x00, 0x10, 0x00, 0x10, 0x00, 0x30, 0x00, 0x33, 0xE0, 0x36, 0x30, 0x38, 0x18, 0x38, 0x08, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x18, 0x0C, 0x18, 0x08, 0x0C, 0x18, 0x0E, 0x30, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFC, 0x1F, 0xFC, 0x10, 0x08, 0x30, 0x10, 0x20, 0x10, 0x20, 0x20, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x80, 0x00, 0x80, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x0C, 0x30, 0x18, 0x18, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x38, 0x0C, 0x38, 0x08, 0x1E, 0x18, 0x0F, 0x20, 0x07, 0xC0, 0x18, 0xF0, 0x30, 0x78, 0x30, 0x38, 0x60, 0x1C, 0x60, 0x0C, 0x60, 0x0C, 0x60, 0x0C, 0x60, 0x0C, 0x30, 0x18, 0x18, 0x30, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x18, 0x20, 0x30, 0x10, 0x30, 0x18, 0x60, 0x08, 0x60, 0x0C, 0x60, 0x0C, 0x60, 0x0C, 0x60, 0x0C, 0x60, 0x0C, 0x70, 0x1C, 0x30, 0x2C, 0x18, 0x6C, 0x0F, 0x8C, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x18, 0x00, 0x10, 0x30, 0x30, 0x30, 0x60, 0x30, 0xC0, 0x0F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xC0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xC0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; // clang-format on static void draw_char(char *yuv_buf, char ch, int w, int h, int x, int y) { int i, j; int8_t num = ch - 0x30; if (ch == ':') { num = 10; } else if (ch == '-') { num = 11; } else if (num < 0 || num > 10) { return; } const uint8_t *num_font = (const uint8_t*)font_data[num]; int size = sizeof(font_data[0]); for (i = 0; i < size; i++) { for (j = 0; j < 8; j++) { if (num_font[i] & (0x80 >> j)) { // 越界就不再绘制 if (x + j + i % (FONT_W / 8) * 8 >= w) { break; } yuv_buf[(y + i / (FONT_W / 8)) * w + x + j + i % (FONT_W / 8) * 8] = WATERMARK_COLOR; } else { // yuv_buf[(y+i)*WIDTH,+x+j] = 0; } } } } static char draw_str(char *yuv_buf, char *str, int w, int h, int x, int y) { while (*str) { draw_char(yuv_buf, *str, w, h, x, y); x += FONT_W; str++; } return 0; } static int32_t watermark_work(struct os_work *work) { struct yuv_arg_s *arg; struct watermark_msi_s *watermark = (struct watermark_msi_s *) work; struct framebuff *fb; uint32_t send_count; fb = msi_get_fb(watermark->msi, 0); // 检查是否需要发送到下一级 if (fb && !watermark->output_en) { send_count = msi_output_fb(watermark->msi, NULL); if (!send_count) { msi_delete_fb(NULL, fb); fb = NULL; } else { watermark->output_en = 1; } } if (fb) { char path[64]; struct tm *time_info; struct timeval ptimeval; gettimeofday(&ptimeval, NULL); time_t time_val = (time_t)ptimeval.tv_sec; time_info = gmtime(&time_val); uint32_t year = time_info->tm_year + 1900; uint32_t mon = time_info->tm_mon + 1; uint32_t day = time_info->tm_mday; uint32_t hour = time_info->tm_hour; uint32_t min = time_info->tm_min; uint32_t sec = time_info->tm_sec; os_sprintf(path, "%04d %02d %02d %02d:%02d:%02d", year,mon,day,hour, min, sec); arg = (struct yuv_arg_s *) fb->priv; // 增加水印后,发出去 draw_str((char*)fb->data, path, arg->out_w, arg->out_h, WATERMARK_X, WATERMARK_Y); sys_dcache_clean_invalid_range((uint32_t *) (fb->data + WATERMARK_Y * arg->out_w), arg->out_w * 32); send_count = msi_output_fb(watermark->msi, fb); if (!send_count) { watermark->output_en = 0; } } return 0; } static int32_t watermark_msi_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2) { int32_t ret = RET_OK; struct watermark_msi_s *watermark = (struct watermark_msi_s *) msi->priv; switch (cmd_id) { case MSI_CMD_POST_DESTROY: { os_work_cancle2(&watermark->work, 1); STREAM_LIBC_FREE(watermark); } break; case MSI_CMD_PRE_DESTROY: { os_work_cancle2(&watermark->work, 1); } break; case MSI_CMD_TRANS_FB: { struct framebuff *fb = (struct framebuff *) param1; // printf("mtype:%d\n",fb->mtype); if (fb->mtype != F_YUV) { ret = RET_ERR; } // 如果需要过滤,并且过滤类型不匹配就不增加水印 else if (watermark->filter && watermark->filter != fb->stype) { ret = RET_ERR; } } break; case MSI_CMD_TRANS_FB_END: { os_run_work(&watermark->work); } break; default: { } break; } return ret; } // 中转(路由)msi,不需要接收,仅仅发送就可以了 struct msi *yuv_time_watermark(const char *name, uint8_t filter) { // 设置1个接收,只是为了可以output_fb给到这个msi uint8_t isnew; struct msi *msi = msi_new(name, 8, &isnew); if (isnew) { struct watermark_msi_s *watermark = (struct watermark_msi_s *) STREAM_LIBC_ZALLOC(sizeof(struct watermark_msi_s)); ASSERT(watermark); watermark->msi = msi; watermark->filter = filter; msi->priv = (void *) watermark; msi->action = watermark_msi_action; OS_WORK_INIT(&watermark->work, watermark_work, 0); os_run_work_delay(&watermark->work, 1); msi->enable = 1; } return msi; }