435 lines
13 KiB
C++
Executable File
435 lines
13 KiB
C++
Executable File
#include "osd.h"
|
|
|
|
#include <ui/GraphicBuffer.h>
|
|
#include <ui/GraphicBufferAllocator.h>
|
|
#include <ui/GraphicBufferMapper.h>
|
|
|
|
#include <math.h>
|
|
#include <time.h>
|
|
#include <cwchar>
|
|
#include <ft2build.h>
|
|
#include FT_FREETYPE_H
|
|
#include <freetype/ftglyph.h>
|
|
|
|
#include <png.h>
|
|
#include "pngstruct.h"
|
|
#include "pnginfo.h"
|
|
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include "ExternalCameraDeviceSession_3.4.h"
|
|
|
|
#include "android-base/macros.h"
|
|
#include <utils/Timers.h>
|
|
#include <utils/Trace.h>
|
|
#include <linux/videodev2.h>
|
|
#include <sync/sync.h>
|
|
|
|
#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
|
|
#include <libyuv.h>
|
|
|
|
#include <jpeglib.h>
|
|
#include "RgaCropScale.h"
|
|
#include <RockchipRga.h>
|
|
#include <im2d_api/im2d.h>
|
|
#include <ui/GraphicBuffer.h>
|
|
#include <ui/GraphicBufferAllocator.h>
|
|
#include <ui/GraphicBufferMapper.h>
|
|
#ifndef RK_GRALLOC_4
|
|
#include "ExternalCameraGralloc.h"
|
|
#else
|
|
#include "ExternalCameraGralloc4.h"
|
|
#endif
|
|
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <poll.h>
|
|
#include <unistd.h>
|
|
|
|
namespace android {
|
|
namespace hardware {
|
|
namespace camera {
|
|
namespace device {
|
|
namespace V3_4 {
|
|
namespace implementation {
|
|
|
|
#define FONT_WIDTH 300
|
|
#define FONT_HEIGHT 30
|
|
#define WIDTH 50
|
|
#define HEIGHT 30
|
|
#define ALIGN(value, align) ((value + align -1) & ~(align-1))
|
|
|
|
int osd_time_pos_x,osd_time_pos_y;
|
|
int osd_logo_pos_x,osd_logo_pos_y;
|
|
|
|
int OSD_IMAGE_W;
|
|
int OSD_IMAGE_H;
|
|
|
|
FT_Library mLibrary;
|
|
FT_Face mFace;
|
|
FT_GlyphSlot mSlot;
|
|
FT_Matrix mMatrix; /* transformation matrix */
|
|
FT_Vector mPen; /* untransformed origin */
|
|
|
|
void deInitFt() {
|
|
FT_Done_Face (mFace);
|
|
FT_Done_FreeType(mLibrary);
|
|
}
|
|
|
|
void resetFt() {
|
|
mPen.x = 0 * 50;
|
|
mPen.y = ( HEIGHT - 10 ) * 50;
|
|
}
|
|
|
|
int initFt() {
|
|
|
|
FT_Error error;
|
|
|
|
char* text;
|
|
|
|
double angle;
|
|
int target_height = HEIGHT;
|
|
int n;
|
|
|
|
angle = ( 0.0 / 360 ) * 3.14159 * 2; /* use 25 degrees */
|
|
|
|
error = FT_Init_FreeType(&mLibrary); /* initialize library */
|
|
/* error handling omitted */
|
|
|
|
error = FT_New_Face(mLibrary, FONT_FILE, 0, &mFace); /* create face object */
|
|
/* error handling omitted */
|
|
|
|
#if 1
|
|
/* use 50pt at 100dpi */
|
|
error = FT_Set_Char_Size(mFace, 20 * 35, 0,
|
|
100, 0 ); /* set character size */
|
|
|
|
/* pixels = 50 /72 * 100 = 69 */
|
|
#else
|
|
FT_Set_Pixel_Sizes(mFace, 15, 0);
|
|
#endif
|
|
/* error handling omitted */
|
|
|
|
mSlot = mFace->glyph;
|
|
|
|
/* set up matrix */
|
|
mMatrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
|
|
mMatrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
|
|
mMatrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
|
|
mMatrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
|
|
|
|
/* the pen position in 26.6 cartesian space coordinates; */
|
|
/* start at (0,40) relative to the upper left corner */
|
|
mPen.x = 0 * 50;
|
|
mPen.y = ( HEIGHT - 10 ) * 50;
|
|
return 0;
|
|
}
|
|
|
|
|
|
void draw_bitmap( FT_Bitmap* bitmap, unsigned char *buf, FT_Int x, FT_Int y, int w, int h)
|
|
{
|
|
FT_Int i, j, p, q;
|
|
FT_Int x_max = x + bitmap->width;
|
|
FT_Int y_max = y + bitmap->rows;
|
|
int pixByte = 4;
|
|
for ( i = x, p = 0; i < x_max; i++, p++ )
|
|
{
|
|
for ( j = y, q = 0; j < y_max; j++, q++ )
|
|
{
|
|
unsigned char alth_vale = bitmap->buffer[q * bitmap->width + p];
|
|
double alth =(alth_vale*1.0)/255;
|
|
buf[(j*w+i)*pixByte] = 0xff*alth;
|
|
buf[(j*w+i)*pixByte+1] = 0xff*alth;
|
|
buf[(j*w+i)*pixByte+2] = 0x00*alth;
|
|
buf[(j*w+i)*pixByte+3] = alth_vale;
|
|
}
|
|
}
|
|
}
|
|
void wchar2RGBA(wchar_t *text, unsigned char *rgba, int w, int h) {
|
|
//FT_ENCODING_GB2312, FT_ENCODING_UNICODE
|
|
int len = wcslen(text);
|
|
FT_Select_Charmap(mFace, FT_ENCODING_UNICODE);
|
|
FT_Set_Char_Size(mFace, 20 * 50, 0, 80, 0);
|
|
for (int i=0; i<len; i++) {
|
|
FT_Set_Transform(mFace, &mMatrix, &mPen);
|
|
int result = FT_Load_Glyph(mFace, FT_Get_Char_Index(mFace, text[i]), FT_LOAD_DEFAULT);
|
|
|
|
//FT_RENDER_MODE_MONO FT_RENDER_MODE_NORMAL 第二个参数为渲染模式
|
|
result = FT_Render_Glyph(mFace->glyph, FT_RENDER_MODE_NORMAL);
|
|
FT_Bitmap bmp = mFace->glyph->bitmap;
|
|
//int h = bmp.rows;
|
|
//int w = bmp.width;
|
|
draw_bitmap(&bmp, rgba,
|
|
mFace->glyph->bitmap_left,
|
|
HEIGHT - mFace->glyph->bitmap_top, w, h);
|
|
mPen.x += mSlot->advance.x;
|
|
mPen.y += mSlot->advance.y;
|
|
}
|
|
}
|
|
|
|
void string2RGBA(char* text, unsigned char *rgba, int w, int h){
|
|
|
|
int num_chars = strlen(text);
|
|
FT_Error error;
|
|
for (int n = 0; n < num_chars; n++ )
|
|
{
|
|
/* set transformation */
|
|
FT_Set_Transform(mFace, &mMatrix, &mPen);
|
|
|
|
/* load glyph image into the slot (erase previous one) */
|
|
error = FT_Load_Char(mFace, text[n], FT_LOAD_RENDER );
|
|
if ( error )
|
|
continue; /* ignore errors */
|
|
/* now, draw to our target surface (convert position) */
|
|
draw_bitmap( &mSlot->bitmap, rgba,
|
|
mSlot->bitmap_left,
|
|
HEIGHT- mSlot->bitmap_top, w, h);
|
|
|
|
/* increment pen position */
|
|
mPen.x += mSlot->advance.x;
|
|
mPen.y += mSlot->advance.y;
|
|
}
|
|
}
|
|
|
|
void getCSTTimeFormat(char* pStdTimeFormat)
|
|
{
|
|
time_t nTimeStamp;
|
|
time(&nTimeStamp);
|
|
char pTmpString[256] = {0};
|
|
tm *pTmStruct = localtime(&nTimeStamp);
|
|
sprintf(pTmpString, "%04d-%02d-%02d %02d:%02d:%02d", pTmStruct->tm_year + 1900, pTmStruct->tm_mon + 1, pTmStruct->tm_mday, \
|
|
pTmStruct->tm_hour, pTmStruct->tm_min, pTmStruct->tm_sec);
|
|
strcpy(pStdTimeFormat, pTmpString);
|
|
}
|
|
|
|
void getCSTTimeFormatUnicode(wchar_t* pStdTimeFormat)
|
|
{
|
|
time_t nTimeStamp;
|
|
time(&nTimeStamp);
|
|
wchar_t pTmpString[256] = {0};
|
|
tm *pTmStruct = localtime(&nTimeStamp);
|
|
swprintf(pTmpString, 256, OSD_TEXT, pTmStruct->tm_year + 1900, pTmStruct->tm_mon + 1, pTmStruct->tm_mday, \
|
|
pTmStruct->tm_hour, pTmStruct->tm_min, pTmStruct->tm_sec);
|
|
wmemcpy(pStdTimeFormat, pTmpString, 128);
|
|
return;
|
|
}
|
|
|
|
void getGMTTimeFormat(char* pStdTimeFormat)
|
|
{
|
|
time_t ltime;
|
|
time(<ime);
|
|
//ltime += 8*3600; //北京时区
|
|
tm* gmt = gmtime(<ime);
|
|
char s[128] = { 0 };
|
|
strftime(s, 80, "%Y-%m-%d %H:%M:%S", gmt);
|
|
strcpy(pStdTimeFormat, s);
|
|
}
|
|
|
|
void timeFormat2Timestamp(const char* strTimeFormat, time_t& timeStamp)
|
|
{
|
|
// strTimeFormat should be such as "2001-11-12 18:31:01"
|
|
struct tm *timeinfo;
|
|
memset( timeinfo, 0, sizeof(struct tm));
|
|
strptime(strTimeFormat, "%Y-%m-%d %H:%M:%S", timeinfo);
|
|
timeStamp = mktime(timeinfo);
|
|
}
|
|
|
|
int DecodePNG(char* png_path,unsigned int* buf) {
|
|
FILE *fp;
|
|
fp = fopen(png_path, "rb");
|
|
png_byte sig[8];
|
|
fread(sig, 1, 8, fp);
|
|
if(png_sig_cmp(sig, 0, 8)){
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
|
|
png_structp png_ptr;
|
|
png_infop info_ptr;
|
|
|
|
png_ptr = png_create_read_struct(png_get_libpng_ver(NULL), NULL, NULL, NULL);
|
|
info_ptr = png_create_info_struct(png_ptr);
|
|
setjmp(png_jmpbuf(png_ptr));
|
|
png_init_io(png_ptr, fp);
|
|
png_set_sig_bytes(png_ptr, 8);
|
|
png_read_info(png_ptr, info_ptr);
|
|
|
|
ALOGD("PNG INFO(%s):\n pixel_depth = %d,bit_depth = %d, width = %d,height = %d", png_path,
|
|
info_ptr->pixel_depth,info_ptr->bit_depth,
|
|
info_ptr->width,info_ptr->height);
|
|
|
|
png_bytep row_pointers[info_ptr->height];
|
|
int row;
|
|
for (row = 0; row < info_ptr->height; row++){
|
|
row_pointers[row] = NULL;
|
|
row_pointers[row] = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr,info_ptr));
|
|
}
|
|
png_read_image(png_ptr, row_pointers);
|
|
int i, j;
|
|
OSD_IMAGE_W = ALIGN(info_ptr->width,16);
|
|
OSD_IMAGE_H = info_ptr->height;
|
|
info_ptr->width = OSD_IMAGE_W;
|
|
unsigned int *pDst = buf;//(unsigned int*)malloc(size);//因为sizeof(unsigned long)=8
|
|
|
|
printf("sizeof(unsigned int) = %d\n", (int)sizeof(unsigned int));
|
|
if(info_ptr->pixel_depth == 32){
|
|
unsigned char* pSrc;
|
|
unsigned int pixelR,pixelG,pixelB,pixelA;
|
|
for(j=0; j<info_ptr->height; j++){
|
|
pSrc = row_pointers[j];
|
|
for(i=0; i<info_ptr->width; i++){
|
|
pixelR = *pSrc++;
|
|
pixelG = *pSrc++;
|
|
pixelB = *pSrc++;
|
|
pixelA = *pSrc++;
|
|
pDst[i] = (pixelR<< 24) | (pixelR << 16) | (pixelB << 8) | pixelA;
|
|
if (pixelA==0) {
|
|
pDst[i] = 0;
|
|
}
|
|
}
|
|
pDst += info_ptr->width;
|
|
}
|
|
}
|
|
|
|
for (row = 0; row < info_ptr->height; row++){
|
|
png_free(png_ptr,row_pointers[row]);
|
|
}
|
|
fclose(fp);
|
|
png_free_data(png_ptr,info_ptr,PNG_FREE_ALL,-1);
|
|
png_destroy_read_struct(&png_ptr,NULL,NULL);
|
|
return 0;
|
|
}
|
|
|
|
void processOSD(int width,int height,unsigned long dst_fd){
|
|
static uint32_t *pixelsLogo = nullptr;
|
|
if(pixelsLogo == nullptr){
|
|
static buffer_handle_t memHandle = nullptr;
|
|
android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
|
|
const auto usage =
|
|
GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_OFTEN;
|
|
unsigned pixelsPerLine;
|
|
android::status_t result =
|
|
alloc.allocate(500, 500, HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, &memHandle, &pixelsPerLine, 0,
|
|
"ExternalCameraDevice");
|
|
GraphicBufferMapper &mapper = GraphicBufferMapper::get();
|
|
mapper.lock(memHandle,
|
|
GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
|
|
android::Rect(500, 500),
|
|
(void **) &pixelsLogo);
|
|
|
|
// If we failed to lock the pixel buffer, we're about to crash, but log it first
|
|
if (!pixelsLogo) {
|
|
ALOGE("Camera failed to gain access to image buffer for writing");
|
|
}
|
|
DecodePNG(PNG_LOGO,pixelsLogo);
|
|
}
|
|
|
|
static uint32_t *pixelsFont = nullptr;
|
|
if(pixelsFont == nullptr){
|
|
static buffer_handle_t memHandle = nullptr;
|
|
android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
|
|
const auto usage =
|
|
GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_OFTEN;
|
|
unsigned pixelsPerLine;
|
|
android::status_t result =
|
|
alloc.allocate(500, 500, HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, &memHandle, &pixelsPerLine, 0,
|
|
"ExternalCameraDevice");
|
|
GraphicBufferMapper &mapper = GraphicBufferMapper::get();
|
|
mapper.lock(memHandle,
|
|
GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
|
|
android::Rect(500, 500),
|
|
(void **) &pixelsFont);
|
|
|
|
// If we failed to lock the pixel buffer, we're about to crash, but log it first
|
|
if (!pixelsFont) {
|
|
ALOGE("Camera failed to gain access to image buffer for writing");
|
|
}
|
|
initFt();
|
|
|
|
wchar_t pStdTimeFormat[128] = { 0 };
|
|
getCSTTimeFormatUnicode(pStdTimeFormat);
|
|
memset((unsigned char*)pixelsFont,0x00,FONT_WIDTH*FONT_HEIGHT*4);
|
|
|
|
wchar2RGBA(pStdTimeFormat, (unsigned char*)pixelsFont, FONT_WIDTH, FONT_HEIGHT);
|
|
resetFt();
|
|
deInitFt();
|
|
}
|
|
|
|
camera2::RgaCropScale::Params rgain, rgain0, rgaout;
|
|
unsigned char* timeOsdVddr = NULL;
|
|
unsigned char* labelOsdVddr = NULL;
|
|
int timeOsdFd = -1;
|
|
int labelOsdFd = -1;
|
|
int timeOsdWidth = 0;
|
|
int timeOsdHeight = 0;
|
|
int labelOsdWidth = 0;
|
|
int labelOsdHeight = 0;
|
|
|
|
timeOsdVddr = (unsigned char*)pixelsFont;
|
|
|
|
labelOsdVddr = (unsigned char*)pixelsLogo;
|
|
timeOsdWidth = FONT_WIDTH;
|
|
timeOsdHeight = FONT_HEIGHT;
|
|
labelOsdWidth = OSD_IMAGE_W;
|
|
labelOsdHeight = OSD_IMAGE_H;
|
|
|
|
osd_time_pos_x = width - timeOsdWidth;
|
|
osd_time_pos_y = height - timeOsdHeight;
|
|
ALOGD("osd_time_pos_x:%d,osd_time_pos_y:%d",osd_time_pos_x,osd_time_pos_y);
|
|
|
|
rgain.fd = timeOsdFd;
|
|
rgain.fmt = HAL_PIXEL_FORMAT_RGBA_8888;
|
|
rgain.vir_addr = (char*)timeOsdVddr;
|
|
rgain.mirror = false;
|
|
rgain.width = timeOsdWidth;
|
|
rgain.height = timeOsdHeight;
|
|
rgain.offset_x = 0;
|
|
rgain.offset_y = 0;
|
|
rgain.width_stride = timeOsdWidth;
|
|
rgain.height_stride = timeOsdHeight;
|
|
rgain.translate_x = osd_time_pos_x;
|
|
rgain.translate_y = osd_time_pos_y;
|
|
rgain.blend = 1;
|
|
|
|
rgaout.fd = dst_fd;
|
|
rgaout.fmt = HAL_PIXEL_FORMAT_YCrCb_NV12;
|
|
rgaout.mirror = false;
|
|
rgaout.width = width;
|
|
rgaout.height = height;
|
|
rgaout.offset_x = 0;
|
|
rgaout.offset_y = 0;
|
|
rgaout.width_stride = width;
|
|
rgaout.height_stride = height;
|
|
camera2::RgaCropScale::Im2dBlit(&rgain, &rgaout);
|
|
|
|
ALOGD("labelOsdWidth:%d,labelOsdHeight:%d",labelOsdWidth,labelOsdHeight);
|
|
osd_logo_pos_x = width - labelOsdWidth;
|
|
osd_logo_pos_y = height - labelOsdHeight - timeOsdHeight;
|
|
ALOGD("osd_logo_pos_x:%d,osd_logo_pos_y:%d",osd_logo_pos_x,osd_logo_pos_y);
|
|
|
|
rgain0.fd = labelOsdFd;
|
|
rgain0.fmt = HAL_PIXEL_FORMAT_RGBA_8888;
|
|
rgain0.vir_addr = (char*)labelOsdVddr;
|
|
rgain0.mirror = false;
|
|
rgain0.width = labelOsdWidth;
|
|
rgain0.height = labelOsdHeight;
|
|
rgain0.offset_x = 0;
|
|
rgain0.offset_y = 0;
|
|
rgain0.width_stride = labelOsdWidth;
|
|
rgain0.height_stride = labelOsdHeight;
|
|
rgain0.translate_x = osd_logo_pos_x;
|
|
rgain0.translate_y = osd_logo_pos_y;
|
|
rgain0.blend = 1;
|
|
|
|
camera2::RgaCropScale::Im2dBlit(&rgain0, &rgaout);
|
|
}
|
|
|
|
|
|
} // namespace implementation
|
|
} // namespace V3_4
|
|
} // namespace device
|
|
} // namespace camera
|
|
} // namespace hardware
|
|
} // namespace android
|