This commit is contained in:
刘可亮
2024-09-03 11:16:08 +08:00
parent cf270df8d6
commit 803cac77d5
2931 changed files with 614364 additions and 31222 deletions

View File

@@ -0,0 +1,17 @@
from building import *
import os
cwd = GetCurrentDir()
group = []
src = Glob('*.c')
CPPPATH = [cwd]
list = os.listdir(cwd)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
group = group + SConscript(os.path.join(d, 'SConscript'))
group = group + DefineGroup('LVGL-port', src, depend = ['LPKG_USING_LVGL'], CPPPATH = CPPPATH)
Return('group')

View File

@@ -0,0 +1,17 @@
from building import *
import os
cwd = GetCurrentDir()
group = []
src = Glob('*.c')
CPPPATH = [cwd]
list = os.listdir(cwd)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
group = group + SConscript(os.path.join(d, 'SConscript'))
group = group + DefineGroup('LVGL-port', src, depend = ['LPKG_USING_LVGL'], CPPPATH = CPPPATH)
Return('group')

View File

@@ -0,0 +1,127 @@
/*
* Copyright (c) 2024, ArtInChip Technology Co., Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Authors: Ning Fang <ning.fang@artinchip.com>
*/
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include "lvgl.h"
#include "aic_ui.h"
#include "aic_core.h"
#include "mpp_ge.h"
#define ALIGN_8B(x) (((x) + (7)) & ~7)
#define ALIGN_1024B(x) ((x+1023) & (~1023))
struct lv_mpp_buf
{
struct mpp_buf buf;
unsigned char *data;
int size;
};
struct lv_mpp_buf *lv_mpp_image_alloc(int width, int height, enum mpp_pixel_format fmt)
{
struct lv_mpp_buf *image;
int size = 0;
image = (struct lv_mpp_buf *)aicos_malloc(MEM_DEFAULT, sizeof(struct lv_mpp_buf));
if (!image) {
LV_LOG_ERROR("aicos_malloc failed");
return NULL;
}
memset(image, 0, sizeof(struct lv_mpp_buf));
if (fmt == MPP_FMT_ARGB_8888) {
image->buf.stride[0] = ALIGN_8B(width * 4);
} else if (fmt == MPP_FMT_RGB_565) {
image->buf.stride[0] = ALIGN_8B(width * 2);
} else {
LV_LOG_ERROR("unsupport fmt:%d", fmt);
aicos_free(MEM_DEFAULT, image);
return NULL;
}
size = image->buf.stride[0] * height;
image->size = size;
image->buf.buf_type = MPP_PHY_ADDR;
image->buf.size.width = width;
image->buf.size.height = height;
image->buf.format = fmt;
image->data = (unsigned char *)aicos_malloc(MEM_CMA, size + 1023);
if (!image->data) {
aicos_free(MEM_DEFAULT, image);
return NULL;
} else {
image->buf.phy_addr[0] = (unsigned int)ALIGN_1024B(((unsigned long)image->data));
aicos_dcache_clean_invalid_range((unsigned long *)((unsigned long)image->buf.phy_addr[0]), size);
}
return image;
}
void lv_mpp_image_flush_cache(struct lv_mpp_buf *image)
{
aicos_dcache_clean_invalid_range((unsigned long *)((unsigned long)image->buf.phy_addr[0]), image->size);
return;
}
void lv_mpp_image_free(struct lv_mpp_buf *image)
{
if (image) {
if (image->data)
aicos_free(MEM_CMA, image->data);
aicos_free(MEM_DEFAULT, image);
}
return;
}
static struct mpp_ge *g_ge = NULL;
int lv_ge_fill(struct mpp_buf *buf, enum ge_fillrect_type type,
unsigned int start_color, unsigned int end_color, int blend)
{
int ret;
struct ge_fillrect fill = { 0 };
if (!g_ge)
g_ge = mpp_ge_open();
/* fill info */
fill.type = type;
fill.start_color = start_color;
fill.end_color = end_color;
/* dst buf */
memcpy(&fill.dst_buf, buf, sizeof(struct mpp_buf));
/* ctrl */
fill.ctrl.flags = 0;
fill.ctrl.alpha_en = blend;
ret = mpp_ge_fillrect(g_ge, &fill);
if (ret < 0) {
LV_LOG_WARN("fillrect1 fail\n");
return LV_RES_INV;
}
ret = mpp_ge_emit(g_ge);
if (ret < 0) {
LV_LOG_WARN("emit fail\n");
return LV_RES_INV;
}
ret = mpp_ge_sync(g_ge);
if (ret < 0) {
LV_LOG_WARN("sync fail\n");
return LV_RES_INV;
}
return LV_RES_OK;
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2022-2024, ArtInChip Technology Co., Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Authors: Ning Fang <ning.fang@artinchip.com>
*/
#ifndef CANVAS_IMAGE_H
#define CANVAS_IMAGE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "lvgl.h"
#include "aic_ui.h"
#include "aic_core.h"
#include "mpp_ge.h"
struct lv_mpp_buf
{
struct mpp_buf buf;
unsigned char *data;
int size;
};
struct lv_mpp_buf *lv_mpp_image_alloc(int width, int height, enum mpp_pixel_format fmt);
void lv_mpp_image_flush_cache(struct lv_mpp_buf *image);
void lv_mpp_image_free(struct lv_mpp_buf *image);
int lv_ge_fill(struct mpp_buf *buf, enum ge_fillrect_type type,
unsigned int start_color, unsigned int end_color, int blend);
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif //CANVAS_IMAGE_H

View File

@@ -0,0 +1,310 @@
/*
* Copyright (c) 2024, ArtInChip Technology Co., Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Authors: Ning Fang <ning.fang@artinchip.com>
*/
#include "lv_aic_canvas.h"
#include "lv_assert.h"
#include "lv_math.h"
#include "lv_draw.h"
#include "lv_refr.h"
#include "lv_draw_sw.h"
#define USE_HW_IMG_BLIT
#define MY_CLASS &lv_aic_canvas_class
static void lv_aic_canvas_constructor(const lv_obj_class_t *class_p, lv_obj_t *obj);
static void lv_aic_canvas_destructor(const lv_obj_class_t *class_p, lv_obj_t *obj);
static void init_fake_disp(lv_obj_t *canvas, lv_disp_t *disp, lv_disp_drv_t *drv, lv_area_t *clip_area);
static void deinit_fake_disp(lv_obj_t *canvas, lv_disp_t *disp);
const lv_obj_class_t lv_aic_canvas_class = {
.constructor_cb = lv_aic_canvas_constructor,
.destructor_cb = lv_aic_canvas_destructor,
.instance_size = sizeof(lv_aic_canvas_t),
.base_class = &lv_img_class
};
lv_obj_t *lv_aic_canvas_create(lv_obj_t * parent)
{
LV_LOG_INFO("begin");
lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
lv_obj_class_init_obj(obj);
return obj;
}
lv_res_t lv_aic_canvas_alloc_buffer(lv_obj_t *obj, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
// only support argb8888 currently
enum mpp_pixel_format fmt = MPP_FMT_ARGB_8888;
lv_aic_canvas_t *canvas = (lv_aic_canvas_t *)obj;
if (cf != LV_IMG_CF_TRUE_COLOR_ALPHA) {
LV_LOG_WARN("please check cf: %d, only support LV_IMG_CF_TRUE_COLOR_ALPHA", cf);
}
canvas->img_buf= lv_mpp_image_alloc(w, h, fmt);
if (!canvas->img_buf) {
LV_LOG_ERROR("lv_mpp_image_alloc failed");
return LV_RES_INV;
}
#ifdef USE_HW_IMG_BLIT
canvas->dsc.header.cf = LV_IMG_CF_RESERVED_16;
canvas->dsc.header.w = w;
canvas->dsc.header.h = h;
canvas->dsc.data = (uint8_t *)&canvas->img_buf->buf;
#else
canvas->dsc.header.cf = cf;
canvas->dsc.header.w = w;
canvas->dsc.header.h = h;
canvas->dsc.data = (void *)((unsigned long)(canvas->img_buf->buf.phy_addr[0]));
#endif
lv_img_set_src(obj, &canvas->dsc);
lv_img_cache_invalidate_src(&canvas->dsc);
return LV_RES_OK;
}
void lv_aic_canvas_draw_text(lv_obj_t *obj, lv_coord_t x, lv_coord_t y, lv_coord_t max_w,
lv_draw_label_dsc_t * draw_dsc, const char * txt)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_aic_canvas_t *canvas = (lv_aic_canvas_t *)obj;
lv_img_dsc_t *dsc = &canvas->dsc;
if(dsc->header.cf >= LV_IMG_CF_INDEXED_1BIT && dsc->header.cf <= LV_IMG_CF_INDEXED_8BIT) {
LV_LOG_WARN("lv_canvas_draw_text: can't draw to LV_IMG_CF_INDEXED canvas");
return;
}
// Create a dummy display to fool the lv_draw function, It will think it draws to real screen
lv_disp_t fake_disp;
lv_disp_drv_t driver;
lv_area_t clip_area;
init_fake_disp(obj, &fake_disp, &driver, &clip_area);
lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing();
_lv_refr_set_disp_refreshing(&fake_disp);
lv_area_t coords;
coords.x1 = x;
coords.y1 = y;
coords.x2 = x + max_w - 1;
coords.y2 = dsc->header.h - 1;
lv_draw_label(driver.draw_ctx, draw_dsc, &coords, txt, NULL);
_lv_refr_set_disp_refreshing(refr_ori);
deinit_fake_disp(obj, &fake_disp);
if (dsc->header.cf == LV_IMG_CF_RESERVED_16) {
lv_mpp_image_flush_cache(canvas->img_buf);
}
lv_obj_invalidate(obj);
}
void lv_aic_canvas_draw_text_to_center(lv_obj_t *obj, lv_draw_label_dsc_t *label_dsc, const char *txt)
{
lv_aic_canvas_t *canvas = (lv_aic_canvas_t *)obj;
lv_ge_fill(&canvas->img_buf->buf, GE_NO_GRADIENT, 0x00000000, 0x00000000, 0);
lv_point_t txt_size;
lv_txt_get_size(&txt_size, txt, label_dsc->font, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
lv_coord_t x = (canvas->dsc.header.w - txt_size.x) / 2;
lv_coord_t y = (canvas->dsc.header.h - txt_size.y) / 2;
lv_aic_canvas_draw_text(obj, x, y, canvas->dsc.header.w, label_dsc, txt);
lv_mpp_image_flush_cache(canvas->img_buf);
lv_obj_invalidate(obj);
return;
}
static void lv_aic_canvas_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
LV_TRACE_OBJ_CREATE("begin");
lv_aic_canvas_t * canvas = (lv_aic_canvas_t *)obj;
canvas->dsc.header.always_zero = 0;
canvas->dsc.header.cf = LV_IMG_CF_TRUE_COLOR;
canvas->dsc.header.h = 0;
canvas->dsc.header.w = 0;
canvas->dsc.data_size = 0;
canvas->dsc.data = NULL;
lv_img_set_src(obj, &canvas->dsc);
if (canvas->img_buf)
lv_mpp_image_free(canvas->img_buf);
LV_TRACE_OBJ_CREATE("finished");
}
static void lv_aic_canvas_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
LV_TRACE_OBJ_CREATE("begin");
lv_aic_canvas_t * canvas = (lv_aic_canvas_t *)obj;
lv_img_cache_invalidate_src(&canvas->dsc);
}
static inline lv_color32_t lv_pixel_mix(lv_color32_t c1, lv_color32_t c2, uint8_t mix)
{
lv_color32_t ret;
ret.ch.red = LV_UDIV255(c1.ch.red *mix + c2.ch.red * (255 - mix) + LV_COLOR_MIX_ROUND_OFS);
ret.ch.green = LV_UDIV255(c1.ch.green *mix + c2.ch.green * (255 - mix) + LV_COLOR_MIX_ROUND_OFS);
ret.ch.blue = LV_UDIV255(c1.ch.blue *mix + c2.ch.blue * (255 - mix) + LV_COLOR_MIX_ROUND_OFS);
ret.ch.alpha = 0xff;
return ret;
}
static inline void lv_pixel_mix_with_alpha(lv_color32_t bg_color, lv_opa_t bg_opa,
lv_color32_t fg_color, lv_opa_t fg_opa,
lv_color32_t *res_color, lv_opa_t *res_opa)
{
if(fg_opa >= LV_OPA_MAX || bg_opa <= LV_OPA_MIN) {
res_color->full = fg_color.full;
*res_opa = fg_opa;
} else if(fg_opa <= LV_OPA_MIN) {
res_color->full = bg_color.full;
*res_opa = bg_opa;
} else if(bg_opa >= LV_OPA_MAX) {
*res_color = lv_pixel_mix(fg_color, bg_color, fg_opa);
*res_opa = LV_OPA_COVER;
} else {
static lv_opa_t fg_opa_save = 0;
static lv_opa_t bg_opa_save = 0;
static lv_color32_t fg_color_save = _LV_COLOR_ZERO_INITIALIZER32;
static lv_color32_t bg_color_save = _LV_COLOR_ZERO_INITIALIZER32;
static lv_color32_t res_color_saved = _LV_COLOR_ZERO_INITIALIZER32;
static lv_opa_t res_opa_saved = 0;
if(fg_opa != fg_opa_save || bg_opa != bg_opa_save || fg_color.full != fg_color_save.full ||
bg_color.full != bg_color_save.full) {
fg_opa_save = fg_opa;
bg_opa_save = bg_opa;
fg_color_save.full = fg_color.full;
bg_color_save.full = bg_color.full;
res_opa_saved = 255 - ((uint16_t)((uint16_t)(255 - fg_opa) * (255 - bg_opa)) >> 8);
LV_ASSERT(res_opa_saved != 0);
lv_opa_t ratio = (uint16_t)((uint16_t)fg_opa * 255) / res_opa_saved;
res_color_saved = lv_pixel_mix(fg_color, bg_color, ratio);
}
res_color->full = res_color_saved.full;
*res_opa = res_opa_saved;
}
}
static inline void rgb565_to_argb(uint16_t src_pixel, uint32_t* dst_color)
{
unsigned int a, r, g, b;
a = 0xff;
r = ((src_pixel & 0xf800) >> 8);
g = (src_pixel & 0x07e0) >> 3;
b = (src_pixel & 0x1f) << 3;
*dst_color = (a << 24) | ((r | (r >> 5)) << 16) |
((g | (g >> 6)) << 8) | (b | (b >> 5));
}
static void set_pixel_true_color_alpha(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w,
lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa)
{
(void) disp_drv; /*Unused*/
uint8_t *buf_px = buf + (buf_w * y * 4 + x * 4);
lv_color32_t bg_color;
lv_color32_t fg_color;
lv_color32_t res_color;
lv_opa_t bg_opa = buf_px[3];
#if LV_COLOR_DEPTH == 16
rgb565_to_argb((uint16_t)color.full, &fg_color.full);
#else
fg_color.full = color.full;
#endif
bg_color = *((lv_color32_t *)buf_px);
lv_pixel_mix_with_alpha(bg_color, bg_opa, fg_color, opa, &res_color, &buf_px[3]);
if(buf_px[3] <= LV_OPA_MIN) return;
buf_px[0] = res_color.ch.blue;
buf_px[1] = res_color.ch.green;
buf_px[2] = res_color.ch.red;
}
static void lv_disp_drv_set_px_cb(lv_disp_drv_t * disp_drv, lv_img_cf_t cf)
{
switch(cf) {
case LV_IMG_CF_TRUE_COLOR_ALPHA:
disp_drv->set_px_cb = set_pixel_true_color_alpha;
break;
default:
LV_LOG_ERROR("unknown cf:%d", cf);
disp_drv->set_px_cb = NULL;
}
}
static void init_fake_disp(lv_obj_t *canvas, lv_disp_t *disp, lv_disp_drv_t *drv, lv_area_t *clip_area)
{
lv_aic_canvas_t *aic_canvas = (lv_aic_canvas_t *)canvas;
lv_img_dsc_t * dsc = &aic_canvas->dsc;
lv_img_cf_t cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
clip_area->x1 = 0;
clip_area->x2 = dsc->header.w - 1;
clip_area->y1 = 0;
clip_area->y2 = dsc->header.h - 1;
lv_memset_00(disp, sizeof(lv_disp_t));
disp->driver = drv;
lv_disp_drv_init(disp->driver);
disp->driver->hor_res = dsc->header.w;
disp->driver->ver_res = dsc->header.h;
lv_draw_ctx_t * draw_ctx = lv_mem_alloc(sizeof(lv_draw_sw_ctx_t));
LV_ASSERT_MALLOC(draw_ctx);
if(draw_ctx == NULL) return;
lv_draw_sw_init_ctx(drv, draw_ctx);
disp->driver->draw_ctx = draw_ctx;
draw_ctx->clip_area = clip_area;
draw_ctx->buf_area = clip_area;
if (aic_canvas->img_buf) {
if (dsc->header.cf == LV_IMG_CF_RESERVED_16)
draw_ctx->buf = (void *)((unsigned long)(aic_canvas->img_buf->buf.phy_addr[0]));
else
draw_ctx->buf = (void *)dsc->data;
} else {
return;
}
cf = aic_canvas->img.cf;
lv_disp_drv_set_px_cb(disp->driver, cf);
}
static void deinit_fake_disp(lv_obj_t *canvas, lv_disp_t *disp)
{
LV_UNUSED(canvas);
lv_draw_sw_deinit_ctx(disp->driver, disp->driver->draw_ctx);
lv_mem_free(disp->driver->draw_ctx);
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2024, ArtInChip Technology Co., Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Authors: Ning Fang <ning.fang@artinchip.com>
*/
#ifndef LV_AIC_CANVAS_H
#define LV_AIC_CANVAS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "lv_obj.h"
#include "lv_img.h"
#include "lv_draw_img.h"
#include "canvas_image.h"
extern const lv_obj_class_t lv_aic_canvas_class;
typedef struct {
lv_img_t img;
lv_img_dsc_t dsc;
struct lv_mpp_buf *img_buf;
} lv_aic_canvas_t;
lv_obj_t *lv_aic_canvas_create(lv_obj_t *parent);
lv_res_t lv_aic_canvas_alloc_buffer(lv_obj_t *obj, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf);
void lv_aic_canvas_draw_text(lv_obj_t *obj, lv_coord_t x, lv_coord_t y, lv_coord_t max_w,
lv_draw_label_dsc_t * draw_dsc, const char *txt);
void lv_aic_canvas_draw_text_to_center(lv_obj_t *obj, lv_draw_label_dsc_t *label_dsc, const char *txt);
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_AIC_CANVAS_H*/

View File

@@ -0,0 +1,17 @@
from building import *
import os
cwd = GetCurrentDir()
group = []
src = Glob('*.c')
CPPPATH = [cwd]
list = os.listdir(cwd)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
group = group + SConscript(os.path.join(d, 'SConscript'))
group = group + DefineGroup('LVGL-port', src, depend = ['LPKG_USING_LVGL'], CPPPATH = CPPPATH)
Return('group')

View File

@@ -0,0 +1,502 @@
#include "aic_lv_ffmpeg.h"
#if LV_USE_FFMPEG == 0 && defined(AIC_MPP_PLAYER_INTERFACE)
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#define MY_CLASS &lv_aic_player_class
struct ffmpeg_context_s {
struct aic_player *aic_player;
struct av_media_info media_info;
int play_end;
int play_async;
int play_detected;
};
#define FRAME_DEF_REFR_PERIOD 33 /*[ms]*/
static void lv_ffmpeg_player_get_disp_area(lv_obj_t *obj, lv_point_t *pos,
lv_coord_t *width, lv_coord_t *height, lv_coord_t *rotation);
static void lv_ffmpeg_player_set_disp_area(lv_obj_t *obj, lv_point_t pos,
lv_coord_t width, lv_coord_t height, lv_coord_t rotation);
static void lv_ffmpeg_player_protect_disp_area(lv_obj_t *obj, lv_point_t *pos,
lv_coord_t *width, lv_coord_t *height, lv_coord_t *rotation);
static void lv_ffmpeg_player_frame_update_cb(lv_timer_t * timer);
static void lv_ffmpeg_player_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void lv_ffmpeg_player_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static int aic_event_handle(void *app_data, int event, int data1, int data2)
{
int ret = 0;
struct ffmpeg_context_s *ffmpeg_ctx = (struct ffmpeg_context_s *)app_data;
switch(event) {
case AIC_PLAYER_EVENT_PLAY_END:
ffmpeg_ctx->play_end = 1;
break;
case AIC_PLAYER_EVENT_PLAY_TIME:
break;
case AIC_PLAYER_EVENT_DEMUXER_FORMAT_DETECTED:
ffmpeg_ctx->play_detected = 1;
break;
case AIC_PLAYER_EVENT_DEMUXER_FORMAT_NOT_DETECTED:
break;
default:
break;
}
return ret;
}
const lv_obj_class_t lv_aic_player_class = {
.constructor_cb = lv_ffmpeg_player_constructor,
.destructor_cb = lv_ffmpeg_player_destructor,
.instance_size = sizeof(lv_ffmpeg_player_t),
.base_class = &lv_img_class
};
void lv_ffmpeg_init(void)
{
return;
}
int lv_ffmpeg_get_frame_num(const char * path)
{
int ret = -1;
return ret;
}
lv_obj_t * lv_ffmpeg_player_create(lv_obj_t * parent)
{
lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
lv_obj_class_init_obj(obj);
return obj;
}
lv_res_t lv_ffmpeg_player_set_src(lv_obj_t * obj, const char *path)
{
lv_res_t res = LV_RES_INV;
char fake_image_name[128] = {0};
struct ffmpeg_context_s *ffmpeg_ctx;
lv_ffmpeg_player_t *player = (lv_ffmpeg_player_t *)obj;
lv_point_t pos;
lv_coord_t width, height, rotation;
if (!player->ffmpeg_ctx) {
player->ffmpeg_ctx = calloc(1, sizeof(struct ffmpeg_context_s));
if(player->ffmpeg_ctx == NULL) {
LV_LOG_ERROR("ffmpeg_ctx malloc failed");
goto failed;
}
}
ffmpeg_ctx = player->ffmpeg_ctx;
if (!ffmpeg_ctx->aic_player) {
ffmpeg_ctx->aic_player = aic_player_create((char *)path);
if (!ffmpeg_ctx->aic_player) {
LV_LOG_ERROR("create aic player failed: %s", path);
goto failed;
}
aic_player_set_event_callback(ffmpeg_ctx->aic_player, ffmpeg_ctx, aic_event_handle);
} else {
aic_player_stop(ffmpeg_ctx->aic_player);
}
lv_timer_pause(player->timer);
aic_player_set_uri(ffmpeg_ctx->aic_player, (char *)path);
ffmpeg_ctx->play_detected = 0;
if (ffmpeg_ctx->play_async == 0) {
res = aic_player_prepare_sync(ffmpeg_ctx->aic_player);
} else {
res = aic_player_prepare_async(ffmpeg_ctx->aic_player);
}
if (res) {
LV_LOG_ERROR("aic_player_prepare failed");
goto failed;
}
res = aic_player_get_media_info(ffmpeg_ctx->aic_player,
&ffmpeg_ctx->media_info);
if (res != 0) {
LV_LOG_ERROR("aic_player_get_media_info failed");
goto failed;
}
/* update the obj before redraw */
lv_obj_update_layout(obj);
player->imgdsc.header.w = ffmpeg_ctx->media_info.video_stream.width;
player->imgdsc.header.h = ffmpeg_ctx->media_info.video_stream.height;
ffmpeg_ctx->play_end = 0;
if (ffmpeg_ctx->media_info.has_audio == 1 && ffmpeg_ctx->media_info.has_video == 0) {
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN); /* audio did't not disp */
lv_timer_resume(player->timer);
return LV_RES_OK;
}
lv_ffmpeg_player_get_disp_area(obj, &pos, &width, &height, &rotation);
if (width == 0 && height == 0) {
width = player->imgdsc.header.w;
height = player->imgdsc.header.h;
}
snprintf(fake_image_name, 128, "L:/%dx%d_%d_%08x.fake",
width, height, 0, 0x00000000);
lv_img_set_src(&player->img.obj, fake_image_name);
if (width == 0 && height == 0) {
width = player->imgdsc.header.w;
height = player->imgdsc.header.h;
}
lv_ffmpeg_player_protect_disp_area(obj, &pos, &width, &height, &rotation);
if (ffmpeg_ctx->play_async == 0)
lv_ffmpeg_player_set_disp_area(obj , pos, width, height, rotation);
lv_timer_resume(player->timer);
return LV_RES_OK;
failed:
return LV_RES_INV;
}
void lv_ffmpeg_player_set_cmd(lv_obj_t * obj, lv_ffmpeg_player_cmd_t cmd)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_ffmpeg_player_t * player = (lv_ffmpeg_player_t *)obj;
struct ffmpeg_context_s *ffmpeg_ctx;
int ret;
if(!player->ffmpeg_ctx) {
LV_LOG_ERROR("ffmpeg_ctx is NULL");
return;
}
ffmpeg_ctx = player->ffmpeg_ctx;
if (!ffmpeg_ctx->aic_player) {
LV_LOG_ERROR("aic_player is NULL ");
return;
}
switch(cmd) {
case LV_FFMPEG_PLAYER_CMD_START:
ret = aic_player_start(ffmpeg_ctx->aic_player);
if (ret != 0) {
LV_LOG_ERROR("aic_player_start failed");
break;
}
LV_LOG_INFO("aic player start");
break;
case LV_FFMPEG_PLAYER_CMD_STOP:
ret = aic_player_stop(ffmpeg_ctx->aic_player);
if (ret != 0) {
LV_LOG_ERROR("aic_player_stop failed");
break;
}
LV_LOG_INFO("aic player stop");
break;
case LV_FFMPEG_PLAYER_CMD_PAUSE:
ret = aic_player_pause(ffmpeg_ctx->aic_player);
if (ret != 0) {
LV_LOG_ERROR("aic_player_pause failed");
break;
}
LV_LOG_INFO("aic player pause");
break;
case LV_FFMPEG_PLAYER_CMD_RESUME:
ret = aic_player_play(ffmpeg_ctx->aic_player);
if (ret != 0) {
LV_LOG_ERROR("aic_player_start failed");
break;
}
LV_LOG_INFO("aic player resume");
break;
default:
LV_LOG_ERROR("Error cmd: %d", cmd);
break;
}
}
void lv_ffmpeg_player_set_cmd_ex(lv_obj_t * obj, lv_ffmpeg_player_cmd_t cmd, void *data)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_ffmpeg_player_t * player = (lv_ffmpeg_player_t *)obj;
struct ffmpeg_context_s *ffmpeg_ctx;
int ret;
bool *end = (bool *)data;
struct av_media_info *media_info = (struct av_media_info *)data;
s32 *set_vol = (s32 *)data;
s32 *get_vol = (s32 *)data;
u64 *seek = (u64 *)data;
if(!player->ffmpeg_ctx) {
LV_LOG_ERROR("ffmpeg_ctx is NULL");
return;
}
ffmpeg_ctx = player->ffmpeg_ctx;
if (!ffmpeg_ctx->aic_player) {
LV_LOG_ERROR("aic_player is NULL ");
return;
}
switch(cmd) {
case LV_FFMPEG_PLAYER_CMD_START:
case LV_FFMPEG_PLAYER_CMD_STOP:
case LV_FFMPEG_PLAYER_CMD_PAUSE:
case LV_FFMPEG_PLAYER_CMD_RESUME:
lv_ffmpeg_player_set_cmd(obj, cmd);
break;
case LV_FFMPEG_PLAYER_CMD_PLAY_END_EX:
*end = ffmpeg_ctx->play_end == 1 ? true : false;
break;
case LV_FFMPEG_PLAYER_CMD_GET_MEDIA_INFO_EX:
memcpy(media_info, &ffmpeg_ctx->media_info, sizeof(struct av_media_info));
break;
case LV_FFMPEG_PLAYER_CMD_SET_VOLUME_EX:
ret = aic_player_set_volum(ffmpeg_ctx->aic_player, *set_vol);
if (ret != 0) {
LV_LOG_ERROR("aic_player_set_volum failed");
break;
}
break;
case LV_FFMPEG_PLAYER_CMD_GET_VOLUME_EX:
ret = aic_player_get_volum(ffmpeg_ctx->aic_player, get_vol);
if (ret != 0) {
LV_LOG_ERROR("aic_player_get_volum failed");
break;
}
break;
case LV_FFMPEG_PLAYER_CMD_SET_PLAY_TIME_EX:
ffmpeg_ctx->play_end = 0;
ret = aic_player_seek(ffmpeg_ctx->aic_player, *seek);
if (ret != 0) {
LV_LOG_ERROR("aic_player_seek failed");
break;
}
break;
case LV_FFMPEG_PLAYER_CMD_GET_PLAY_TIME_EX:
if (ffmpeg_ctx->play_end == 1) {
*seek = ffmpeg_ctx->media_info.duration;
return;
}
*seek = aic_player_get_play_time(ffmpeg_ctx->aic_player);
if (*seek < 0) {
LV_LOG_ERROR("aic_player_get_play_time failed");
break;
}
break;
#ifdef PLAYER_ASYNC
/* async src is not currently supported */
case LV_FFMPEG_PLAYER_CMD_SET_SRC_ASYNC:
ffmpeg_ctx->play_async = 1;
break;
case LV_FFMPEG_PLAYER_WAIT_SRC_ASYNC:
while(ffmpeg_ctx->play_detected == 0) {
rt_thread_mdelay(5);
}
lv_timer_ready(player->timer);
break;
#endif
default:
LV_LOG_ERROR("Error cmd: %d", cmd);
break;
}
}
void lv_ffmpeg_player_set_auto_restart(lv_obj_t * obj, bool en)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_ffmpeg_player_t * player = (lv_ffmpeg_player_t *)obj;
player->auto_restart = en;
}
static void lv_ffmpeg_player_frame_update_cb(lv_timer_t * timer)
{
lv_obj_t * obj = (lv_obj_t *)timer->user_data;
lv_ffmpeg_player_t * player = (lv_ffmpeg_player_t *)obj;
struct ffmpeg_context_s *ffmpeg_ctx;
static lv_point_t point, last_point;
static lv_coord_t rotation, last_rotation;
static lv_coord_t width, last_width;
static lv_coord_t height, last_height;
ffmpeg_ctx = player->ffmpeg_ctx;
if(!ffmpeg_ctx) {
return;
}
if (!ffmpeg_ctx->aic_player) {
return;
}
if (ffmpeg_ctx->media_info.has_audio == 1 && ffmpeg_ctx->media_info.has_video == 0) {
goto update_cb_out;
}
lv_ffmpeg_player_get_disp_area(obj, &point, &width, &height, &rotation);
if (rotation != 90 || rotation != 180 || rotation != 270) {
LV_LOG_ERROR("aic_player only supported rotation angles, 90, 180, 270\n");
LV_LOG_ERROR("obj default rotation angle is set to 0\n");
lv_obj_set_style_transform_angle(obj, 0, LV_PART_MAIN);
goto update_cb_out;
}
/* avoid repeatedly setting in callback functions */
if (last_point.x != point.x || last_point.y != point.y ||
last_width != width || last_height != height ||
last_rotation != rotation) {
lv_ffmpeg_player_protect_disp_area(obj, &point, &width, &height, &rotation);
lv_ffmpeg_player_set_disp_area(obj, point, width, height, rotation);
last_point.x = point.x;
last_point.y = point.y;
last_height = height;
last_width = width;
last_rotation = rotation;
}
update_cb_out:
if (player->auto_restart && ffmpeg_ctx->play_end) {
ffmpeg_ctx->play_end = 0;
aic_player_seek(ffmpeg_ctx->aic_player, 0);
LV_LOG_INFO("auto_restart");
}
}
static void lv_ffmpeg_player_get_disp_area(lv_obj_t *obj, lv_point_t *pos,
lv_coord_t *width, lv_coord_t *height, lv_coord_t *rotation)
{
lv_area_t coords;
lv_obj_get_coords(obj, &coords);
*width = lv_obj_get_style_width(obj, 0);
*height = lv_obj_get_style_height(obj, 0);
pos->x = coords.x1;
pos->y = coords.y1;
*rotation = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
}
static void lv_ffmpeg_player_set_disp_area(lv_obj_t *obj, lv_point_t pos,
lv_coord_t width, lv_coord_t height, lv_coord_t rotation)
{
lv_ffmpeg_player_t *player = (lv_ffmpeg_player_t *)obj;
struct ffmpeg_context_s *ffmpeg_ctx = player->ffmpeg_ctx;
lv_obj_t *mask_img = &player->img.obj;
struct mpp_rect disp_rect = {0};
u32 mpp_rotation = MPP_ROTATION_0;
int ret = -1;
char fake_image_name[128] = {0};
snprintf(fake_image_name, 128, "L:/%dx%d_%d_%08x.fake",
width, height, 0, 0x00000000);
/* use fake image to change the transparency of the relevant ui layer to 0,
* so that the video player can not be affected.
*/
lv_img_set_src(mask_img, fake_image_name);
disp_rect.x = pos.x;
disp_rect.y = pos.y;
disp_rect.width = width;
disp_rect.height = height;
ret = aic_player_set_disp_rect(ffmpeg_ctx->aic_player, &disp_rect);
if (ret != 0) {
LV_LOG_ERROR("aic_player_set_disp_rect failed");
}
if (rotation == 90)
mpp_rotation = MPP_ROTATION_90;
if (rotation == 180)
mpp_rotation = MPP_ROTATION_180;
if (rotation == 270)
mpp_rotation = MPP_ROTATION_270;
ret = aic_player_set_rotation(ffmpeg_ctx->aic_player, mpp_rotation);
if (ret != 0) {
LV_LOG_ERROR("aic_player_set_rotation failed");
}
}
static void lv_ffmpeg_player_protect_disp_area(lv_obj_t *obj, lv_point_t *pos,
lv_coord_t *width, lv_coord_t *height, lv_coord_t *rotation)
{
if (pos->x > LV_HOR_RES) {
pos->x = LV_HOR_RES;
LV_LOG_ERROR("lv obj pos x too large!");
}
if (pos->y > LV_VER_RES) {
pos->y = LV_VER_RES;
LV_LOG_ERROR("lv obj pos y too large!");
}
if (pos->x + *width > LV_HOR_RES) {
*width = (LV_HOR_RES - pos->x);
LV_LOG_ERROR("lv obj width too large!");
}
if (pos->y + *height > LV_VER_RES) {
*height = (LV_HOR_RES - pos->y);
LV_LOG_ERROR("lv obj height too large!");
}
}
static void lv_ffmpeg_player_constructor(const lv_obj_class_t * class_p,
lv_obj_t * obj)
{
LV_TRACE_OBJ_CREATE("begin");
lv_ffmpeg_player_t * player = (lv_ffmpeg_player_t *)obj;
player->auto_restart = false;
player->ffmpeg_ctx = NULL;
player->timer = lv_timer_create(lv_ffmpeg_player_frame_update_cb,
FRAME_DEF_REFR_PERIOD, obj);
lv_timer_pause(player->timer);
LV_TRACE_OBJ_CREATE("finished");
}
static void lv_ffmpeg_player_destructor(const lv_obj_class_t * class_p,
lv_obj_t * obj)
{
LV_TRACE_OBJ_CREATE("begin");
lv_ffmpeg_player_t * player = (lv_ffmpeg_player_t *)obj;
if(player->timer) {
lv_timer_del(player->timer);
player->timer = NULL;
}
if(player->ffmpeg_ctx) {
struct ffmpeg_context_s *ffmpeg_ctx;
ffmpeg_ctx = player->ffmpeg_ctx;
if (ffmpeg_ctx->aic_player) {
aic_player_stop(ffmpeg_ctx->aic_player);
aic_player_destroy(ffmpeg_ctx->aic_player);
ffmpeg_ctx->aic_player = NULL;
}
free(player->ffmpeg_ctx);
player->ffmpeg_ctx = NULL;
}
LV_TRACE_OBJ_CREATE("finished");
}
#endif /*NO LV_USE_FFMPEG*/

