在编写openresty代码时,有时候要调用自己编写的C++模块。
本文给出了两种常用的方法:
在C++多进程master-worker工作机制较完整的实现,边端和云端协同工作实现 这篇博客中,我提到在x86服务器端进行轨迹叠加时,需要lua代码调用C++封装的视频和轨迹叠加模块。
我开始的实现方法是使用luajit的cffi机制调用C++模块,但由于在视频上画轨迹是一个比较耗CPU,这会阻塞nginx的工作进程;因此后来改用openresty的shell.run异步调用C++模块,这将不会阻塞nginx的工作进程。
这里有注意点
extern "C"
封装成C模块;// video_bbox_drawer.h
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
int drawBBoxOnVideo(const char *inputVideo, const char *bboxString, int bboxStrLen, const char *outputVideo);
#ifdef __cplusplus
}
#endif
local ffi = require("ffi")
ffi.cdef[[
int drawBBoxOnVideo(const char *inputVideo, const char *bboxString, int bboxStrLen, const char *outputVideo, int outputWidth, int outputHeight, int frameRate);
]]
local lib = ffi.load('video_bbox_drawer')
local function read_file(fileName)
local f = assert(io.open(fileName,'r'))
local content = f:read('*all')
f:close()
return content
end
local function test_draw()
local content = read_file("detect_result.txt")
print(#content)
lib.drawBBoxOnVideo("face_1280_720.h264", content , #content, "face_1280_720_lua.mp4")
end
test_draw()
使用lua的os.execute调用方法为:
local function read_file(fileName)
local f = assert(io.open(fileName,'r'))
local content = f:read('*all')
f:close()
return content
end
local function test_draw()
local content = read_file("detect_result.txt")
print(#content)
local cmd = "./bin/video_bbox_drawer" .. " " ..
"face_1280_720.h264" .. " " ..
content .. " " ..
#content .. " "..
"face_1280_720_output.h264"
os.execute(cmd)
--注:如果是openresty的代码调用,应该是使用shell.run调用
--如:local ok, stdout, stderr, reason, status = shell.run(cmd, nil, timeout)
end
test_draw()
在openresty代码中是不建议使用os.execute调用cmd的,因为这会阻塞nginx工作进程;而是使用openresty官方提供的shell模块调用;使用起来和os.execute类似,如:local ok, stdout, stderr, reason, status = shell.run(cmd, nil, timeout)
仔细观察我提供的lua_call_cpp代码,不难发现,其实cffi调用的C++库和C++可执行程序其实是同一份C++代码,只需要在编译的CMakeLists.txt中做区分即可。
project(video_bbox_drawer)
cmake_minimum_required( VERSION 3.0 )
# ...
aux_source_directory(src DIR_SRCS)
include_directories(${PROJECT_SOURCE_DIR}/include)
# 将C++代码编译成可执行程序供lua调用
#add_executable(${PROJECT_NAME} ${DIR_SRCS})
# 将C++代码编译成C动态库供lua调用
add_library(${PROJECT_NAME} SHARED ${DIR_SRCS})
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
target_link_libraries(${PROJECT_NAME} PRIVATE
pthread
opencv_core
opencv_highgui
opencv_imgproc
opencv_videoio
)
endif()
如以上,只是在编译的时候分别启用add_executable和add_library,代码中的main函数对编译C库没有影响。
# 将C++代码编译成可执行程序供lua调用
#add_executable(${PROJECT_NAME} ${DIR_SRCS})
# 将C++代码编译成C动态库供lua调用
add_library(${PROJECT_NAME} SHARED ${DIR_SRCS})