mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-28 07:03:00 +08:00
278 lines
9.1 KiB
ReStructuredText
278 lines
9.1 KiB
ReStructuredText
=============
|
||
Lottie player
|
||
=============
|
||
|
||
Allows to use Lottie animations in LVGL. Taken from this `base repository <https://github.com/ValentiWorkLearning/lv_rlottie>`__
|
||
|
||
LVGL provides the interface to `Samsung/rlottie <https://github.com/Samsung/rlottie>`__ library's C
|
||
API. That is the actual Lottie player is not part of LVGL, it needs to
|
||
be built separately.
|
||
|
||
Build Rlottie
|
||
-------------
|
||
|
||
To build Samsung's Rlottie C++14-compatible compiler and optionally
|
||
CMake 3.14 or higher is required.
|
||
|
||
To build on desktop you can follow the instructions from Rlottie's
|
||
`README <https://github.com/Samsung/rlottie/blob/master/README.md>`__.
|
||
In the most basic case it looks like this:
|
||
|
||
.. code:: shell
|
||
|
||
mkdir rlottie_workdir
|
||
cd rlottie_workdir
|
||
git clone https://github.com/Samsung/rlottie.git
|
||
mkdir build
|
||
cd build
|
||
cmake ../rlottie
|
||
make -j
|
||
sudo make install
|
||
|
||
And finally add the ``-lrlottie`` flag to your linker.
|
||
|
||
On embedded systems you need to take care of integrating Rlottie to the
|
||
given build system.
|
||
|
||
ESP-IDF example at bottom
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Usage
|
||
-----
|
||
|
||
You can use animation from files or raw data (text). In either case
|
||
first you need to enable :c:macro:`LV_USE_RLOTTIE` in ``lv_conf.h``.
|
||
|
||
The ``width`` and ``height`` of the object be set in the *create*
|
||
function and the animation will be scaled accordingly.
|
||
|
||
Use Rlottie from file
|
||
~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
To create a Lottie animation from file use:
|
||
|
||
.. code:: c
|
||
|
||
lv_obj_t * lottie = lv_rlottie_create_from_file(parent, width, height, "path/to/lottie.json");
|
||
|
||
Note that, Rlottie uses the standard STDIO C file API, so you can use
|
||
the path “normally” and no LVGL specific driver letter is required.
|
||
|
||
Use Rlottie from raw string data
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
``lv_example_rlottie_approve.c`` contains an example animation in raw
|
||
format. Instead storing the JSON string a hex array is stored for the
|
||
following reasons: - avoid escaping ``"`` in the JSON file - some
|
||
compilers don't support very long strings
|
||
|
||
``lvgl/scripts/filetohex.py`` can be used to convert a Lottie file a hex
|
||
array. E.g.:
|
||
|
||
.. code:: shell
|
||
|
||
./filetohex.py path/to/lottie.json > out.txt
|
||
|
||
To create an animation from raw data:
|
||
|
||
.. code:: c
|
||
|
||
extern const uint8_t lottie_data[];
|
||
lv_obj_t* lottie = lv_rlottie_create_from_raw(parent, width, height, (const char *)lottie_data);
|
||
|
||
Getting animations
|
||
------------------
|
||
|
||
Lottie is standard and popular format so you can find many animation
|
||
files on the web. For example: https://lottiefiles.com/
|
||
|
||
You can also create your own animations with Adobe After Effects or
|
||
similar software.
|
||
|
||
Controlling animations
|
||
----------------------
|
||
|
||
LVGL provides two functions to control the animation mode:
|
||
:c:func:`lv_rlottie_set_play_mode` and :c:func:`lv_rlottie_set_current_frame`.
|
||
You'll combine your intentions when calling the first method, like in
|
||
these examples:
|
||
|
||
.. code:: c
|
||
|
||
lv_obj_t * lottie = lv_rlottie_create_from_file(scr, 128, 128, "test.json");
|
||
lv_obj_center(lottie);
|
||
// Pause to a specific frame
|
||
lv_rlottie_set_current_frame(lottie, 50);
|
||
lv_rlottie_set_play_mode(lottie, LV_RLOTTIE_CTRL_PAUSE); // The specified frame will be displayed and then the animation will pause
|
||
|
||
// Play backward and loop
|
||
lv_rlottie_set_play_mode(lottie, LV_RLOTTIE_CTRL_PLAY | LV_RLOTTIE_CTRL_BACKWARD | LV_RLOTTIE_CTRL_LOOP);
|
||
|
||
// Play forward once (no looping)
|
||
lv_rlottie_set_play_mode(lottie, LV_RLOTTIE_CTRL_PLAY | LV_RLOTTIE_CTRL_FORWARD);
|
||
|
||
The default animation mode is **play forward with loop**.
|
||
|
||
If you don't enable looping, a :c:enumerator:`LV_EVENT_READY` is sent when the
|
||
animation can not make more progress without looping.
|
||
|
||
To get the number of frames in an animation or the current frame index,
|
||
you can cast the :c:struct:`lv_obj_t` instance to a :c:struct:`lv_rlottie_t` instance
|
||
and inspect the ``current_frame`` and ``total_frames`` members.
|
||
|
||
ESP-IDF Example
|
||
---------------
|
||
|
||
Background
|
||
~~~~~~~~~~
|
||
|
||
Rlottie can be expensive to render on embedded hardware. Lottie
|
||
animations tend to use a large amount of CPU time and can use large
|
||
portions of RAM. This will vary from lottie to lottie but in general for
|
||
best performance: \* Limit total # of frames in the animation \* Where
|
||
possible, try to avoid bezier type animations \* Limit animation render
|
||
size
|
||
|
||
If your ESP32 chip does not have SPIRAM you will face severe limitations
|
||
in render size.
|
||
|
||
To give a better idea on this, lets assume you want to render a 240x320
|
||
lottie animation.
|
||
|
||
In order to pass initialization of the lv_rlottie_t object, you need
|
||
240x320x32/8 (307k) available memory. The latest ESP32-S3 has 256kb RAM
|
||
available for this (before freeRtos and any other initialization starts
|
||
taking chunks out). So while you can probably start to render a 50x50
|
||
animation without SPIRAM, PSRAM is highly recommended.
|
||
|
||
Additionally, while you might be able to pass initialization of the
|
||
lv_rlottie_t object, as rlottie renders frame to frame, this consumes
|
||
additional memory. A 30 frame animation that plays over 1 second
|
||
probably has minimal issues, but a 300 frame animation playing over 10
|
||
seconds could very easily crash due to lack of memory as rlottie
|
||
renders, depending on the complexity of the animation.
|
||
|
||
Rlottie will not compile for the IDF using the -02 compiler option at
|
||
this time.
|
||
|
||
For stability in lottie animations, I found that they run best in the
|
||
IDF when enabling :c:macro:`LV_MEM_CUSTOM` (using stdlib.h)
|
||
|
||
For all its faults, when running right-sized animations, they provide a
|
||
wonderful utility to LVGL on embedded LCDs and can look really good when
|
||
done properly.
|
||
|
||
When picking/designing a lottie animation consider the following
|
||
limitations: - Build the lottie animation to be sized for the intended
|
||
size - it can scale/resize, but performance will be best when the base
|
||
lottie size is as intended - Limit total number of frames, the longer
|
||
the lottie animation is, the more memory it will consume for rendering
|
||
(rlottie consumes IRAM for rendering) - Build the lottie animation for
|
||
the intended frame rate - default lottie is 60fps, embedded LCDs likely
|
||
wont go above 30fps
|
||
|
||
IDF Setup
|
||
~~~~~~~~~
|
||
|
||
Where the LVGL simulator uses the installed rlottie lib, the IDF works
|
||
best when using rlottie as a submodule under the components directory.
|
||
|
||
.. code:: shell
|
||
|
||
cd 'your/project/directory'
|
||
git add submodule
|
||
git add submodule https://github.com/Samsung/rlottie.git ./components/rlottie/rlottie
|
||
git submodule update --init --recursive
|
||
|
||
Now, Rlottie is available as a component in the IDF, but it requires
|
||
some additional changes and a CMakeLists file to tell the IDF how to
|
||
compile.
|
||
|
||
Rlottie patch file
|
||
~~~~~~~~~~~~~~~~~~
|
||
|
||
Rlottie relies on a dynamic linking for an image loader lib. This needs
|
||
to be disabled as the IDF doesn't play nice with dynamic linking.
|
||
|
||
A patch file is available in lvgl uner:
|
||
``/env_support/esp/rlottie/0001-changes-to-compile-with-esp-idf.patch``
|
||
|
||
Apply the patch file to your rlottie submodule.
|
||
|
||
CMakeLists for IDF
|
||
~~~~~~~~~~~~~~~~~~
|
||
|
||
An example CMakeLists file has been provided at
|
||
``/env_support/esp/rlottie/CMakeLists.txt``
|
||
|
||
Copy this CMakeLists file to
|
||
``‘your-project-directory'/components/rlottie/``
|
||
|
||
In addition to the component CMakeLists file, you'll also need to tell
|
||
your project level CMakeLists in your IDF project to require rlottie:
|
||
|
||
.. code:: console
|
||
|
||
REQUIRES "lvgl" "rlottie"
|
||
|
||
From here, you should be able to use lv_rlottie objects in your ESP-IDF
|
||
project as any other widget in LVGL ESP examples. Please remember that
|
||
these animations can be highly resource constrained and this does not
|
||
guarantee that every animation will work.
|
||
|
||
Additional Rlottie considerations in ESP-IDF
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
While unecessary, removing the ``rlottie/rlottie/example`` folder can remove
|
||
many un-needed files for this embedded LVGL application
|
||
|
||
From here, you can use the relevant LVGL lv_rlottie functions to create
|
||
lottie animations in LVGL on embedded hardware!
|
||
|
||
Please note, that while lottie animations are capable of running on many
|
||
ESP chips, below is recommended for best performance.
|
||
|
||
- ESP32-S3-WROOM-1-N16R8
|
||
|
||
- 16mb quad spi flash
|
||
- 8mb octal spi PSRAM
|
||
|
||
- IDF4.4 or higher
|
||
|
||
The Esp-box devkit meets this spec and
|
||
https://github.com/espressif/esp-box is a great starting point to adding
|
||
lottie animations.
|
||
|
||
you'll need to enable:c:macro:`LV_USE_RLOTTIE` through idf.py menuconfig under
|
||
LVGL component settings.
|
||
|
||
Additional changes to make use of SPIRAM
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
lv_alloc/realloc do not make use of SPIRAM. Given the high memory usage
|
||
of lottie animations, it is recommended to shift as much out of internal
|
||
DRAM into SPIRAM as possible. In order to do so, SPIRAM will need to be
|
||
enabled in the menuconfig options for your given espressif chip.
|
||
|
||
There may be a better solution for this, but for the moment the
|
||
recommendation is to make local modifications to the lvgl component in
|
||
your espressif project. This is as simple as swapping
|
||
lv_alloc/lv_realloc calls in lv_rlottie.c with heap_caps_malloc (for
|
||
IDF) with the appropriate :c:expr:`MALLOC_CAP` call - for SPIRAM usage this is
|
||
:c:expr:`MALLOC_CAP_SPIRAM`.
|
||
|
||
.. code:: c
|
||
|
||
rlottie->allocated_buf = heap_caps_malloc(allocaled_buf_size+1, MALLOC_CAP_SPIRAM);
|
||
|
||
Example
|
||
-------
|
||
|
||
.. include:: ../examples/libs/rlottie/index.rst
|
||
|
||
|
||
API
|
||
---
|
||
|
||
:ref:`lv_rlottie`
|