[杂项] rlottie
前言
面向用户的企业级产品,UI 和交互会直接影响到用户的体验:鼠标交互可以附加 UI 的 hover
, pressed
状态; 对于持续的状态 (Download, Uninstall, Update), 则可以考虑在功能入口引入 GIF 。下图是博主随意截取的 GIF (Sam Smith)
预备知识
Concurrency In Action: single-producer, single-consumer
Lock-free concurrent data structure:
lock-free data structures rely on the use of atomic operations and the associated memory-ordering guarantees in order to ensure that data becomes visible to other threads in the correct order.
Guildllines:
- use
std::memory_order_seq_cst
for prototyping - use a lock-free memory reclamation scheme
- simplify it to the context:
- only one thread calling
push()
at a time - only one thread calling
pop()
at a time
- only one thread calling
- watch out for the ABA problem
- identify busy-wait loops and help the other thread
- use
-
A lottie is JSON-based animation file format that allows you to ship animations on any playform as easily as shipping static assets.
Parse Lottie:
- LottieAnimation: a bodymovin player for Qt
- rlottie: a platform independent standalone c++ library for rendering vector based animations and art IN REALTIME
Tips on rlottie:
- render mode: synchronize (
rendersync
) and asynchronzie (render
) - cache policy: load from data with corresponding key to distinguish different cache
- render mode: synchronize (
简介
客户端中使用动画的业务场景大致相同, 如下范式可供参考:
本博主负责的 AR 直播 (1080p59.94) 项目中使用过类似范式: 16.6ms 内使用最少的 cpu 时间处理 4 路输出, 而每路每帧的 1080p 图片
copy
耗时 3ms 左右哦.
- desigen structure:
- 设计 单生产单消费者 数据结构:
lock_free_queue
- 分析业务场景并简化之,以适用于
lock_free_queue
- 设计 单生产单消费者 数据结构:
- request render:
- 通过异步接口
render()
请求渲染一帧图片,并得到对应的future
对象. - 将
future
对象存至对应的lock_free_queue
:render_queue
- 通过异步接口
- process request: 遍历所有
render_queue
中的所有future
对象 (得益于良好的数据结构,业务逻辑无需锁)
准备阶段
本阶段就是要设计 (拿来主义) 对应的 无锁 数据结构啦, 一切从简, 就简单贴出标准的接口.
1 |
|
代码实现
本阶段仅仅列出 rlottie
接口相关的内容.
预备知识 和 简介 是理论和实践经验的陈述. 其中涉及的异步处理框架, 需要根据项目的业务场景和采用的设计模式 (MVC, MVVM) 进行定制.
- parseLottie:
lottie
初始化, 包括: Animation, Surface 对象的构造, 堆内存分配1
2
3
4
5
6
7
8
9
10
11void parseLottie(std::string lottie_file)
{
// load data
auto lottieData = util::loadFromFile(lottie_file); // load lottie.json file from lottie_file
// parse lottie and contruct `Animation`
lottieAnimation = Animation::loadFromData(lottieData, lottie_file); // ****key: lottie_file****
// alloc 1 frame buffer and construct `Surface`
size_t bytesPerLine = cols * sizeof(unint32_t); // row bytes to iterate
auto lottieBuffer = (uint32_t*)malloc(bytesPerline * rows);
lottieSurface = Surface(lottieBuffer, cols, rows, bytesPerline);
} - requestRender: 以
lottie
动画的帧率, 调用该接口完成 1 次异步渲染请求1
2
3
4
5
6
7void requestRender()
{
auto future = lottieAnimation->render(currentFrame, lottieSurface, true);
currentFrame = (currentFrame + 1) % lottieAnimation->totalFrame();
// lock-free queue
lottieQueue->push(std::make_pair(key_to_index, future));
}
插件集成 – Windows
- Build rlottie
- Integrate rlottie
Header Files:
- Visual Studio: setup Additional Include Directories
- CMakeLists
- include_directories (
- ${CMAKE_SOURCE_DIR}/rlottie/include
- )
Libs
- Visual Studio: setup Additional Dependencies
- CMakeLists
- target_link_libraries (${PROJECT_NAME}
- PRIVATE
- debug
- ${CMAKE_SOURCE_DIR}/rlottie/sdk/debug/rlottie.lib
- optimized
- ${CMAKE_SOURCE_DIR}/rlottie/sdk/release/rlottie.lib
- )
Dlls
- Visual Studio: copy them to Output Directory
- CMakeLists
-
cmake_path(CONVERT
"
${CMAKE_SOURCE_DIR}
/rlottie/sdk/$
/*.dll TO_NATIVE_PATH_LIST rlottie_dll_path) - cmake_path(CONVERT "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/" TO_NATIVE_PATH_LIST runtime_output_ path)
- add_custom_command(TARGET${XXX_TARGET_NAME} POST_BUILD
- COMMAND xcopy "${rlottie_dll_path}" "${runtime_output_path}" /y
- WORKING_DIRECTORY${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND "Copying thirdparty files" VERBATIM
- )
-
cmake_path(CONVERT
"
${CMAKE_SOURCE_DIR}
/rlottie/sdk/$