Два метода openresty (nginx+lua) или luajit, вызывающие модули C++

I. Обзор

  • Расположение проекта демо-кода: https://gitee.com/liudegui/lua_call_cpp

При написании кода openresty иногда вам нужно вызвать свой собственный модуль C++.
В этой статье представлены два часто используемых метода:

  • 1. Вызов cffi на основе luajit в основном используется для вызова модулей C++ с относительно коротким временем блокировки;
  • 2. Вызов модуля оболочки на основе Openresty , который соответствует вызову os.execute в lua, который можно использовать для вызова модулей C++ с относительно длительным временем блокировки.

В полной реализации многопроцессорного рабочего механизма C++ master-worker, блоге реализации совместной работы на стороне и в облаке я упомянул, что при выполнении суперпозиции траекторий на стороне сервера x86 код lua должен вызывать видео, инкапсулированное в C++. модуль наложения траекторий.
Мой первоначальный метод реализации заключается в использовании механизма cffi luajit для вызова модуля C++, но поскольку отрисовка дорожки на видео является относительно ресурсоемким процессом, он будет блокировать рабочий процесс nginx, поэтому позже я переключился на shell.run от openresty. для асинхронного вызова модуля C++, это не будет блокировать рабочие процессы nginx.

2. Lua вызывает модули C++ на основе cffi, что подходит для кода openresty

Вот некоторые моменты, на которые следует обратить внимание

  • При инкапсуляции модулей C++ вам необходимо использовать extern "C"инкапсуляцию в модули C;
  • Входящие параметры C++ могут использовать только формат POD, а не C++ STL.Структура структуры языка 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
  • lua cffi вызывает модуль C++

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()

3. Lua асинхронно вызывает исполняемую программу C++ (код openresty использует вызов оболочки)

Метод вызова os.execute с использованием lua:

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, он аналогичен os.execute, например: local ok , стандартный вывод, стандартный вывод, причина, статус = shell.run(cmd, nil, timeout)

4. Один и тот же код быстро адаптируется к разным методам вызова

Внимательно изучите предоставленный мной код lua_call_cpp , и нетрудно обнаружить, что библиотека C++, вызываемая cffi, и исполняемая программа 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 соответственно во время компиляции, и основная функция в коде не повлияет на компиляцию библиотеки C.

# 将C++代码编译成可执行程序供lua调用
#add_executable(${PROJECT_NAME} ${DIR_SRCS})
# 将C++代码编译成C动态库供lua调用
add_library(${PROJECT_NAME} SHARED ${DIR_SRCS})

Guess you like

Origin blog.csdn.net/stallion5632/article/details/125955805