View File

@@ -0,0 +1,132 @@
/**
* lv__ffmpeg is compatible with the following formats on the luban and luban-lite platforms:
*
* Container Format: Supports MP4 container, mjpeg(D13x), H264(D21x) raw stream, and MP3 container.
*
* Transport Protocol: Supports local files.
*
* Video Decoding: Supports mjpeg(D13x), H264(D21x).
* Audio Decoding: Supports MP3 and AAC.
* This is because ffmpeg is implemented to interface with aic_player, so it only supports formats that are supported by aic_player.
*
*/
/**
* @file aic_lv_ffmpeg.h
*
*/
#ifndef LV_AIC_FFMPEG_H
#define LV_AIC_FFMPEG_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lvgl.h"
#if LV_USE_FFMPEG == 0 && defined(AIC_MPP_PLAYER_INTERFACE)
#include "aic_player.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
struct ffmpeg_context_s;
extern const lv_obj_class_t lv_ffmpeg_player_class;
typedef struct {
lv_img_t img;
lv_timer_t * timer;
lv_img_dsc_t imgdsc;
bool auto_restart;
struct ffmpeg_context_s * ffmpeg_ctx;
} lv_ffmpeg_player_t;
typedef enum {
LV_FFMPEG_PLAYER_CMD_START,
LV_FFMPEG_PLAYER_CMD_STOP,
LV_FFMPEG_PLAYER_CMD_PAUSE,
LV_FFMPEG_PLAYER_CMD_RESUME,
/* the following extension commands are only supported by aic */
LV_FFMPEG_PLAYER_CMD_PLAY_END_EX, /* data type is bool * */
LV_FFMPEG_PLAYER_CMD_GET_MEDIA_INFO_EX, /* data type is struct av_media_info * */
LV_FFMPEG_PLAYER_CMD_SET_VOLUME_EX, /* data type is s32 *, rang: 0 ~ 100 */
LV_FFMPEG_PLAYER_CMD_GET_VOLUME_EX, /* data type is s32 *, rang: 0 ~ 100 */
LV_FFMPEG_PLAYER_CMD_SET_PLAY_TIME_EX, /* data type is u64 *, unite: microsecond */
LV_FFMPEG_PLAYER_CMD_GET_PLAY_TIME_EX, /* data type is u64 *, unite: microsecond */
_LV_FFMPEG_PLAYER_CMD_LAST
} lv_ffmpeg_player_cmd_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Register FFMPEG image decoder
*/
void lv_ffmpeg_init(void);
/**
* Get the number of frames contained in the file
* @param path image or video file name
* @return Number of frames, less than 0 means failed
*/
int lv_ffmpeg_get_frame_num(const char * path);
/**
* Create ffmpeg_player object
* @param parent pointer to an object, it will be the parent of the new player
* @return pointer to the created ffmpeg_player
*/
lv_obj_t * lv_ffmpeg_player_create(lv_obj_t * parent);
/**
* Set the path of the file to be played
* @param obj pointer to a ffmpeg_player object
* @param path video file path
* @return LV_RES_OK: no error; LV_RES_INV: can't get the info.
*/
lv_res_t lv_ffmpeg_player_set_src(lv_obj_t * obj, const char * path);
/**
* Set command control video player
* @param obj pointer to a ffmpeg_player object
* @param cmd control commands
*/
void lv_ffmpeg_player_set_cmd(lv_obj_t * obj, lv_ffmpeg_player_cmd_t cmd);
/**
* Set the video to automatically replay
* @param obj pointer to a ffmpeg_player object
* @param en true: enable the auto restart
*/
void lv_ffmpeg_player_set_auto_restart(lv_obj_t * obj, bool en);
/*=====================
* Expansion functions
*====================*/
/**
* Set command control video player, expansion commands can be used
* @param obj pointer to a ffmpeg_player object
* @param cmd control commands
* @param data set or read data
*/
void lv_ffmpeg_player_set_cmd_ex(lv_obj_t * obj, lv_ffmpeg_player_cmd_t cmd, void *data);
/**********************
* MACROS
**********************/
#endif /*LV_USE_FFMPEG*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_AIC_FFMPEG_H*/