HI3516 web服务器移植
1、源码下载
下载boa服务器源码。
#源码下载:
http://www.boa.org
#源码解压:
tar -vxf boa-0.94.13.tar.gz
2、编译文件修改
编译之前,可能会遇到编译出错,需要修改相关配置文件:
#1、修改src/boa.c文件
#if 0
if (passwdbuf == NULL) {
DIE(getpwuid);
}
if (initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1) {
DIE(initgroups);
}
#endif
#if 0
if (setuid(0) != -1) {
DIE(icky Linux kernel bug!);
}
#endif
#2、修改src/config.c文件
extern char *error_log_name;
extern char *access_log_name;
extern char *cgi_log_name;
#3、修改src/util.c文件
if (use_localtime) {
t = localtime(¤t_time);
// time_offset = TIMEZONE_OFFSET(t);
time_offset = 0;
} else {
#4、修改src/index_dir.c文件
#include compat.h
#define MAXNAMLEN 1024 //增加宏
#define MAX_FILE_LENGTH MAXNAMLEN
#5、修改src/defines.h文件
#ifndef SERVER_ROOT
#define SERVER_ROOT /boa
#endif
3、添加配置文件
(1)boa.conf配置修改
#修改boa.conf文件如下:
User 0
Group 0
ErrorLog /boa/log/error_log
AccessLog /boa/log/access_log
ServerName www.your.org.here
DocumentRoot /boa/www
DirectoryMaker //boa/boa_indexer
MimeTypes /boa/mime.types
ScriptAlias /cgi-bin/ /boa/cgi-bin/
(2)在boa-0.94.13目录下,创建boa_conf文件,将boa.conf文件拷贝到boa-0.94.13/boa_conf目录下。
(3)将ubuntu系统下/etc/mime.types文件拷贝到boa-0.94.13/boa_conf目录下。
(4)添加html测试页面index.html,将index.html文件拷贝到boa-0.94.13/boa_conf目录下。
<!DOCTYPE html>
<html lang=zh>
<head>
<meta charset=UTF-8>
<meta http-equiv=X-UA-Compatible content=IE=edge>
<meta name=viewport content=width=device-width, initial-scale=1.0>
<title>Document</title>
</head>
<body>
hello world
</body>
</html>
4、源码移植
将boa-0.94.13文件,放到HI3516 SDK的third_party目录下。
在boa-0.94.13目录下创建build.gn文件。
# Copyright (c) 2020 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the License);
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an AS IS BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import(//build/lite/config/hap_pack.gni)
executable(boa) {
include_dirs = [
.,
]
sources = [
src/alias.c,
src/boa.c,
src/buffer.c,
src/cgi.c,
src/cgi_header.c,
src/config.c,
src/escape.c,
src/get.c,
src/hash.c,
src/ip.c,
src/log.c,
src/mmap_cache.c,
src/pipe.c,
src/queue.c,
src/read.c,
src/request.c,
src/response.c,
src/select.c,
src/signals.c,
src/util.c,
src/sublog.c,
src/timestamp.c,
src/y.tab.c,
src/lex.yy.c,
]
}
executable(boa_indexer) {
include_dirs = [
.,
]
sources = [
src/index_dir.c,
src/escape.c,
]
}
copy(boa_config) {
sources = [ boa_conf ]
outputs = [ $root_out_dir/etc/{{source_file_part}} ]
}
group(boa_group) {
deps = [
:boa,
:boa_indexer,
:boa_config,
]
}
5、构建BOA服启动脚本
(1)在vendor/hisilicon/hispark_taurus_linux/init_configs/etc/init.d目录下,添加boa启动脚本S90boa文件。
#!/bin/sh
boa_dir=/boa
boa_exe_dir=/bin
boa_conf_dir=/etc/boa_conf
eth0_ip=192.168.137.200
if [ -d $boa_dir ];then
rm -rf $boa_dir
fi
dir_array=(log www cgi-bin)
for i in ${dir_array[@]}
do
mkdir -p $boa_dir/$i
done
cp $boa_conf_dir/boa.conf $boa_dir/
cp $boa_conf_dir/mime.types $boa_dir/
cp $boa_conf_dir/index.html $boa_dir/www/
cp $boa_exe_dir/boa $boa_dir/
cp $boa_exe_dir/boa_indexer $boa_dir/
ifconfig eth0 $eth0_ip
while : ; do
ifconfig_eth0_ip=`ifconfig eth0 | egrep -o ([0-9]{1,3}\.){3}[0-9]{1,3} | head -n 1`
if [[ $ifconfig_eth0_ip == $eth0_ip ]]; then
sleep 12
break;
else
echo eth0 ip is $ifconfig_eth0_ip
usleep 100000
fi
done
$boa_dir/./boa
(2)在vendor/hisilicon/hispark_taurus_linux/init_configs/BUILD.gn文件将S90boa加入到init_initd中。
#在vendor/hisilicon/hispark_taurus_linux/init_configs/BUILD.gn文件中修改如下:
copy(init_initd) {
sources = [
etc/init.d/rcS,
etc/init.d/S00devs,
etc/init.d/S01mdev,
etc/init.d/S80network,
etc/init.d/S82ohos,
etc/init.d/S90boa,
]
outputs = [ $root_out_dir/etc/init.d/{{source_file_part}} ]
}
6、启动BOA服务器
重新烧录并启动板子,用网线连接HI3516和PC,在PC浏览器上访问192.168.137.200地址,可以显示网页。
7、cgic移植
HTTP协议是WWW的基础,基于客户/服务器模型,服务器可以为分布在网络中的客户提供服务。HTTP是建立在TCP/IP协议之上的“无连接”协议,每次连接只处理一个请求。在BOA服务器上,运行产着一个守护进程对端口进行监听,等待来自客户的请求。当一个请求到来时,将创建一个子进程为用户的连接服务。根据请求的不同,服务器返回HTML文件或者通过CGI调用外部应用程序,返回处理结果。服务器通过CGI与外部程序和脚本之间进行交互,根据客户端在进行请求时所采取的方法,服务器会收集客户所提供的信息,并将该部分信息发送给指定的CGI扩展程序。CGI扩展程序进行信息处理并将结果返回服务器,然后服务器 对信息进行分析,并将结果发送回客户端。
外部CGI程序与BOA服务器进行通信、传递有关参数和处理结果是通过环境变量、命令行参数和标准输入来进行的。服务器提供了客户端(浏览器)与CGI扩展程序之间的信息交换的通道。CGI的标准输入是服务器的标准输出,而CGI的标准输出是服务器的标准输入。客户的请求通过服务器的标准输出传送给CGI的标准输入,CGI对信息进行处理后,将结果发送到它的标准输入,然后由服务器将处理结果发送给客户端。
(1)下载cgic源码:
https://gitee.com/ikaros-521/cgic
(2)将下载的cgic源码拷贝的boa-0.94.13目录下,并修改BUILD.gn文件。
executable(cgic_master) {
include_dirs = [
.,
]
sources = [
cgic-master/cgic.c,
cgic-master/cgictest.c,
]
}
...
group(boa_group) {
deps = [
:boa,
:boa_indexer,
:boa_config,
:cgic_master,
]
}
(3)修改boa启动脚本S90boa,将生成的cgic_master文件拷贝到/boa/cgic-bin目录下:
...
cp $boa_exe_dir/boa_indexer $boa_dir/
cp $boa_exe_dir/cgic_* $boa_dir/cgi-bin/
...
(4)在PC浏览器中访问cgic_master页面,在PC浏览器上访问192.168.137.200/cgi-bin/cgic-master地址,可以cgi显示网页。
8、获取HI3516 camera数据流
参考//applications/sample/camera/cameraApp/cameraApp/src/main/cpp代码,调用camera框架启动camera,框架会将camera数据放入到Surface中,应用可以注册一个Surface到框架,这样在应用层就可以获取到camera数据流。
(1)camera框架代码修改。
//(1)修改foundation/multimedia/camera_lite/services/impl/src/camera_device.cpp文件:
int32_t RecordAssistant::SetFrameConfig(FrameConfig &fc, uint32_t *streamId)
{
fc_ =
auto surfaceList = fc.GetSurfaces();
if (surfaceList.size() > VIDEO_MAX_NUM || surfaceList.size() == 0) {
MEDIA_ERR_LOG(the number of surface in frame config must 1 or 2 now.\n);
return MEDIA_ERR;
}
uint32_t num = 0;
int32_t ret = MEDIA_OK;
for (auto &surface : surfaceList) {
CODEC_HANDLETYPE codecHdl = nullptr;
StreamAttr stream = {};
#ifdef __LINUX__
g_surface = surface; //这里需要把surface赋值给g_surface,surface是应用层传下来的suface,g_surface定义在录制模块中。
StreamAttrInitialize(&stream, g_surface, STREAM_VIDEO, fc);
#else
StreamAttrInitialize(&stream, surface, STREAM_VIDEO, fc);
#endif
//...
}
//(2)camera编码格式修改,修改//foundation/multimedia/camera_lite/frameworks/frame_config.cpp文件:
FrameConfig::FrameConfig(int32_t type) : type_(type)
{
crop.x = 0;
crop.y = 0;
crop.w = 0;
crop.h = 0;
SetParameter(CAM_IMAGE_CROP_RECT, crop);
SetParameter(CAM_IMAGE_INVERT_MODE, CAM_CENTER_MIRROR);
SetParameter(CAM_FRAME_FPS, DEFAULT_FPS);
if (type == FRAME_CONFIG_RECORD) {
SetParameter(CAM_IMAGE_FORMAT, CAM_FORMAT_JPEG); //修改录制编码格式
} else if (type == FRAME_CONFIG_CAPTURE) {
SetParameter(CAM_IMAGE_FORMAT, CAM_FORMAT_JPEG);
} else {
SetParameter(CAM_IMAGE_FORMAT, CAM_FORMAT_YVU420);
}
}
(2)添加应用程序代码:
在//boa-0.94.13目录下,创建camera目录,拷贝//applications/sample/camera/cameraApp/cameraApp/src/main/cpp/camera_manager.cpp、camera_manager.h文件,修改内容如下:
//(1)修改camera_manager.cpp文件
Surface *SampleCameraStateMng::StartRecord(void)
{
int ret = 0;
if (gRecordSta_ == MEDIA_STATE_START) {
return NULL;
}
Surface *surface = Surface::CreateSurface();
if (surface == nullptr) {
return NULL;
}
surface->SetWidthAndHeight(IMAGE_WIDTH, IMAGE_HEIGHT);
surface->SetQueueSize(5); /* queueSize is 5 */
surface->SetSize(PAGE_SIZE * PAGE_SIZE);
FrameConfig *fc = new FrameConfig(FRAME_CONFIG_RECORD);
fc->AddSurface(*surface);
if (cam_->TriggerLoopingCapture(*fc) != 0) {
fc->RemoveSurface(*surface);
delete surface;
delete fc;
return NULL;
}
gRecordSta_ = MEDIA_STATE_START;
return surface;
}
//(2)添加camera_device_test.cpp文件
#include <algorithm>
#include <meta_data.h>
#include <window/window.h>
#include <unistd.h>
#include <signal.h>
#include camera_manager.h
#include gfx_utils/color.h
#include ui_config.h
#include securec.h
#include camera_device_test.h
using namespace OHOS;
using namespace OHOS::Media;
static Surface *camera_Surface = NULL;
static SampleCameraManager *cam_manager;
void CameraOnStart(void)
{
cam_manager = new SampleCameraManager();
cam_manager->SampleCameraCreate();
int timecnt = 0;
while (1)
{
if (++timecnt > 5) /* 5s timeout */
{
printf(wait camera timeout!! \n);
break;
}
if (cam_manager->SampleCameraIsReady()) break;
sleep(1);
}
camera_Surface = cam_manager->SampleCameraStartRecord();
}
int releaseFrameBuffer(void* handle)
{
if (NULL == camera_Surface || NULL == handle)
{
return -1;
}
camera_Surface->ReleaseBuffer((SurfaceBuffer*)handle);
return 0;
}
int getFrameBuffer(void** handle, unsigned char** frame_buf, unsigned int *frame_size)
{
if (NULL == camera_Surface)
{
return -2;
}
if (NULL == handle || NULL == frame_buf || NULL == frame_size)
{
return -3;
}
SurfaceBuffer* frame = NULL;
for (int i = 0; i < 5; i++)
{
frame = camera_Surface->AcquireBuffer();
if (NULL == frame) usleep(15 * 1000);
else break;
}
if (NULL == frame)
{
return -4;
}
*frame_buf = static_cast<unsigned char *>(frame->GetVirAddr());
*frame_size = frame->GetSize();
if (NULL == *frame_buf || *frame_size <= 0)
{
releaseFrameBuffer((void*)frame);
*frame_buf = NULL;
*frame_size = 0;
return -5;
}
*((SurfaceBuffer**)handle) = frame;
return 0;
}
void CameraOnStop(void)
{
if (NULL == camera_Surface)
{
return;
}
cam_manager->SampleCameraStop();
}
9、HI3516 web摄像头
(1)参照MJPG-streamer视频软件使用了:应用网络协议---MJPEG协议 ,将camera jpeg数据推送到网页,在//boa-0.94.13/cgic-master添加camera_cgi.c文件,代码如下:
int cgiMain()
{
//open system log
// openlog(MJPG-streamer , LOG_PID|LOG_CONS, LOG_USER);
// DBG(starting application);
// DBG(cgiMain pid :%u,(unsigned int)getpid());
fprintf(cgiOut, Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, max-age=0\r\n
Pragma: no-cache\r\nExpires: Thu, 01 Jan 1970 00:00:01 GMT\r\n);
fprintf(cgiOut,Content-Type: multipart/x-mixed-replace;boundary=boundarydonotcross\r\n\n);
// cgiHeaderContentType(image/jpeg);
int ret = 0;
void *handle = NULL;
unsigned char *frame_buf=NULL;
unsigned int frame_size = 0;
CameraOnStart();
while(1) {
ret = getFrameBuffer(&handle, &frame_buf, &frame_size);
if(ret == 0) {
fprintf(cgiOut, Content-Type: image/jpeg\r\nContent-Length: %d\r\n\n, frame_size);
fwrite(frame_buf, frame_size, 1, cgiOut);
fprintf(cgiOut, \r\n\n--boundarydonotcross\r\n);
releaseFrameBuffer(handle);
}
}
return 0;
}
(2)修改BUILD.gn文件:
shared_library(camera_device) {
sources = [
camera/camera_device_test.cpp,
camera/camera_manager.cpp,
]
deps = [
${aafwk_lite_path}/frameworks/ability_lite:aafwk_abilitykit_lite,
${appexecfwk_lite_path}/frameworks/bundle_lite:bundle,
//foundation/communication/ipc_lite:liteipc_adapter,
//foundation/distributedschedule/samgr_lite/samgr:samgr,
//foundation/graphic/surface,
//foundation/graphic/ui:lite_ui,
//foundation/graphic/utils:lite_graphic_utils,
//foundation/multimedia/camera_lite/frameworks:camera_lite,
//foundation/multimedia/media_lite/frameworks/recorder_lite:recorder_lite,
//utils/native/lite/kv_store:kv_store,
]
}
executable(cgic_camera) {
include_dirs = [
.,
camera,
]
sources = [
cgic-master/cgic.c,
cgic-master/camera_cgi.c,
]
deps = [
:camera_device,
]
}
executable(cgic_master) {
include_dirs = [
.,
]
sources = [
cgic-master/cgic.c,
cgic-master/cgictest.c,
]
}
...
group(boa_group) {
deps = [
:boa,
:boa_indexer,
:boa_config,
:cgic_master,
:cgic_camera,
]
}
(3)在PC浏览器中访问cgic_master页面,在PC浏览器上访问192.168.137.200/cgi-bin/cgic_camera地址,可以在网页上显示摄像头视频。
9、移植过程中的问题
#问题一:
[OHOS ERROR] ninja: error: '../../../third_party/boa-0.94.13/src/y.tab.c', needed by 'obj/third_party/boa-0 .94.13/src/boa.y.tab.o', missing and no known rule to make it
[OHOS ERROR] ninja: error: '../../../third_party/boa-0.94.13/src/lex.yy.c', needed by 'obj/third_party/boa-0.94.13/src/boa.lex.yy.o', missing and no known rule to make it
#解决办法:
出现问题的原因是在编译过程中发现缺少'y.tab.c、y.tab.h、lex.yy.c'文件,查看boa源码Makefile,发现这两个文件是在编译过程中生成的,所以可以现在ubuntu中执行boa源码中的Makefile生成缺少的文件,在把生成的文件拷贝的'/boa-0.94.13/src'目录下。
#问题二:
[OHOS ERROR] ../../../third_party/boa-0.94.13/src/compat.h:28:10: fatal error: 'config.h' file not found
[OHOS ERROR] #include config.h
#解决办法:
和问题一一样,缺少config.h文件,将生成的文'config.h'拷贝的'/boa-0.94.13/src'目录下。
#问题三:
在PC上访问192.168.137.200地址时,显示无法访问。
#解决办法:
确定PC网卡和板子配置的IP地址是否在统一个网段,要先确保PC可以ping通板子。
#问题四:
无法显示摄像头视频。
#可能有以下原因:
(1)检查摄像头驱动有没有打开成功。
(2)在getFrameBuffer接口中,无法从Surface中获取camera数据----检查foundation/multimedia/camera_lite/services/impl/src/camera_device.cpp文件中,有没有在RecordAssistant::SetFrameConfig函数中把surface赋值给g_surface。
(3)在getFrameBuffer接口中可以获取数据,但是还是无法显示视频---检查camera框架中,设置的camera数据输出格式是否是jpeg,查看//foundation/multimedia/camera_lite/frameworks/frame_config.cpp文件中FrameConfig::FrameConfig设置的格式是否是CAM_FORMAT_JPEG。
想了解更多关于开源的内容,请访问:
51CTO 开源基础软件社区
https://ost.51cto.com/#bkwz