upload
@@ -0,0 +1,193 @@
|
||||
# Body Pose Detection \(Python)
|
||||
|
||||
This application runs on Atlas 200 DK, to infer human body poses. The model used is modified from Lightweight OpenPose [Osokin, Daniil. "Real-time 2d multi-person pose estimation on CPU: Lightweight OpenPose." arXiv preprint arXiv:1811.12004 (2018)], an open-source pose detection network. This application can be run on various input formats, namely image input, video input as well as live camera input.
|
||||
|
||||
The pose detection network originates from [Cao, Zhe, et al. "OpenPose: realtime multi-person 2D pose estimation using Part Affinity Fields." arXiv preprint arXiv:1812.08008 (2018)], where the network provides two outputs: heatmaps and PAF maps for each frame. In the post-processing of the model, both heatmaps and PAF maps are used to obtain multi-persion pose estimation.
|
||||
|
||||
In this repository, the post-processing a simplied version for edge computing, where only the heatmap is used to calculate the predicted locations of the human body joints. A set of 14 detected joints are grouped, connected to form limbs and associated to a person. The diagram below represents connection scheme:
|
||||
|
||||
12 12: head, 13: neck
|
||||
|
|
||||
|
|
||||
0-----13-----3
|
||||
/ / \ \
|
||||
1 / \ 4
|
||||
/ / \ \
|
||||
2 6 9 5
|
||||
| |
|
||||
7 10
|
||||
| |
|
||||
8 11
|
||||
|
||||
|
||||
|
||||
The figure below shows the sample output on a single image input. The detected pose is displayed in the form of a skeleton overlay on the image.
|
||||
|
||||
**Figure** OpenPose detection result<a name="zh-cn_topic_0228757088_fig64391558352"></a>
|
||||

|
||||
|
||||
## Software Preparation<a name="zh-cn_topic_0228757083_section17595135641"></a>
|
||||
|
||||
Clone or download the project repository:
|
||||
|
||||
**mkdir -p $HOME/AscendProjects**
|
||||
**cd $HOME/AscendProjects**
|
||||
**git clone ssh://git@rnd-gitlab-ca-g.huawei.com:2222/hispark/openpose-pythonc73.git**
|
||||
OR
|
||||
**wget https://rnd-gitlab-ca-g.huawei.com/hispark/openpose-pythonc73.git**
|
||||
|
||||
Then, unzip the downloaded file:
|
||||
|
||||
**unzip openpose-pythonC73.zip**
|
||||
|
||||
|
||||
## Environment Preparation<a name="zh-cn_topic_0228757083_section17595135641"></a>
|
||||
Install required libraries for Python3 environment (OpenCV, PresentAgent and Python3env)
|
||||
|
||||
Please refer to https://github.com/Huawei-Ascend/samples/tree/master/common
|
||||
|
||||
|
||||
## Environment Deployment<a name="zh-cn_topic_0228757083_section1759513564117"></a>
|
||||
|
||||
1. Go to the root directory where the application code is located, such as: $HOME/AscendProjects/openpose-pythonC73/.
|
||||
|
||||
**cd $HOME/AscendProjects/openpose-pythonC73/**
|
||||
|
||||
2. Modify the configuration file.
|
||||
|
||||
Modify **presenter\_server\_ip** and **presenter\_view\_ip** in **script/body\_pose.conf** to the current ubuntu server and atlas200dk development board network port ip, **presenter \_agent\_ip** is the ip of the network port connected to the ubuntu server on the development board.
|
||||
|
||||
If you use USB connection, the USB network port ip of the development board is 192.168.1.2, and the network port ip of the virtual network card connected to the ubuntu server and the development board is 192.168.1.223, then the configuration file content is as follows:
|
||||
|
||||
**presenter\_server\_ip=192.168.1.223**
|
||||
|
||||
**presenter\_view\_ip=192.168.1.223**
|
||||
|
||||
**presenter\_agent\_ip=192.168.1.2**
|
||||
|
||||
|
||||
Generally, when connecting via USB, atlas200dk\_board\_ip is the USB network port ip of the development board, and the default is 192.168.1.2. When connecting through a network port, atlas200dk\_board\_ip is the network port ip of the development board, and the default is 192.168.0.2.
|
||||
|
||||
3. Copy the application code to the development board.
|
||||
|
||||
Navigate to the root directory where the openpose-pythonC73 application code is located, such as: AscendProjects/openpose-pythonC73, execute the following command to copy the application code to the development board. If the copy fails, please check if there is a directory HIAI\_PROJECTS on the development board, and if not, create it.
|
||||
|
||||
**scp -r ~/AscendProjects/openpose-pythonC73 HwHiAiUser@192.168.1.2:/home/HwHiAiUser/HIAI\_PROJECTS**
|
||||
|
||||
Enter the development board password when prompted for password. The default password of the development board is **Mind@123**, as shown below:
|
||||
<a name="zh-cn_topic_02287570831_zh-cn_topic_0198304761_fig1660453512014"></a>
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
4. Start Presenter Server.
|
||||
|
||||
**NOTE**: This step is required when the presenter server needs to be used for video or live display on the browser. Otherwise, skip this step.
|
||||
|
||||
Execute the following command to start the Presenter Server in the background.
|
||||
|
||||
**bash $HOME/AscendProjects/openpose-pythonC73/script/run_presenter_server.sh &**
|
||||
|
||||
Log in to the Presenter Server using the prompted URL. The figure below shows that the Presenter Server has started successfully.
|
||||
|
||||
**Figure** Home Page Display<a name="zh-cn_topic_0228757088_fig64391558352"></a>
|
||||

|
||||
|
||||
|
||||
The communication between Presenter Server, Mind Studio and Atlas 200 DK is shown as below:
|
||||
|
||||
|
||||
**Figure** Examples of IP addresses<a name="zh-cn_topic_0228757088_fig1881532172010"></a>
|
||||

|
||||
|
||||
NOTE:
|
||||
|
||||
- The IP address used by the Atlas 200 DK developer board is 192.168.1.2 (USB connection).
|
||||
- The IP address for the communication between Presenter Server and Atlas 200 DK is the IP address of the UI Host server on the same network segment as Atlas 200 DK, for example: 192.168.1.223.
|
||||
- This example of the IP address for accessing Presenter Server through a browser is 10.10.0.1. Since Presenter Server and Mind Studio are deployed on the same server, this IP address is also the IP for accessing Mind Studio through a browser.
|
||||
|
||||
|
||||
5. Copy acl.so to the development board. Please skip this step if it is already done in other projects.
|
||||
|
||||
**scp ~/Ascend/ascend-toolkit/20.0.RC1/arm64-linux_gcc7.3.0/pyACL/python/site-packages/acl/acl.so HwHiAiUser@192.168.1.2:/home/HwHiAiUser/Ascend/**
|
||||
|
||||
**Please replace X.X.X with the actual version number of the Ascend-Toolkit development kit package**
|
||||
**For example: the package name of the Toolkit package is Ascend-Toolkit-20.0.RC1-x86_64-linux_gcc7.3.0.run, then the version number of this Toolkit is 20.0.RC1.**
|
||||
|
||||
|
||||
6. Log in to the development board and add environment variables. Please skip this step if it is already done in other projects.
|
||||
|
||||
**ssh HwHiAiUser@192.168.1.2**
|
||||
**vim ~/.bashrc**
|
||||
Add two lines at the end
|
||||
**export LD_LIBRARY_PATH=/home/HwHiAiUser/Ascend/acllib/lib64**
|
||||
**export PYTHONPATH=/home/HwHiAiUser/Ascend/:\\${PYTHONPATH}**
|
||||

|
||||
|
||||
Execute the following command to make the environment variable take effect
|
||||
**source ~/.bashrc**
|
||||
|
||||
|
||||
## Running the Application
|
||||
1. Check whether the "CAMERA0" camera is used.
|
||||
The "CAMERA0" camera is used by default in the code. Please refer to the link below for the viewing method.
|
||||
https://support.huaweicloud.com/usermanual-A200dk_3000/atlas200dk_02_0051.html
|
||||
|
||||
2. Log in to the development board. Navigate to the code directory corresponding to the required input source format (image, video or live camera), and execute one of the following commands to run the application according to the input source format.
|
||||
|
||||
**NOTE**: To execute it, you could use the default input (just run **python3 main.py** without parameter), or input parameters as below for input/output paths and model path as indicated in **main.py**. For the video input, you also have the option to save the output as a video or display to presenter server, with the value in parameter 'is_presenter_server' set to False or True, respectively .
|
||||
|
||||
*Image input source*:
|
||||
|
||||
**cd ~/HIAI_PROJECTS/openpose-pythonC73/code_image**
|
||||
**python3 main.py --model='model/body_pose.om' --frames_input_src='tennis_player.jpg' --output_dir='outputs'**
|
||||
|
||||
*Video input source (output video)*:
|
||||
|
||||
**cd ~/HIAI_PROJECTS/openpose-pythonC73/code_video**
|
||||
**python3 main.py --model='model/body_pose.om' --frames_input_src='yoga.mp4' --output_dir='outputs' --is_presenter_server=False**
|
||||
|
||||
Video input source (output streamed to presenter server)*:
|
||||
|
||||
**cd ~/HIAI_PROJECTS/openpose-pythonC73/code_video**
|
||||
**python3 main.py --model='model/body_pose.om' --frames_input_src='yoga.mp4' --output_dir='outputs' --is_presenter_server=True**
|
||||
|
||||
*Live camera source*:
|
||||
|
||||
**cd ~/HIAI_PROJECTS/openpose-pythonC73/code_live**
|
||||
**python3 main.py --model='model/body_pose.om'**
|
||||
|
||||
3. If you need to view the detection results using presenter server for the live input or video source, log in to the Presenter Server website using the URL that was prompted when the Presenter Server service was started. Otherwise, skip this step.
|
||||
|
||||
Wait for the Presenter Agent to transmit data to the server, and click "Refresh" to refresh. When there is data, the status of the corresponding Channel turns green, as shown in the figure below.
|
||||
|
||||
**Figure** Presenter Server<a name="zh-cn_topic_0228461904_zh-cn_topic_0203223294_fig113691556202312"></a>
|
||||

|
||||
|
||||
Click the corresponding View Name link on the right, such as "video" in the above picture, to view the results.
|
||||
|
||||
## Stopping Application<a name="zh-cn_topic_0228757088_section1092612277429"></a>
|
||||
|
||||
If the presenter server is being used for display, stop
|
||||
|
||||
- **Stop Presenter Server**
|
||||
|
||||
The Presenter Server service will always be running after it is started. If you want to stop the Presenter Server service corresponding to the pose detection application, you can perform the following operations.
|
||||
|
||||
Execute the following command on the command line on the server where the process of the Presenter Server service is running:
|
||||
|
||||
**ps -ef | grep presenter**
|
||||
|
||||
```
|
||||
ascend@ubuntu:~/AscendProjects/openpose-pythonC73/script$ ps -ef | grep presenter
|
||||
ascend 9560 1342 0 02:19 pts/4 00:00:04 python3/home/ascend/AscendProjects/openpose-pythonC73.bak/script/..//present
|
||||
erserver/presenter_server.py --app openpose-pythonC73
|
||||
```
|
||||
|
||||
As shown above, _9650_ is the process ID of the Presenter Server service corresponding to the openpose-pythonC73 application.
|
||||
|
||||
If you want to stop this service, execute the following command:
|
||||
|
||||
|
||||
**kill -9** _9650_
|
||||
@@ -0,0 +1,215 @@
|
||||
import numpy as np
|
||||
import acl
|
||||
from atlas_utils.utils import *
|
||||
from atlas_utils.acl_image import AclImage
|
||||
|
||||
class Dvpp():
|
||||
def __init__(self, acl_resource):
|
||||
self._stream = acl_resource.stream
|
||||
self._run_mode = acl_resource.run_mode
|
||||
self._dvpp_channel_desc = None
|
||||
ret = self._init_resource()
|
||||
if ret == FAILED:
|
||||
raise Exception("Dvpp init failed")
|
||||
|
||||
def __del__(self):
|
||||
if self._resize_config:
|
||||
acl.media.dvpp_destroy_resize_config(self._resize_config)
|
||||
|
||||
if self._dvpp_channel_desc:
|
||||
acl.media.dvpp_destroy_channel(self._dvpp_channel_desc)
|
||||
acl.media.dvpp_destroy_channel_desc(self._dvpp_channel_desc)
|
||||
|
||||
if self._jpege_config:
|
||||
acl.media.dvpp_destroy_jpege_config(self._jpege_config)
|
||||
|
||||
def _init_resource(self):
|
||||
# create dvpp channel
|
||||
self._dvpp_channel_desc = acl.media.dvpp_create_channel_desc()
|
||||
ret = acl.media.dvpp_create_channel(self._dvpp_channel_desc)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Dvpp create channel failed")
|
||||
return FAILED
|
||||
# create resize configuration
|
||||
self._resize_config = acl.media.dvpp_create_resize_config()
|
||||
#create yuv to jpeg configuration
|
||||
self._jpege_config = acl.media.dvpp_create_jpege_config()
|
||||
ret = acl.media.dvpp_set_jpege_config_level (self._jpege_config, 100)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Dvpp set jpege config failed")
|
||||
return FAILED
|
||||
|
||||
return SUCCESS
|
||||
|
||||
def _gen_input_pic_desc(self, image,
|
||||
width_align_factor=16, height_align_factor=2):
|
||||
#create image input desc
|
||||
stride_width = align_up(image.width, width_align_factor)
|
||||
stride_height = align_up(image.height, height_align_factor)
|
||||
|
||||
pic_desc = acl.media.dvpp_create_pic_desc()
|
||||
acl.media.dvpp_set_pic_desc_data(pic_desc, image.data())
|
||||
acl.media.dvpp_set_pic_desc_format(pic_desc,
|
||||
PIXEL_FORMAT_YUV_SEMIPLANAR_420)
|
||||
acl.media.dvpp_set_pic_desc_width(pic_desc, image.width)
|
||||
acl.media.dvpp_set_pic_desc_height(pic_desc, image.height)
|
||||
acl.media.dvpp_set_pic_desc_width_stride(pic_desc, stride_width)
|
||||
acl.media.dvpp_set_pic_desc_height_stride(pic_desc, stride_height)
|
||||
acl.media.dvpp_set_pic_desc_size(pic_desc, image.size)
|
||||
|
||||
return pic_desc
|
||||
|
||||
def _gen_output_pic_desc(self, width, height,
|
||||
output_buffer, output_buffer_size,
|
||||
width_align_factor=16, height_align_factor=2):
|
||||
# create image output desc
|
||||
stride_width = align_up(width, width_align_factor)
|
||||
stride_height = align_up(height, height_align_factor)
|
||||
|
||||
pic_desc = acl.media.dvpp_create_pic_desc()
|
||||
acl.media.dvpp_set_pic_desc_data(pic_desc, output_buffer)
|
||||
acl.media.dvpp_set_pic_desc_format(pic_desc,
|
||||
PIXEL_FORMAT_YUV_SEMIPLANAR_420)
|
||||
acl.media.dvpp_set_pic_desc_width(pic_desc, width)
|
||||
acl.media.dvpp_set_pic_desc_height(pic_desc, height)
|
||||
acl.media.dvpp_set_pic_desc_width_stride(pic_desc, stride_width)
|
||||
acl.media.dvpp_set_pic_desc_height_stride(pic_desc, stride_height)
|
||||
acl.media.dvpp_set_pic_desc_size(pic_desc, output_buffer_size)
|
||||
|
||||
return pic_desc
|
||||
|
||||
def _stride_yuv_size(self, width, height,
|
||||
width_align_factor=16, height_align_factor=2):
|
||||
stride_width = align_up(width, width_align_factor)
|
||||
stride_height = align_up(height, height_align_factor)
|
||||
stride_size = yuv420sp_size(stride_width, stride_height)
|
||||
|
||||
return stride_width, stride_height, stride_size
|
||||
|
||||
|
||||
def jpegd(self, image):
|
||||
# jepg image to yuv image
|
||||
# create converted image desc
|
||||
output_desc, out_buffer = self._gen_jpegd_out_pic_desc(image)
|
||||
ret = acl.media.dvpp_jpeg_decode_async(self._dvpp_channel_desc,
|
||||
image.data(),
|
||||
image.size,
|
||||
output_desc,
|
||||
self._stream)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("dvpp_jpeg_decode_async failed ret={}".format(ret))
|
||||
return None
|
||||
|
||||
ret = acl.rt.synchronize_stream(self._stream)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("dvpp_jpeg_decode_async failed ret={}".format(ret))
|
||||
return None
|
||||
|
||||
width, height, size = self._stride_yuv_size(image.width, image.height)
|
||||
return AclImage(out_buffer, width, height, size)
|
||||
|
||||
def _gen_jpegd_out_pic_desc(self, image):
|
||||
# predict memory sieze for decoding jpeg to yuy image
|
||||
out_buffer_size, ret = acl.media.dvpp_jpeg_predict_dec_size( \
|
||||
image.data(), image.size, PIXEL_FORMAT_YUV_SEMIPLANAR_420)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Predict jpeg decode size failed, return ", ret)
|
||||
return None
|
||||
# allocate memory for yuv image
|
||||
out_buffer, ret = acl.media.dvpp_malloc(out_buffer_size)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Dvpp malloc failed, error: ", ret)
|
||||
return None
|
||||
# create output image desc
|
||||
pic_desc = self._gen_output_pic_desc(image.width, image.height,
|
||||
out_buffer, out_buffer_size)
|
||||
return pic_desc, out_buffer
|
||||
|
||||
|
||||
def resize(self, image, resize_width, resize_height):
|
||||
# resize yuvsp420 image to specified size
|
||||
# generate input image desc
|
||||
input_desc = self._gen_input_pic_desc(image)
|
||||
# calculate resized image size
|
||||
stride_width = align_up16(resize_width)
|
||||
stride_height = align_up2(resize_height)
|
||||
output_size = yuv420sp_size(stride_width, stride_height)
|
||||
# allocate memory for resized image
|
||||
out_buffer, ret = acl.media.dvpp_malloc(output_size)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Dvpp malloc failed, error: ", ret)
|
||||
return None
|
||||
#create output desc
|
||||
output_desc = self._gen_output_pic_desc(resize_width, resize_height,
|
||||
out_buffer, output_size)
|
||||
if output_desc == None:
|
||||
print("Gen resize output desc failed")
|
||||
return None
|
||||
# call DVPP asynchronous resize interface to resize image
|
||||
ret = acl.media.dvpp_vpc_resize_async(self._dvpp_channel_desc,
|
||||
input_desc,
|
||||
output_desc,
|
||||
self._resize_config,
|
||||
self._stream)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Vpc resize async failed, error: ", ret)
|
||||
return None
|
||||
# wait for resize to complete
|
||||
ret = acl.rt.synchronize_stream(self._stream)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Resize synchronize stream failed, error: ", ret)
|
||||
return None
|
||||
# release allocated memory for resize
|
||||
acl.media.dvpp_destroy_pic_desc(input_desc)
|
||||
acl.media.dvpp_destroy_pic_desc(output_desc)
|
||||
return AclImage(out_buffer, stride_width,
|
||||
stride_height, output_size, MEMORY_DVPP)
|
||||
|
||||
def _gen_resize_out_pic_desc(self, resize_width,
|
||||
resize_height, output_size):
|
||||
out_buffer, ret = acl.media.dvpp_malloc(output_size)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Dvpp malloc failed, error: ", ret)
|
||||
return None
|
||||
pic_desc = self._gen_output_pic_desc(resize_width, resize_height,
|
||||
out_buffer, output_size)
|
||||
return pic_desc, out_buffer
|
||||
|
||||
|
||||
def jpege(self, image):
|
||||
# convert yuv420sp image to jpeg image
|
||||
# create input image desc
|
||||
input_desc = self._gen_input_pic_desc(image)
|
||||
# predict memory size for conversion
|
||||
output_size, ret = acl.media.dvpp_jpeg_predict_enc_size(
|
||||
input_desc, self._jpege_config)
|
||||
if (ret != ACL_ERROR_NONE):
|
||||
print("Predict jpege output size failed")
|
||||
return None
|
||||
# allocate memory for conversion
|
||||
output_buffer, ret = acl.media.dvpp_malloc(output_size)
|
||||
if (ret != ACL_ERROR_NONE):
|
||||
print("Malloc jpege output memory failed")
|
||||
return None
|
||||
# output size is an parameter for both input and output, which needs to be a pointer
|
||||
output_size_array = np.array([output_size], dtype=np.int32)
|
||||
output_size_ptr = acl.util.numpy_to_ptr(output_size_array)
|
||||
|
||||
# call jpeg asynchronous interface to convert image异步接口转换图片
|
||||
ret = acl.media.dvpp_jpeg_encode_async(self._dvpp_channel_desc,
|
||||
input_desc, output_buffer,
|
||||
output_size_ptr,
|
||||
self._jpege_config,
|
||||
self._stream)
|
||||
if (ret != ACL_ERROR_NONE):
|
||||
print("Jpege failed, ret ", ret)
|
||||
return None
|
||||
# wait for conversion to complete
|
||||
ret = acl.rt.synchronize_stream(self._stream)
|
||||
if (ret != ACL_ERROR_NONE):
|
||||
print("Jpege synchronize stream, failed, ret ", ret)
|
||||
return None
|
||||
# release resource
|
||||
acl.media.dvpp_destroy_pic_desc(input_desc)
|
||||
return AclImage(output_buffer, image.width,
|
||||
image.height, int(output_size_array[0]), MEMORY_DVPP)
|
||||
@@ -0,0 +1,263 @@
|
||||
import acl
|
||||
import numpy as np
|
||||
import datetime
|
||||
from atlas_utils.utils import *
|
||||
from atlas_utils.acl_image import AclImage
|
||||
|
||||
|
||||
class Model(object):
|
||||
def __init__(self, acl_resource, model_path):
|
||||
self._run_mode = acl_resource.run_mode
|
||||
self.model_path = model_path # string
|
||||
self.model_id = None # pointer
|
||||
self.input_dataset = None
|
||||
self.output_dataset = None
|
||||
self._output_info = []
|
||||
self.model_desc = None # pointer when using
|
||||
self._init_resource()
|
||||
|
||||
|
||||
def __del__(self):
|
||||
if self.input_dataset:
|
||||
self._release_dataset(self.input_dataset)
|
||||
if self.output_dataset:
|
||||
self._release_dataset(self.output_dataset)
|
||||
if self.model_id:
|
||||
ret = acl.mdl.unload(self.model_id)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("acl.mdl.unload error:", ret)
|
||||
if self.model_desc:
|
||||
ret = acl.mdl.destroy_desc(self.model_desc)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("acl.mdl.destroy_desc error:", ret)
|
||||
print("Model release source success")
|
||||
|
||||
def _init_resource(self):
|
||||
print("Init model resource")
|
||||
# loading model file
|
||||
self.model_id, ret = acl.mdl.load_from_file(self.model_path)
|
||||
check_ret("acl.mdl.load_from_file", ret)
|
||||
self.model_desc = acl.mdl.create_desc()
|
||||
ret = acl.mdl.get_desc(self.model_desc, self.model_id)
|
||||
check_ret("acl.mdl.get_desc", ret)
|
||||
# obtain model outputs number
|
||||
output_size = acl.mdl.get_num_outputs(self.model_desc)
|
||||
# create model output dataset structure
|
||||
self._gen_output_dataset(output_size)
|
||||
print("[Model] class Model init resource stage success")
|
||||
# obtain shape and type of each output of the model
|
||||
self._get_output_desc(output_size)
|
||||
# create a table to record memory for input data, which can be reused when allocating memory for the input
|
||||
self._init_input_buffer()
|
||||
|
||||
return SUCCESS
|
||||
|
||||
def _get_output_desc(self, output_size):
|
||||
for i in range(output_size):
|
||||
# obtain shape and type of each output
|
||||
dims = acl.mdl.get_output_dims(self.model_desc, i)
|
||||
shape = tuple(dims[0]["dims"])
|
||||
datatype = acl.mdl.get_output_data_type(self.model_desc, i)
|
||||
size = acl.mdl.get_output_size_by_index(self.model_desc, i)
|
||||
|
||||
if datatype == ACL_FLOAT:
|
||||
np_type = np.float32
|
||||
elif datatype == ACL_INT32:
|
||||
np_type = np.int32
|
||||
elif datatype == ACL_UINT32:
|
||||
np_type = np.uint32
|
||||
else:
|
||||
print("Unspport model output datatype ", datatype)
|
||||
return None
|
||||
# create a numpy array corresponding to outputs, with the same datatype and shape of outputs
|
||||
output_tensor = np.zeros(size//4, dtype=np_type).reshape(shape)
|
||||
if not output_tensor.flags['C_CONTIGUOUS']:
|
||||
output_tensor = np.ascontiguousarray(output_tensor)
|
||||
|
||||
tensor_ptr = acl.util.numpy_to_ptr(output_tensor)
|
||||
self._output_info.append({"ptr": tensor_ptr,
|
||||
"tensor": output_tensor})
|
||||
|
||||
def _gen_output_dataset(self, size):
|
||||
print("[Model] create model output dataset:")
|
||||
dataset = acl.mdl.create_dataset()
|
||||
for i in range(size):
|
||||
# allocate device memory for each output
|
||||
size = acl.mdl.get_output_size_by_index(self.model_desc, i)
|
||||
buffer, ret = acl.rt.malloc(size, ACL_MEM_MALLOC_NORMAL_ONLY)
|
||||
check_ret("acl.rt.malloc", ret)
|
||||
# create output data buffer structure, fill allocated memory into the data buffer
|
||||
dataset_buffer = acl.create_data_buffer(buffer, size)
|
||||
#add data buffer to output dataset
|
||||
_, ret = acl.mdl.add_dataset_buffer(dataset, dataset_buffer)
|
||||
print("malloc output %d, size %d"%(i, size))
|
||||
if ret:
|
||||
# release resource if failed
|
||||
acl.rt.free(buffer)
|
||||
acl.destroy_data_buffer(dataset)
|
||||
check_ret("acl.destroy_data_buffer", ret)
|
||||
self.output_dataset = dataset
|
||||
print("[Model] create model output dataset success")
|
||||
|
||||
def _init_input_buffer(self):
|
||||
# create a table recording the input data memory allocated for users
|
||||
# currently, the numpy data needs to be copied to device for memory allocation only when the input is numpy array
|
||||
self._input_num = acl.mdl.get_num_inputs(self.model_desc)
|
||||
self._input_buffer = []
|
||||
for i in range(self._input_num):
|
||||
# none of inputs is allocated memory initially
|
||||
item = {"addr":None, "size":0}
|
||||
self._input_buffer.append(item)
|
||||
|
||||
def _gen_input_dataset(self, input_list):
|
||||
# organize input dataset structure
|
||||
ret = SUCCESS
|
||||
# return if the input number does not match model requirements
|
||||
if len(input_list) != self._input_num:
|
||||
print("Current input data num %d unequal to"
|
||||
" model input num %d"%(len(input_list), self._input_num))
|
||||
return FAILED
|
||||
|
||||
self.input_dataset = acl.mdl.create_dataset()
|
||||
for i in range(self._input_num):
|
||||
item = input_list[i]
|
||||
# parse input, currently supports AclImage type, Acl pointer and numpy array
|
||||
data, size = self._parse_input_data(item, i)
|
||||
if (data is None) or (size == 0):
|
||||
# not parse the remaining data when parsing data fails
|
||||
ret = FAILED
|
||||
print("The %d input is invalid"%(i))
|
||||
break
|
||||
# create input dataset buffer structure, fill in input data
|
||||
dataset_buffer = acl.create_data_buffer(data, size)
|
||||
# add dataset buffer to dataset
|
||||
_, ret = acl.mdl.add_dataset_buffer(self.input_dataset,
|
||||
dataset_buffer)
|
||||
if ret:
|
||||
print("Add input dataset buffer failed")
|
||||
acl.destroy_data_buffer(self.input_dataset)
|
||||
ret = FAILED
|
||||
break
|
||||
if ret == FAILED:
|
||||
# release dataset if fails
|
||||
self._release_dataset(self.input_dataset)
|
||||
|
||||
return ret
|
||||
|
||||
def _parse_input_data(self, input, index):
|
||||
data = None
|
||||
size = 0
|
||||
if isinstance(input, AclImage):
|
||||
# if input data is AclImage, directly return memory pointer and sieze of image
|
||||
# defautly image memory is data on the device
|
||||
size = input.size
|
||||
data = input.data()
|
||||
elif isinstance(input, np.ndarray):
|
||||
# if input is numpy data, allocate device memory for data and copy data to device
|
||||
# allocated memory can be reused, no need to apply for it everytime
|
||||
ptr = acl.util.numpy_to_ptr(input)
|
||||
size = input.size * input.itemsize
|
||||
data = self._copy_input_to_device(ptr, size, index)
|
||||
if data == None:
|
||||
size = 0
|
||||
print("Copy input to device failed")
|
||||
# if directly input memory pointer, structure should be dict like {"data":, "size":}, and default memory is on the device side
|
||||
elif (isinstance(input, dict) and
|
||||
input.has_key('data') and input.has_key('size')):
|
||||
size = input['size']
|
||||
data = input['data']
|
||||
else:
|
||||
print("Unsupport input")
|
||||
|
||||
return data, size
|
||||
|
||||
def _copy_input_to_device(self, input_ptr, size, index):
|
||||
# allocate device memory for input, and copy data to this memory
|
||||
buffer_item = self._input_buffer[index]
|
||||
data = None
|
||||
# according to the index of the data in the model input, check whether the input has already been allocated memory
|
||||
if buffer_item['addr'] is None:
|
||||
# if not, allocate memory, copy data and record memory for resue
|
||||
data = copy_data_device_to_device(input_ptr, size)
|
||||
if data is None:
|
||||
print("Malloc memory and copy model %dth "
|
||||
"input to device failed"%(index))
|
||||
return None
|
||||
buffer_item['addr'] = data
|
||||
buffer_item['size'] = size
|
||||
elif size == buffer_item['size']:
|
||||
# if memory has already been allocated for the input, and memory size is consistent with current input data
|
||||
# copy data to this memory for inference
|
||||
ret = acl.rt.memcpy(buffer_item['addr'], size,
|
||||
input_ptr, size,
|
||||
ACL_MEMCPY_DEVICE_TO_DEVICE)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Copy model %dth input to device failed"%(index))
|
||||
return None
|
||||
data = buffer_item['addr']
|
||||
else:
|
||||
# if memory has already been allocated for the input, but memory size is not consistent with current input data
|
||||
# it would be considered as exception. because size of each model input is fixed
|
||||
print("The model %dth input size %d is change,"
|
||||
" before is %d"%(index, size, buffer_item['size']))
|
||||
return None
|
||||
|
||||
return data
|
||||
|
||||
def execute(self, input_list):
|
||||
# create dataset object instance for offline model inference
|
||||
ret = self._gen_input_dataset(input_list)
|
||||
if ret == FAILED:
|
||||
print("Gen model input dataset failed")
|
||||
return None
|
||||
# call execute inference data of offline model
|
||||
start = datetime.datetime.now()
|
||||
ret = acl.mdl.execute(self.model_id,
|
||||
self.input_dataset,
|
||||
self.output_dataset)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Execute model failed for acl.mdl.execute error ", ret)
|
||||
return None
|
||||
end = datetime.datetime.now()
|
||||
print("acl.mdl.execute exhaust ", end - start)
|
||||
# release input dataset object instance without releasing input data memory
|
||||
#self._release_dataset(self.input_dataset)
|
||||
# decode the binary data stream output from inference to numpy array, shape and datatype of the array are consistent with model outputs
|
||||
return self._output_dataset_to_numpy()
|
||||
|
||||
def _output_dataset_to_numpy(self):
|
||||
dataset = []
|
||||
num = acl.mdl.get_dataset_num_buffers(self.output_dataset)
|
||||
# iterative each output
|
||||
for i in range(num):
|
||||
# obtain memory address from output buffer
|
||||
buffer = acl.mdl.get_dataset_buffer(self.output_dataset, i)
|
||||
data = acl.get_data_buffer_addr(buffer)
|
||||
size = int(acl.get_data_buffer_size(buffer))
|
||||
output_ptr = self._output_info[i]["ptr"]
|
||||
output_tensor = self._output_info[i]["tensor"]
|
||||
ret = acl.rt.memcpy(output_ptr, output_tensor.size*output_tensor.itemsize,
|
||||
data, size, ACL_MEMCPY_DEVICE_TO_DEVICE)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Memcpy inference output to local failed")
|
||||
return None
|
||||
|
||||
dataset.append(output_tensor)
|
||||
|
||||
return dataset
|
||||
|
||||
def _release_dataset(self, dataset):
|
||||
if not dataset:
|
||||
return
|
||||
print("destroy dataset")
|
||||
num = acl.mdl.get_dataset_num_buffers(dataset)
|
||||
for i in range(num):
|
||||
data_buf = acl.mdl.get_dataset_buffer(dataset, i)
|
||||
if data_buf:
|
||||
ret = acl.destroy_data_buffer(data_buf)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Destroy data buffer error ", ret)
|
||||
ret = acl.mdl.destroy_dataset(dataset)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Destroy data buffer error ", ret)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import acl
|
||||
|
||||
from atlas_utils.utils import *
|
||||
|
||||
class AclResource(object):
|
||||
def __init__(self, device_id=0):
|
||||
self.device_id = device_id
|
||||
self.context = None
|
||||
self.stream = None
|
||||
self.run_mode = None
|
||||
|
||||
def init(self):
|
||||
print("init resource stage:")
|
||||
ret = acl.init()
|
||||
check_ret("acl.rt.set_device", ret)
|
||||
|
||||
ret = acl.rt.set_device(self.device_id)
|
||||
check_ret("acl.rt.set_device", ret)
|
||||
|
||||
self.context, ret = acl.rt.create_context(self.device_id)
|
||||
check_ret("acl.rt.create_context", ret)
|
||||
|
||||
self.stream, ret = acl.rt.create_stream()
|
||||
check_ret("acl.rt.create_stream", ret)
|
||||
|
||||
self.run_mode, ret = acl.rt.get_run_mode()
|
||||
check_ret("acl.rt.get_run_mode", ret)
|
||||
|
||||
print("Init resource success")
|
||||
|
||||
def __del__(self):
|
||||
if self.stream:
|
||||
acl.rt.destroy_stream(self.stream)
|
||||
if self.context:
|
||||
acl.rt.destroy_context(self.context)
|
||||
acl.rt.reset_device(self.device_id)
|
||||
acl.finalize()
|
||||
print("Release acl resource success")
|
||||
@@ -0,0 +1,115 @@
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
import copy
|
||||
|
||||
import acl
|
||||
#from utils import *
|
||||
from atlas_utils.constants import *
|
||||
|
||||
|
||||
class AclImage():
|
||||
def __init__(self, image, width=0, height=0,
|
||||
size=0, memory_type=MEMORY_NORMAL):
|
||||
self._data = None
|
||||
self._np_array = None
|
||||
self._memory_type = memory_type
|
||||
self.width = 0
|
||||
self.height = 0
|
||||
self.channels = 0
|
||||
self.size = 0
|
||||
|
||||
if isinstance(image, str):
|
||||
self._instance_by_image_file(image)
|
||||
elif str(type(image))=="<class 'numpy.ndarray'>":
|
||||
self._instance_by_numpy_array(image,width,height)
|
||||
elif isinstance(image, int):
|
||||
self._instance_by_buffer(image, width, height, size)
|
||||
else:
|
||||
print("Create instance failed for unknow image data type")
|
||||
|
||||
def _instance_by_numpy_array(self, image,width,height):
|
||||
self._data = image
|
||||
self._type = IMAGE_DATA_NUMPY
|
||||
self.size = self._data.itemsize * self._data.size
|
||||
self.width = width
|
||||
self.height = height
|
||||
|
||||
def _instance_by_image_file(self, image_path):
|
||||
self._data = np.fromfile(image_path, dtype=np.byte)
|
||||
self._type = IMAGE_DATA_NUMPY
|
||||
self.size = self._data.itemsize * self._data.size
|
||||
image = Image.open(image_path)
|
||||
self.width, self.height = image.size
|
||||
|
||||
def _instance_by_buffer(self, image_buffer, width, height, size):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.size = size
|
||||
self._data = image_buffer
|
||||
self._type = IMAGE_DATA_BUFFER
|
||||
|
||||
def tobytes(self):
|
||||
if self._type == IMAGE_DATA_NUMPY:
|
||||
return self._data
|
||||
else:
|
||||
return acl.util.ptr_to_numpy(self._data, (self.size, ), NPY_BYTE).tobytes()
|
||||
|
||||
def data(self):
|
||||
if self._type == IMAGE_DATA_NUMPY:
|
||||
return acl.util.numpy_to_ptr(self._data)
|
||||
else:
|
||||
return self._data
|
||||
|
||||
def copy_to_device(self, run_mode):
|
||||
device_ptr = None
|
||||
if run_mode == ACL_HOST:
|
||||
device_ptr = copy_data_host_to_device(self.data(), self.size)
|
||||
else:
|
||||
device_ptr = copy_data_device_to_device(self.data(), self.size)
|
||||
if device_ptr is None:
|
||||
print("Copy image to device failed ")
|
||||
return None
|
||||
|
||||
print("image copyt to device ", device_ptr, "%d, %d, %d"%(self.width,
|
||||
self.height, self.size))
|
||||
return AclImage(device_ptr, self.width,
|
||||
self.height, self.size, MEMORY_DEVICE)
|
||||
|
||||
def copy_as_nparray(self):
|
||||
if self._type == IMAGE_DATA_BUFFER:
|
||||
#np_output = np.zeros(self.size, dtype=np.byte)
|
||||
#if not np_output.flags['C_CONTIGUOUS']:
|
||||
# np_output = np.ascontiguousarray(np_output)
|
||||
np_output_ptr, ret = acl.rt.malloc(self.size, ACL_MEM_MALLOC_NORMAL_ONLY)
|
||||
print("image ", np_output_ptr)
|
||||
ret = acl.rt.memcpy(np_output_ptr, self.size, self._data, self.size, 3)
|
||||
if (ret != ACL_ERROR_NONE):
|
||||
print("Copy mage to np array failed for memcpy error ", ret)
|
||||
return None
|
||||
return copy.deepcopy(acl.util.ptr_to_numpy(np_output_ptr, (self.size, ), NPY_BYTE))
|
||||
else:
|
||||
return self._data.copy()
|
||||
|
||||
def destroy(self):
|
||||
if (self._data is None) or (self.size == 0):
|
||||
print("Release image abnormaly, data is None")
|
||||
return
|
||||
|
||||
if self._memory_type == MEMORY_DEVICE:
|
||||
acl.rt.free(self._data)
|
||||
elif self._memory_type == MEMORY_HOST:
|
||||
acl.rt.free_host(self._data)
|
||||
elif self._memory_type == MEMORY_DVPP:
|
||||
acl.media.dvpp_free(self._data)
|
||||
|
||||
self._data = None
|
||||
self.size = 0
|
||||
|
||||
def __del__(self):
|
||||
self.destroy()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
# !/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
#
|
||||
from ctypes import *
|
||||
import os
|
||||
import time
|
||||
import sys
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.append(BASE_DIR)
|
||||
|
||||
from lib.atlasutil_so import libatlas
|
||||
from constants import *
|
||||
from acl_image import AclImage
|
||||
|
||||
CAMERA_OK = 0
|
||||
CAMERA_ERROR = 1
|
||||
|
||||
CAMERA_CLOSED = 0
|
||||
CAMERA_OPENED = 1
|
||||
|
||||
INVALID_IMAGE_PTR = 0
|
||||
|
||||
class CameraOutputC(Structure):
|
||||
_fields_ = [
|
||||
('size', c_int),
|
||||
('data', POINTER(c_ubyte))
|
||||
]
|
||||
|
||||
|
||||
class Camera():
|
||||
def __init__(self, id, fps=20, size=(1280, 720)):
|
||||
self._id = id
|
||||
self._fps = fps
|
||||
self._width = size[0]
|
||||
self._height = size[1]
|
||||
self._size = int(self._width * self._height * 3 / 2)
|
||||
self._status = CAMERA_CLOSED
|
||||
if CAMERA_OK == self._open():
|
||||
self._status = CAMERA_OPENED
|
||||
else:
|
||||
print("Open camera %d failed"%(id))
|
||||
|
||||
def _open(self):
|
||||
ret = libatlas.OpenCameraEx(self._id, self._fps,
|
||||
self._width, self._height)
|
||||
print(ret)
|
||||
if (ret != CAMERA_OK):
|
||||
print("ERROR:Open camera %d failed ,ret = %d"%(self._id, ret))
|
||||
return CAMERA_ERROR
|
||||
self._status = CAMERA_OPENED
|
||||
return CAMERA_OK
|
||||
|
||||
def is_opened(self):
|
||||
return (self._status == CAMERA_OPENED)
|
||||
|
||||
def read(self):
|
||||
frame_data = CameraOutputC()
|
||||
ret = libatlas.ReadCameraFrame(self._id, byref(frame_data))
|
||||
if (ret != CAMERA_OK):
|
||||
print("ERROR:Read camera %d failed"%(self._id))
|
||||
return None
|
||||
|
||||
return AclImage(addressof(frame_data.data.contents),
|
||||
self._width, self._height, self._size, MEMORY_DVPP)
|
||||
|
||||
def close(self):
|
||||
print("Close camera ", self._id)
|
||||
libatlas.CloseCameraEx(self._id)
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
cap = Camera(id=0, fps=20, size=(1280, 720))
|
||||
|
||||
start = time.time()
|
||||
for i in range(0,100):
|
||||
image = cap.read()
|
||||
print("Read 100 frame exhaust ", time.time() - start)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
"""
|
||||
Copyright (R) @huawei.com, all rights reserved
|
||||
-*- coding:utf-8 -*-
|
||||
CREATED: 2020-6-04 20:12:13
|
||||
MODIFIED: 2020-6-06 14:04:45
|
||||
"""
|
||||
SUCCESS = 0
|
||||
FAILED = 1
|
||||
|
||||
ACL_DEVICE = 0
|
||||
ACL_HOST = 1
|
||||
|
||||
MEMORY_NORMAL = 0
|
||||
MEMORY_HOST = 1
|
||||
MEMORY_DEVICE = 2
|
||||
MEMORY_DVPP = 3
|
||||
MEMORY_CTYPES = 4
|
||||
|
||||
IMAGE_DATA_NUMPY = 0
|
||||
IMAGE_DATA_BUFFER = 1
|
||||
|
||||
|
||||
# error code
|
||||
ACL_ERROR_NONE = 0
|
||||
ACL_ERROR_INVALID_PARAM = 100000
|
||||
ACL_ERROR_UNINITIALIZE = 100001
|
||||
ACL_ERROR_REPEAT_INITIALIZE = 100002
|
||||
ACL_ERROR_INVALID_FILE = 100003
|
||||
ACL_ERROR_WRITE_FILE = 100004
|
||||
ACL_ERROR_INVALID_FILE_SIZE = 100005
|
||||
ACL_ERROR_PARSE_FILE = 100006
|
||||
ACL_ERROR_FILE_MISSING_ATTR = 100007
|
||||
ACL_ERROR_FILE_ATTR_INVALID = 100008
|
||||
ACL_ERROR_INVALID_DUMP_CONFIG = 100009
|
||||
ACL_ERROR_INVALID_PROFILING_CONFIG = 100010
|
||||
ACL_ERROR_INVALID_MODEL_ID = 100011
|
||||
ACL_ERROR_DESERIALIZE_MODEL = 100012
|
||||
ACL_ERROR_PARSE_MODEL = 100013
|
||||
ACL_ERROR_READ_MODEL_FAILURE = 100014
|
||||
ACL_ERROR_MODEL_SIZE_INVALID = 100015
|
||||
ACL_ERROR_MODEL_MISSING_ATTR = 100016
|
||||
ACL_ERROR_MODEL_INPUT_NOT_MATCH = 100017
|
||||
ACL_ERROR_MODEL_OUTPUT_NOT_MATCH = 100018
|
||||
ACL_ERROR_MODEL_NOT_DYNAMIC = 100019
|
||||
ACL_ERROR_OP_TYPE_NOT_MATCH = 100020
|
||||
ACL_ERROR_OP_INPUT_NOT_MATCH = 100021
|
||||
ACL_ERROR_OP_OUTPUT_NOT_MATCH = 100022
|
||||
ACL_ERROR_OP_ATTR_NOT_MATCH = 100023
|
||||
ACL_ERROR_OP_NOT_FOUND = 100024
|
||||
ACL_ERROR_OP_LOAD_FAILED = 100025
|
||||
ACL_ERROR_UNSUPPORTED_DATA_TYPE = 100026
|
||||
ACL_ERROR_FORMAT_NOT_MATCH = 100027
|
||||
ACL_ERROR_BIN_SELECTOR_NOT_REGISTERED = 100028
|
||||
ACL_ERROR_KERNEL_NOT_FOUND = 100029
|
||||
ACL_ERROR_BIN_SELECTOR_ALREADY_REGISTERED = 100030
|
||||
ACL_ERROR_KERNEL_ALREADY_REGISTERED = 100031
|
||||
ACL_ERROR_INVALID_QUEUE_ID = 100032
|
||||
ACL_ERROR_REPEAT_SUBSCRIBE = 100033
|
||||
ACL_ERROR_STREAM_NOT_SUBSCRIBE = 100034
|
||||
ACL_ERROR_THREAD_NOT_SUBSCRIBE = 100035
|
||||
ACL_ERROR_WAIT_CALLBACK_TIMEOUT = 100036
|
||||
ACL_ERROR_REPEAT_FINALIZE = 100037
|
||||
ACL_ERROR_BAD_ALLOC = 200000
|
||||
ACL_ERROR_API_NOT_SUPPORT = 200001
|
||||
ACL_ERROR_INVALID_DEVICE = 200002
|
||||
ACL_ERROR_MEMORY_ADDRESS_UNALIGNED = 200003
|
||||
ACL_ERROR_RESOURCE_NOT_MATCH = 200004
|
||||
ACL_ERROR_INVALID_RESOURCE_HANDLE = 200005
|
||||
ACL_ERROR_STORAGE_OVER_LIMIT = 300000
|
||||
ACL_ERROR_INTERNAL_ERROR = 500000
|
||||
ACL_ERROR_FAILURE = 500001
|
||||
ACL_ERROR_GE_FAILURE = 500002
|
||||
ACL_ERROR_RT_FAILURE = 500003
|
||||
ACL_ERROR_DRV_FAILURE = 500004
|
||||
# rule for mem
|
||||
ACL_MEM_MALLOC_HUGE_FIRST = 0
|
||||
ACL_MEM_MALLOC_HUGE_ONLY = 1
|
||||
ACL_MEM_MALLOC_NORMAL_ONLY = 2
|
||||
# rule for memory copy
|
||||
ACL_MEMCPY_HOST_TO_HOST = 0
|
||||
ACL_MEMCPY_HOST_TO_DEVICE = 1
|
||||
ACL_MEMCPY_DEVICE_TO_HOST = 2
|
||||
ACL_MEMCPY_DEVICE_TO_DEVICE = 3
|
||||
# input
|
||||
LAST_ONE = -1
|
||||
LAST_TWO = -2
|
||||
type_dict = {
|
||||
"bool": 0,
|
||||
"int8": 1,
|
||||
"int16": 2,
|
||||
"int32": 4,
|
||||
"int64": 8,
|
||||
"uint8": 1,
|
||||
"uint16": 2,
|
||||
"uint32": 4,
|
||||
"uint64": 8,
|
||||
"float16": 2,
|
||||
"float32": 4,
|
||||
"float64": 8,
|
||||
"float_": 8
|
||||
}
|
||||
NPY_BOOL = 0
|
||||
NPY_BYTE = 1
|
||||
NPY_UBYTE = 2
|
||||
NPY_SHORT = 3
|
||||
NPY_USHORT = 4
|
||||
NPY_INT = 5
|
||||
NPY_UINT = 6
|
||||
NPY_LONG = 7
|
||||
NPY_ULONG = 8
|
||||
NPY_LONGLONG = 9
|
||||
NPY_ULONGLONG = 10
|
||||
|
||||
ACL_DT_UNDEFINED = -1
|
||||
ACL_FLOAT = 0
|
||||
ACL_FLOAT16 = 1
|
||||
ACL_INT8 = 2
|
||||
ACL_INT32 = 3
|
||||
ACL_UINT8 = 4
|
||||
ACL_INT16 = 6
|
||||
ACL_UINT16 = 7
|
||||
ACL_UINT32 = 8
|
||||
ACL_INT64 = 9
|
||||
ACL_UINT64 = 10
|
||||
ACL_DOUBLE = 11
|
||||
ACL_BOOL = 12
|
||||
|
||||
|
||||
|
||||
# data format
|
||||
ACL_FORMAT_UNDEFINED = -1
|
||||
ACL_FORMAT_NCHW = 0
|
||||
ACL_FORMAT_NHWC = 1
|
||||
ACL_FORMAT_ND = 2
|
||||
ACL_FORMAT_NC1HWC0 = 3
|
||||
ACL_FORMAT_FRACTAL_Z = 4
|
||||
ACL_DT_UNDEFINED = -1
|
||||
ACL_FLOAT = 0
|
||||
ACL_FLOAT16 = 1
|
||||
ACL_INT8 = 2
|
||||
ACL_INT32 = 3
|
||||
ACL_UINT8 = 4
|
||||
ACL_INT16 = 6
|
||||
ACL_UINT16 = 7
|
||||
ACL_UINT32 = 8
|
||||
ACL_INT64 = 9
|
||||
ACL_UINT64 = 10
|
||||
ACL_DOUBLE = 11
|
||||
ACL_BOOL = 12
|
||||
acl_dtype = {
|
||||
"dt_undefined": -1,
|
||||
"float": 0,
|
||||
"float16": 1,
|
||||
"int8": 2,
|
||||
"int32": 3,
|
||||
"uint8": 4,
|
||||
"int16": 6,
|
||||
"uint16": 7,
|
||||
"uint32": 8,
|
||||
"int64": 9,
|
||||
"double": 11,
|
||||
"bool": 12
|
||||
}
|
||||
ACL_CALLBACK_NO_BLOCK = 0
|
||||
ACL_CALLBACK_BLOCK = 1
|
||||
PIXEL_FORMAT_YUV_400 = 0 # 0, YUV400 8bit
|
||||
PIXEL_FORMAT_YUV_SEMIPLANAR_420 = 1 # 1, YUV420SP NV12 8bit
|
||||
PIXEL_FORMAT_YVU_SEMIPLANAR_420 = 2 # 2, YUV420SP NV21 8bit
|
||||
PIXEL_FORMAT_YUV_SEMIPLANAR_422 = 3 # 3, YUV422SP NV12 8bit
|
||||
PIXEL_FORMAT_YVU_SEMIPLANAR_422 = 4 # 4, YUV422SP NV21 8bit
|
||||
PIXEL_FORMAT_YUV_SEMIPLANAR_444 = 5 # 5, YUV444SP NV12 8bit
|
||||
PIXEL_FORMAT_YVU_SEMIPLANAR_444 = 6 # 6, YUV444SP NV21 8bit
|
||||
PIXEL_FORMAT_YUYV_PACKED_422 = 7 # 7, YUV422P YUYV 8bit
|
||||
PIXEL_FORMAT_UYVY_PACKED_422 = 8 # 8, YUV422P UYVY 8bit
|
||||
PIXEL_FORMAT_YVYU_PACKED_422 = 9 # 9, YUV422P YVYU 8bit
|
||||
PIXEL_FORMAT_VYUY_PACKED_422 = 10 # 10, YUV422P VYUY 8bit
|
||||
PIXEL_FORMAT_YUV_PACKED_444 = 11 # 11, YUV444P 8bit
|
||||
PIXEL_FORMAT_RGB_888 = 12 # 12, RGB888
|
||||
PIXEL_FORMAT_BGR_888 = 13 # 13, BGR888
|
||||
PIXEL_FORMAT_ARGB_8888 = 14 # 14, ARGB8888
|
||||
PIXEL_FORMAT_ABGR_8888 = 15 # 15, ABGR8888
|
||||
PIXEL_FORMAT_RGBA_8888 = 16 # 16, RGBA8888
|
||||
PIXEL_FORMAT_BGRA_8888 = 17 # 17, BGRA8888
|
||||
PIXEL_FORMAT_YUV_SEMI_PLANNER_420_10BIT = 18 # 18, YUV420SP 10bit
|
||||
PIXEL_FORMAT_YVU_SEMI_PLANNER_420_10BIT = 19 # 19, YVU420sp 10bit
|
||||
PIXEL_FORMAT_YVU_PLANAR_420 = 20 # 20, YUV420P 8bit
|
||||
# images format
|
||||
IMG_EXT = ['.jpg', '.JPG', '.png', '.PNG', '.bmp', '.BMP', '.jpeg', '.JPEG']
|
||||
@@ -0,0 +1,20 @@
|
||||
import threading
|
||||
import ctypes
|
||||
import os
|
||||
|
||||
|
||||
class _AtlasutilLib(object):
|
||||
_instance_lock = threading.Lock()
|
||||
lib = ctypes.CDLL(os.path.dirname(os.path.abspath(__file__)) + '/libatlasutil.so')
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if not hasattr(_AtlasutilLib, "_instance"):
|
||||
with _AtlasutilLib._instance_lock:
|
||||
if not hasattr(_AtlasutilLib, "_instance"):
|
||||
_AtlasutilLib._instance = object.__new__(cls)
|
||||
return _AtlasutilLib._instance
|
||||
|
||||
libatlas = _AtlasutilLib.lib
|
||||
@@ -0,0 +1,59 @@
|
||||
TOPDIR := $(patsubst %,%,$(CURDIR))
|
||||
|
||||
ifndef DDK_PATH
|
||||
$(error "Can not find DDK_PATH env, please set it in environment!.")
|
||||
endif
|
||||
|
||||
LOCAL_MODULE_NAME := libatlasutil.so
|
||||
CC := aarch64-linux-gnu-g++
|
||||
|
||||
|
||||
LOCAL_DIR := .
|
||||
OUT_DIR = out
|
||||
OBJ_DIR = $(OUT_DIR)/obj
|
||||
DEPS_DIR = $(OUT_DIR)/deps
|
||||
LOCAL_LIBRARY=$(OUT_DIR)/$(LOCAL_MODULE_NAME)
|
||||
OUT_INC_DIR = $(OUT_DIR)/include
|
||||
|
||||
INC_DIR = \
|
||||
-I$(HOME)/Ascend/driver/ \
|
||||
-I$(DDK_PATH)/../arm64-linux_gcc7.3.0/acllib/include/
|
||||
|
||||
|
||||
CC_FLAGS := $(INC_DIR) -DENABLE_DVPP_INTERFACE -std=c++11 -fPIC -Wall -O2
|
||||
LNK_FLAGS := \
|
||||
-L$(NPU_HOST_LIB) \
|
||||
-L$(HOME)/Ascend/driver \
|
||||
-lmedia_mini \
|
||||
-lascendcl \
|
||||
-lacl_dvpp \
|
||||
-shared
|
||||
|
||||
SRCS := $(patsubst $(LOCAL_DIR)/%.cpp, %.cpp, $(shell find $(LOCAL_DIR) -name "*.cpp"))
|
||||
OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.cpp, %.o,$(SRCS)))
|
||||
|
||||
ALL_OBJS := $(OBJS)
|
||||
|
||||
all: do_pre_build do_build
|
||||
|
||||
do_pre_build:
|
||||
$(Q)echo - do [$@]
|
||||
$(Q)mkdir -p $(OBJ_DIR)
|
||||
$(Q)mkdir -p $(OUT_INC_DIR)
|
||||
|
||||
do_build: $(LOCAL_LIBRARY) | do_pre_build
|
||||
$(Q)echo - do [$@]
|
||||
|
||||
$(LOCAL_LIBRARY): $(ALL_OBJS)
|
||||
$(Q)echo [LD] $@
|
||||
$(Q)$(CC) $(CC_FLAGS) -o $@ $^ -Wl,--whole-archive -Wl,--no-whole-archive -Wl,--start-group -Wl,--end-group -Wl,-rpath='/home/HwHiAiUser/HIAI_PROJECTS/ascend_lib' $(LNK_FLAGS)
|
||||
|
||||
|
||||
$(OBJS): $(OBJ_DIR)/%.o : %.cpp | do_pre_build
|
||||
$(Q)echo [CC] $@
|
||||
$(Q)mkdir -p $(dir $@)
|
||||
$(Q)$(CC) $(CC_FLAGS) $(INC_DIR) -c -fstack-protector-all $< -o $@
|
||||
|
||||
|
||||
clean:
|
||||
rm -rf $(TOPDIR)/out
|
||||
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* ============================================================================
|
||||
*
|
||||
* Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1 Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2 Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3 Neither the names of the copyright holders nor the names of the
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
* ============================================================================
|
||||
*/
|
||||
#include <memory>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "acl/acl.h"
|
||||
#include "acl/ops/acl_dvpp.h"
|
||||
#include "atlas_utils_common.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
extern "C" {
|
||||
|
||||
#if 0
|
||||
void* CopyDataHostToDvpp(void* data, int size) {
|
||||
void* buffer = nullptr;
|
||||
|
||||
auto aclRet = acldvppMalloc(&buffer, size);
|
||||
if (aclRet != ACL_ERROR_NONE) {
|
||||
ASC_LOG_ERROR("acl malloc dvpp data failed, dataSize=%u, ret=%d",
|
||||
size, aclRet);
|
||||
return nullptr;
|
||||
}
|
||||
printf("malloc dvpp memory size %d ok", size);
|
||||
// copy input to device memory
|
||||
aclRet = aclrtMemcpy(buffer, size, data, size, ACL_MEMCPY_HOST_TO_DEVICE);
|
||||
if (aclRet != ACL_ERROR_NONE) {
|
||||
ASC_LOG_ERROR("acl memcpy data to dvpp failed, size %u, error %d", size, aclRet);
|
||||
acldvppFree(buffer);
|
||||
return nullptr;
|
||||
}
|
||||
printf("copy data to dvpp ok");
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void* CopyDataHostToDevice(void* data, int size) {
|
||||
void* buffer = nullptr;
|
||||
|
||||
auto aclRet = aclrtMalloc(&buffer, size, ACL_MEM_MALLOC_NORMAL_ONLY);
|
||||
if (aclRet != ACL_ERROR_NONE) {
|
||||
ASC_LOG_ERROR("acl malloc device memory failed, dataSize=%u, ret=%d",
|
||||
size, aclRet);
|
||||
return nullptr;
|
||||
}
|
||||
// copy input to device memory
|
||||
aclRet = aclrtMemcpy(buffer, size, data, size, ACL_MEMCPY_HOST_TO_DEVICE);
|
||||
if (aclRet != ACL_ERROR_NONE) {
|
||||
ASC_LOG_ERROR("acl memcpy data to dev failed, size %u, error %d", size, aclRet);
|
||||
aclrtFree(buffer);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void* CopyDataDeviceToDevice(void* data, int size) {
|
||||
void* buffer = nullptr;
|
||||
|
||||
auto aclRet = aclrtMalloc(&buffer, size, ACL_MEM_MALLOC_NORMAL_ONLY);
|
||||
if (aclRet != ACL_ERROR_NONE) {
|
||||
ASC_LOG_ERROR("acl malloc device memory failed, dataSize=%u, ret=%d",
|
||||
size, aclRet);
|
||||
return nullptr;
|
||||
}
|
||||
// copy input to device memory
|
||||
aclRet = aclrtMemcpy(buffer, size, data, size, ACL_MEMCPY_DEVICE_TO_DEVICE);
|
||||
if (aclRet != ACL_ERROR_NONE) {
|
||||
ASC_LOG_ERROR("acl memcpy data to dev failed, size %u, error %d", size, aclRet);
|
||||
aclrtFree(buffer);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void* CopyDataDeviceToHost(void* deviceData, uint32_t dataLen) {
|
||||
void *outHostData = nullptr;
|
||||
|
||||
aclError ret = aclrtMallocHost(&outHostData, dataLen);
|
||||
if (ret != ACL_ERROR_NONE) {
|
||||
ASC_LOG_ERROR("aclrtMallocHost failed, ret[%d]", ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ret = aclrtMemcpy(outHostData, dataLen, deviceData,
|
||||
dataLen, ACL_MEMCPY_DEVICE_TO_HOST);
|
||||
if (ret != ACL_ERROR_NONE) {
|
||||
ASC_LOG_ERROR("aclrtMemcpy failed, ret[%d]", ret);
|
||||
aclrtFreeHost(outHostData);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return outHostData;
|
||||
}
|
||||
|
||||
void* CopyDataDeviceToNewBuf(void* deviceData, uint32_t dataLen) {
|
||||
uint8_t* outHostData = new uint8_t[dataLen];
|
||||
|
||||
/* aclError ret = aclrtMallocHost(&outHostData, dataLen);
|
||||
if (ret != ACL_ERROR_NONE) {
|
||||
ASC_LOG_ERROR("aclrtMallocHost failed, ret[%d]", ret);
|
||||
return nullptr;
|
||||
}
|
||||
*/
|
||||
int ret = aclrtMemcpy(outHostData, dataLen, deviceData,
|
||||
dataLen, ACL_MEMCPY_DEVICE_TO_HOST);
|
||||
if (ret != ACL_ERROR_NONE) {
|
||||
ASC_LOG_ERROR("aclrtMemcpy failed, ret[%d]", ret);
|
||||
aclrtFreeHost(outHostData);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (void *)outHostData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SaveBinFile(const char* filename, void* data, uint32_t size) {
|
||||
FILE *outFileFp = fopen(filename, "wb+");
|
||||
if (outFileFp == nullptr) {
|
||||
ASC_LOG_ERROR("Save file %s failed for open error", filename);
|
||||
return;
|
||||
}
|
||||
fwrite(data, 1, size, outFileFp);
|
||||
|
||||
fflush(outFileFp);
|
||||
fclose(outFileFp);
|
||||
}
|
||||
|
||||
char* ReadBinFile(const std::string& fileName, uint32_t& fileSize)
|
||||
{
|
||||
std::ifstream binFile(fileName, std::ifstream::binary);
|
||||
if (binFile.is_open() == false) {
|
||||
ASC_LOG_ERROR("open file %s failed", fileName.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
binFile.seekg(0, binFile.end);
|
||||
uint32_t binFileBufferLen = binFile.tellg();
|
||||
if (binFileBufferLen == 0) {
|
||||
ASC_LOG_ERROR("binfile is empty, filename is %s", fileName.c_str());
|
||||
binFile.close();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
binFile.seekg(0, binFile.beg);
|
||||
|
||||
char* binFileBufferData = new(std::nothrow) char[binFileBufferLen];
|
||||
if (binFileBufferData == nullptr) {
|
||||
ASC_LOG_ERROR("malloc binFileBufferData failed");
|
||||
binFile.close();
|
||||
return nullptr;
|
||||
}
|
||||
binFile.read(binFileBufferData, binFileBufferLen);
|
||||
binFile.close();
|
||||
fileSize = binFileBufferLen;
|
||||
return binFileBufferData;
|
||||
}
|
||||
|
||||
int ReadImageFile(ImageData* image, const string& filename) {
|
||||
char* data;
|
||||
uint32_t size = 0;
|
||||
|
||||
data = ReadBinFile(filename, size);
|
||||
if (data == nullptr) {
|
||||
ASC_LOG_ERROR("Read image file %s failed", filename.c_str());
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
image->data = SHARED_PRT_U8_BUF(data);
|
||||
image->size = size;
|
||||
printf("read image ok, size %d", size);
|
||||
return STATUS_OK;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* ============================================================================
|
||||
*
|
||||
* Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1 Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2 Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3 Neither the names of the copyright holders nor the names of the
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
* ============================================================================
|
||||
*/
|
||||
|
||||
#ifndef _ATLAS_UTILS_COMMON_H_
|
||||
#define _ATLAS_UTILS_COMMON_H_
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
#include "acl/acl_base.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define STATUS_ERROR -1
|
||||
#define STATUS_OK 0
|
||||
|
||||
#define ALIGN_UP(num, align) (((num) + (align) - 1) & ~((align) - 1))
|
||||
#define ALIGN_UP2(num) ALIGN_UP(num, 2)
|
||||
#define ALIGN_UP16(num) ALIGN_UP(num, 16)
|
||||
#define ALIGN_UP128(num) ALIGN_UP(num, 128)
|
||||
|
||||
#define YUV420SP_SIZE(width, height) ((width) * (height) * 3 / 2)
|
||||
//#define SHARED_PRT_DVPP_BUF(buf) (shared_ptr<uint8_t>((uint8_t *)(buf), [](uint8_t* p) { acldvppFree(p); }))
|
||||
//#define SHARED_PRT_U8_BUF(buf) (shared_ptr<uint8_t>((uint8_t *)(buf), [](uint8_t* p) { delete[](p); }))
|
||||
|
||||
|
||||
#define ASC_LOG_ERROR(fmt, ...) \
|
||||
do{aclAppLog(ACL_ERROR, __FUNCTION__, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \
|
||||
printf(fmt"\n", ##__VA_ARGS__);}while(0)
|
||||
|
||||
#define ASC_LOG_INFO(fmt, ...) \
|
||||
do{aclAppLog(ACL_INFO, __FUNCTION__, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \
|
||||
printf(fmt"\n", ##__VA_ARGS__);}while(0)
|
||||
|
||||
#define ASC_LOG_DEBUG(fmt, ...) \
|
||||
do{aclAppLog(ACL_DEBUG, __FUNCTION__, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \
|
||||
printf(fmt"\n", ##__VA_ARGS__);}while(0)
|
||||
#if 0
|
||||
struct ImageData {
|
||||
bool isAligned = false;
|
||||
uint32_t format = 1; //PIXEL_FORMAT_YUV_SEMIPLANAR_420;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
uint32_t alignWidth = 0;
|
||||
uint32_t alignHeight = 0;
|
||||
uint32_t size = 0;
|
||||
std::shared_ptr<uint8_t> data;
|
||||
};
|
||||
|
||||
struct FrameData {
|
||||
bool isFinished = false;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
uint32_t frameId = 0;
|
||||
ImageData image;
|
||||
};
|
||||
|
||||
struct Resolution {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
struct BoxArea {
|
||||
uint32_t ltx;
|
||||
uint32_t lty;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
|
||||
struct DataBuffer {
|
||||
uint32_t size;
|
||||
std::shared_ptr<void> data;
|
||||
};
|
||||
|
||||
struct DetectionData {
|
||||
ImageData image;
|
||||
std::vector<DataBuffer> output;
|
||||
};
|
||||
|
||||
struct AtlasMessage {
|
||||
int dest;
|
||||
int msgId;
|
||||
std::shared_ptr<void> data;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
void* CopyDataDeviceToHost(void* deviceData, uint32_t dataLen);
|
||||
void* CopyDataHostToDvpp(void* data, int size);
|
||||
void* CopyDataHostToDevice(void* data, int size);
|
||||
void* CopyDataDeviceToDevice(void* data, int size);
|
||||
void* CopyDataDeviceToNewBuf(void* deviceData, uint32_t dataLen);
|
||||
|
||||
void SaveBinFile(const char* filename, void* data, uint32_t size);
|
||||
int ReadImageFile(ImageData* image, const string& filename);
|
||||
|
||||
}
|
||||
#endif
|
||||
#endif /* HIAI_APP_IMAGE_POOL_H_ */
|
||||
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* ============================================================================
|
||||
*
|
||||
* Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1 Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2 Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3 Neither the names of the copyright holders nor the names of the
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
* ============================================================================
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <memory>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "acl/acl.h"
|
||||
#include "acl/ops/acl_dvpp.h"
|
||||
#include "atlas_utils_common.h"
|
||||
#include "camera.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
extern "C" {
|
||||
#include "peripheral_api.h"
|
||||
#include "camera.h"
|
||||
|
||||
CameraManager g_CameraMgr;
|
||||
|
||||
int CameraInit(int id, int fps, int width, int height) {
|
||||
if (!g_CameraMgr.hwInited) {
|
||||
MediaLibInit();
|
||||
g_CameraMgr.hwInited = 1;
|
||||
}
|
||||
|
||||
Camera& cap = CAMERA(id);
|
||||
cap.frameSize = YUV420SP_SIZE(width, height);
|
||||
cap.id = id;
|
||||
cap.fps = fps;
|
||||
cap.width = width;
|
||||
cap.height = height;
|
||||
cap.inited = true;
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
int ConfigCamera(int id, int fps, int width, int height) {
|
||||
int ret = SetCameraProperty(id, CAMERA_PROP_FPS, &fps);
|
||||
if (ret == LIBMEDIA_STATUS_FAILED) {
|
||||
ASC_LOG_ERROR("Set camera fps failed");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
CameraResolution resolution;
|
||||
resolution.width = width;
|
||||
resolution.height = height;
|
||||
ret = SetCameraProperty(id, CAMERA_PROP_RESOLUTION, &resolution);
|
||||
if (ret == LIBMEDIA_STATUS_FAILED) {
|
||||
ASC_LOG_ERROR("Set camera resolution failed");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
CameraCapMode mode = CAMERA_CAP_ACTIVE;
|
||||
ret = SetCameraProperty(id, CAMERA_PROP_CAP_MODE, &mode);
|
||||
if (ret == LIBMEDIA_STATUS_FAILED) {
|
||||
ASC_LOG_ERROR("Set camera mode:%d failed", mode);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
int OpenCameraEx(int id, int fps, int width, int height) {
|
||||
if ((id < 0) || (id >= CAMERA_NUM)) {
|
||||
ASC_LOG_ERROR("Open camera failed for invalid id %d", id);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
if (!CAMERA(id).inited) {
|
||||
CameraInit(id, fps, width, height);
|
||||
}
|
||||
|
||||
CameraStatus status = QueryCameraStatus(id);
|
||||
if (status == CAMERA_STATUS_CLOSED){
|
||||
// Open Camera
|
||||
if (LIBMEDIA_STATUS_FAILED == OpenCamera(id)) {
|
||||
ASC_LOG_ERROR("Camera%d closed, and open failed.", id);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
} else if (status != CAMERA_STATUS_OPEN) {
|
||||
ASC_LOG_ERROR("Invalid camera%d status %d", id, status);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
//Set camera property
|
||||
if (STATUS_OK != ConfigCamera(id, fps, width, height)) {
|
||||
CloseCamera(id);
|
||||
ASC_LOG_ERROR("Set camera%d property failed", id);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
ASC_LOG_INFO("Open camera %d success", id);
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
int ReadCameraFrame(int id, CameraOutput& frame) {
|
||||
int size = CAMERA(id).frameSize;
|
||||
void* data = nullptr;
|
||||
auto aclRet = acldvppMalloc(&data, size);
|
||||
if (aclRet != ACL_ERROR_NONE) {
|
||||
ASC_LOG_ERROR("acl malloc dvpp data failed, dataSize=%u, ret=%d",
|
||||
size, aclRet);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
int ret = ReadFrameFromCamera(id, (void*)data, (int *)&size);
|
||||
if ((ret == LIBMEDIA_STATUS_FAILED) ||
|
||||
(size != CAMERA(id).frameSize)) {
|
||||
acldvppFree(data);
|
||||
ASC_LOG_ERROR("Get image from camera %d failed, size %d", id, size);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
frame.size = size;
|
||||
frame.data = (uint8_t*)data;
|
||||
ASC_LOG_INFO("cpp image ptr 0x%x", data);
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
int CloseCameraEx(int cameraId) {
|
||||
if (LIBMEDIA_STATUS_FAILED == CloseCamera(cameraId)) {
|
||||
ASC_LOG_ERROR("Close camera %d failed", cameraId);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* ============================================================================
|
||||
*
|
||||
* Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1 Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2 Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3 Neither the names of the copyright holders nor the names of the
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
* ============================================================================
|
||||
*/
|
||||
#ifndef _CAMERA_H
|
||||
#define _CAMERA_H
|
||||
|
||||
#define CAMERA_NUM (2)
|
||||
|
||||
#define CAMERA(i) (g_CameraMgr.cap[i])
|
||||
|
||||
struct CameraOutput {
|
||||
int size;
|
||||
uint8_t* data;
|
||||
};
|
||||
|
||||
struct Camera {
|
||||
bool inited = false;
|
||||
int id = 255;
|
||||
int fps = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int frameSize = 0;
|
||||
|
||||
};
|
||||
|
||||
struct CameraManager {
|
||||
bool hwInited = 0;
|
||||
Camera cap[CAMERA_NUM];
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
from .presenter_datatype import *
|
||||
from .presenter_agent import *
|
||||
from .presenter_channel import *
|
||||
#from .presenter_message_pb2 import *
|
||||
|
||||
__all__ = ['presenter_datatype.py', 'presenter_agent', 'presenter_channel', 'presenter_message_pb']
|
||||
@@ -0,0 +1,75 @@
|
||||
# !/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
import time
|
||||
from threading import Thread
|
||||
|
||||
from .socket_client import AgentSocket
|
||||
from . import presenter_message as pm
|
||||
from . import presenter_datatype as datatype
|
||||
|
||||
|
||||
class PresenterAgent():
|
||||
def __init__(self, server_ip, port):
|
||||
self.socket = AgentSocket(server_ip, port)
|
||||
self._closed = False
|
||||
|
||||
def connect_server(self):
|
||||
return self.socket.connect()
|
||||
|
||||
def start_heard_beat_thread(self):
|
||||
self.heart_beat_thread = Thread(target=self._keep_alive)
|
||||
self.heart_beat_thread.start()
|
||||
|
||||
def _keep_alive(self):
|
||||
msg = pm.heartbeat_message()
|
||||
|
||||
while True:
|
||||
if self._closed:
|
||||
print("ERROR:Heard beat thread exit")
|
||||
break
|
||||
|
||||
self.socket.send_msg(msg)
|
||||
time.sleep(2)
|
||||
|
||||
def exit(self):
|
||||
self.socket.close()
|
||||
self._closed = True
|
||||
|
||||
|
||||
def StartPresenterAgent(msg_queue, server_ip, port, open_status, data_respone_counter):
|
||||
agent = PresenterAgent(server_ip, port)
|
||||
ret = agent.connect_server()
|
||||
if ret:
|
||||
print("ERROR:Connect server failed, ret =", ret)
|
||||
return
|
||||
|
||||
open_status.value = datatype.STATUS_CONNECTED
|
||||
|
||||
while True:
|
||||
data = msg_queue.get()
|
||||
|
||||
if open_status.value == datatype.STATUS_EXITING:
|
||||
open_status.value = datatype.STATUS_EXITTED
|
||||
agent.exit()
|
||||
break
|
||||
|
||||
if data:
|
||||
agent.socket.send_msg(data)
|
||||
|
||||
msg_name, msg_body = agent.socket.recv_msg()
|
||||
if (msg_name == None) or (msg_body == None):
|
||||
print("ERROR:Recv invalid message, message name ", msg_name)
|
||||
continue
|
||||
|
||||
if ((open_status.value == datatype.STATUS_CONNECTED)
|
||||
and pm.is_open_channel_response(msg_name)):
|
||||
print("Received open channel respone")
|
||||
open_status.value = datatype.STATUS_OPENED
|
||||
agent.start_heard_beat_thread()
|
||||
print("presenter agent change connect_status to ", open_status.value)
|
||||
|
||||
if ((open_status.value == datatype.STATUS_OPENED) and
|
||||
pm.is_image_frame_response(msg_name)):
|
||||
data_respone_counter.value += 1
|
||||
print("send ok ", data_respone_counter.value)
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
# !/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
import ctypes
|
||||
from ctypes import *
|
||||
import time
|
||||
import configparser
|
||||
from multiprocessing import Process, Queue, Manager
|
||||
import queue
|
||||
import numpy as np
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
|
||||
import acl
|
||||
from ..constants import *
|
||||
from ..lib.atlasutil_so import libatlas
|
||||
|
||||
from .presenter_datatype import *
|
||||
from . import presenter_agent as agent
|
||||
from . import presenter_message as pm
|
||||
|
||||
|
||||
class DataBufC(Structure):
|
||||
_fields_ = [
|
||||
('size', c_int),
|
||||
('data', POINTER(c_ubyte))
|
||||
]
|
||||
|
||||
class DataBuf():
|
||||
def __init__(self, data, data_size):
|
||||
self.data = data
|
||||
self.size = data_size
|
||||
self.nparray = None
|
||||
|
||||
def copy_to_local(self):
|
||||
src_data = DataBufC()
|
||||
src_data.data = cast(self.data, POINTER(c_ubyte))
|
||||
src_data.size = self.size
|
||||
dest_data = DataBufC()
|
||||
ret = libatlas.CopyDataToLocal(byref(dest_data), byref(src_data))
|
||||
if ret:
|
||||
print("Copy data to local failed")
|
||||
return None
|
||||
|
||||
return DataBuf(dest_data.data, dest_data.size)
|
||||
|
||||
def tobytes(self):
|
||||
self.nparray = np.frombuffer((ctypes.c_ubyte * self.size).from_address(ctypes.addressof(self.data.contents)), dtype=np.uint8)
|
||||
return self.nparray.tobytes()
|
||||
|
||||
def destroy(self):
|
||||
data_buf = DataBufC()
|
||||
data_buf.data = cast(self.data, POINTER(c_ubyte))
|
||||
data_buf.size = self.size
|
||||
libatlas.ReleaseDataBuf(byref(data_buf))
|
||||
self.data = None
|
||||
self.size = 0
|
||||
|
||||
|
||||
class PresenterChannel():
|
||||
def __init__(self, server_ip, port, name='video', type=CONTENT_TYPE_VIDEO):
|
||||
self._server_ip = server_ip
|
||||
self._port = port
|
||||
self._type = type
|
||||
self._name = name
|
||||
self.agent_msg_queue = Queue()
|
||||
self.open_status = Manager().Value('i', STATUS_DISCONNECT)
|
||||
self.data_respone_counter = Manager().Value('i', 0)
|
||||
self._send_counter = 0
|
||||
self._send_buffer = queue.Queue(64)
|
||||
self.send_cnt = 0
|
||||
self.relase_cnt = 0
|
||||
|
||||
def startup(self):
|
||||
agent_process = Process(target=agent.StartPresenterAgent,
|
||||
args=(self.agent_msg_queue, self._server_ip,self._port,
|
||||
self.open_status, self.data_respone_counter))
|
||||
agent_process.start()
|
||||
time.sleep(0.5)
|
||||
|
||||
self._send_open_channel_request(self._name, self._type)
|
||||
|
||||
return self._wait_open_status(STATUS_OPENED)
|
||||
|
||||
def _wait_open_status(self, listen_status):
|
||||
ret = STATUS_ERROR
|
||||
for i in range(0, 100):
|
||||
time.sleep(0.1)
|
||||
if self.open_status.value == listen_status:
|
||||
print("Open status is %d now"%(listen_status))
|
||||
ret = STATUS_OK
|
||||
break
|
||||
|
||||
return ret
|
||||
|
||||
def send_message(self, data):
|
||||
self.agent_msg_queue.put(data)
|
||||
self._send_counter += 1
|
||||
|
||||
def _send_open_channel_request(self, channel_name, content_type):
|
||||
request_msg = pm.open_channel_request(channel_name, content_type)
|
||||
self.send_message(request_msg)
|
||||
|
||||
def _release_send_success_data(self):
|
||||
release_num = self._send_buffer.qsize() - \
|
||||
(self._send_counter - self.data_respone_counter.value)
|
||||
if release_num > 0:
|
||||
for i in range(0, release_num):
|
||||
data = self._send_buffer.get_nowait()
|
||||
data.destroy()
|
||||
data = None
|
||||
self.relase_cnt += 1
|
||||
#print("Released send success images ", self.relase_cnt)
|
||||
|
||||
def send_detection_data(self, image_width, image_height,
|
||||
image_data, detection_result):
|
||||
if self._send_buffer.full() is True:
|
||||
print("ERROR:Send detection data failed for buffer is full")
|
||||
return False
|
||||
|
||||
image_buf = DataBuf(image_data.data(), image_data.size).copy_to_local()
|
||||
request_msg = pm.image_frame_request(image_width, image_height,
|
||||
image_buf.tobytes(), detection_result)
|
||||
self.send_message(request_msg)
|
||||
self._send_buffer.put(image_buf)
|
||||
self._release_send_success_data()
|
||||
|
||||
return True
|
||||
|
||||
def _send_heart_beat_message(self):
|
||||
msg = pm.heartbeat_message()
|
||||
self.send_message(msg)
|
||||
|
||||
def __del__(self):
|
||||
self.open_status.value = STATUS_EXITING
|
||||
print("Presenter channel close...")
|
||||
self._send_heart_beat_message()
|
||||
if STATUS_OK == self._wait_open_status(STATUS_EXITTED):
|
||||
print("Presenter channel closed")
|
||||
else:
|
||||
print("Presenter channel close failed for presenter agent no response")
|
||||
|
||||
|
||||
def get_presenter_server_addr(config_file):
|
||||
config = configparser.ConfigParser()
|
||||
config.read(config_file)
|
||||
presenter_server_ip = config['baseconf']['presenter_server_ip']
|
||||
port = int(config['baseconf']['presenter_server_port'])
|
||||
|
||||
print("presenter server ip %s, port %d"%(presenter_server_ip, port))
|
||||
return presenter_server_ip, port
|
||||
|
||||
def open_channel(config_file, channel_name='video', channel_type = CONTENT_TYPE_VIDEO):
|
||||
server_ip, port = get_presenter_server_addr(config_file)
|
||||
channel = PresenterChannel(server_ip, port, channel_name, channel_type)
|
||||
ret = channel.startup()
|
||||
if ret:
|
||||
print("ERROR:Open channel failed")
|
||||
return None
|
||||
return channel
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
STATUS_DISCONNECT = 0
|
||||
STATUS_CONNECTED = 1
|
||||
STATUS_OPEN_CH_REQUEST = 2
|
||||
STATUS_OPENED = 3
|
||||
STATUS_EXITING = 4
|
||||
STATUS_EXITTED = 5
|
||||
|
||||
CONTENT_TYPE_IMAGE = 0
|
||||
CONTENT_TYPE_VIDEO = 1
|
||||
|
||||
STATUS_OK = 0
|
||||
STATUS_ERROR = 1
|
||||
|
||||
|
||||
class Point():
|
||||
def __init__(self, x=0, y=0):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
class Box():
|
||||
def __init__(self, lt, rb):
|
||||
self.lt = Point(lt)
|
||||
self.rb = Point(rb)
|
||||
|
||||
def box_valid(self):
|
||||
return ((self.lt.x >= 0)
|
||||
and (self.lt.y >= 0)
|
||||
and (self.rb.x >= self.lt.x)
|
||||
and (self.rb.y >= self.lt.y))
|
||||
|
||||
class ObjectDetectionResult():
|
||||
def __init__(self, ltx=0, lty=0, rbx=0, rby=0, text=None):
|
||||
self.object_class = 0
|
||||
self.confidence = 0
|
||||
self.box = Box((ltx, lty), (rbx, rby))
|
||||
self.result_text = text
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package ascend.presenter.proto;
|
||||
|
||||
enum OpenChannelErrorCode {
|
||||
kOpenChannelErrorNone = 0;
|
||||
kOpenChannelErrorNoSuchChannel = 1;
|
||||
kOpenChannelErrorChannelAlreadyOpened = 2;
|
||||
kOpenChannelErrorOther = -1;
|
||||
}
|
||||
|
||||
enum ChannelContentType {
|
||||
kChannelContentTypeImage = 0;
|
||||
kChannelContentTypeVideo = 1;
|
||||
}
|
||||
|
||||
// By Protocol Buffer Style Guide, need to use underscore_separated_names
|
||||
// for field names
|
||||
message OpenChannelRequest {
|
||||
string channel_name = 1;
|
||||
ChannelContentType content_type = 2;
|
||||
}
|
||||
|
||||
message OpenChannelResponse {
|
||||
OpenChannelErrorCode error_code = 1;
|
||||
string error_message = 2;
|
||||
}
|
||||
|
||||
message HeartbeatMessage {
|
||||
|
||||
}
|
||||
|
||||
enum ImageFormat {
|
||||
kImageFormatJpeg = 0;
|
||||
}
|
||||
|
||||
message Coordinate {
|
||||
uint32 x = 1;
|
||||
uint32 y = 2;
|
||||
}
|
||||
|
||||
message Rectangle_Attr {
|
||||
Coordinate left_top = 1;
|
||||
Coordinate right_bottom = 2;
|
||||
string label_text = 3;
|
||||
}
|
||||
|
||||
message PresentImageRequest {
|
||||
ImageFormat format = 1;
|
||||
uint32 width = 2;
|
||||
uint32 height = 3;
|
||||
bytes data = 4;
|
||||
repeated Rectangle_Attr rectangle_list = 5;
|
||||
}
|
||||
|
||||
enum PresentDataErrorCode {
|
||||
kPresentDataErrorNone = 0;
|
||||
kPresentDataErrorUnsupportedType = 1;
|
||||
kPresentDataErrorUnsupportedFormat = 2;
|
||||
kPresentDataErrorOther = -1;
|
||||
}
|
||||
|
||||
message PresentImageResponse {
|
||||
PresentDataErrorCode error_code = 1;
|
||||
string error_message = 2;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# !/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
import struct
|
||||
import socket
|
||||
|
||||
from . import presenter_message_pb2 as pb2
|
||||
|
||||
def pack_message(msg_name, msg_data):
|
||||
buf = msg_data.SerializeToString()
|
||||
msg_body_len = len(buf)
|
||||
msg_name_len = len(msg_name)
|
||||
msg_total_len = msg_name_len + msg_body_len + 5
|
||||
data = b''
|
||||
msg_total_len = socket.htonl(msg_total_len)
|
||||
pack_data = struct.pack('IB', msg_total_len, msg_name_len)
|
||||
data += pack_data
|
||||
data += msg_name.encode()
|
||||
data += buf
|
||||
|
||||
return data
|
||||
|
||||
def open_channel_request(channel_name, content_type):
|
||||
request = pb2.OpenChannelRequest()
|
||||
request.channel_name = channel_name
|
||||
request.content_type = content_type
|
||||
|
||||
return pack_message(pb2._OPENCHANNELREQUEST.full_name, request)
|
||||
|
||||
def image_frame_request(image_width, image_height, image_data, detection_result):
|
||||
request = pb2.PresentImageRequest()
|
||||
request.format = 0
|
||||
request.width = image_width
|
||||
request.height = image_height
|
||||
request.data = image_data
|
||||
for i in range(0, len(detection_result)):
|
||||
myadd = request.rectangle_list.add()
|
||||
myadd.left_top.x = detection_result[i].box.lt.x
|
||||
myadd.left_top.y = detection_result[i].box.lt.y
|
||||
myadd.right_bottom.x = detection_result[i].box.rb.x
|
||||
myadd.right_bottom.y = detection_result[i].box.rb.y
|
||||
myadd.label_text = detection_result[i].result_text
|
||||
|
||||
return pack_message(pb2._PRESENTIMAGEREQUEST.full_name, request)
|
||||
|
||||
def heartbeat_message():
|
||||
return pack_message(pb2._HEARTBEATMESSAGE.full_name, pb2.HeartbeatMessage())
|
||||
|
||||
def is_open_channel_response(msg_name):
|
||||
return (msg_name == pb2._OPENCHANNELRESPONSE.full_name)
|
||||
|
||||
def is_image_frame_response(msg_name):
|
||||
return (msg_name == pb2._PRESENTIMAGERESPONSE.full_name)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,493 @@
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: presenter_message.proto
|
||||
|
||||
import sys
|
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf import descriptor_pb2
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='presenter_message.proto',
|
||||
package='ascend.presenter.proto',
|
||||
syntax='proto3',
|
||||
serialized_pb=_b('\n\x17presenter_message.proto\x12\x16\x61scend.presenter.proto\"l\n\x12OpenChannelRequest\x12\x14\n\x0c\x63hannel_name\x18\x01 \x01(\t\x12@\n\x0c\x63ontent_type\x18\x02 \x01(\x0e\x32*.ascend.presenter.proto.ChannelContentType\"n\n\x13OpenChannelResponse\x12@\n\nerror_code\x18\x01 \x01(\x0e\x32,.ascend.presenter.proto.OpenChannelErrorCode\x12\x15\n\rerror_message\x18\x02 \x01(\t\"\x12\n\x10HeartbeatMessage\"\"\n\nCoordinate\x12\t\n\x01x\x18\x01 \x01(\r\x12\t\n\x01y\x18\x02 \x01(\r\"\x94\x01\n\x0eRectangle_Attr\x12\x34\n\x08left_top\x18\x01 \x01(\x0b\x32\".ascend.presenter.proto.Coordinate\x12\x38\n\x0cright_bottom\x18\x02 \x01(\x0b\x32\".ascend.presenter.proto.Coordinate\x12\x12\n\nlabel_text\x18\x03 \x01(\t\"\xb7\x01\n\x13PresentImageRequest\x12\x33\n\x06\x66ormat\x18\x01 \x01(\x0e\x32#.ascend.presenter.proto.ImageFormat\x12\r\n\x05width\x18\x02 \x01(\r\x12\x0e\n\x06height\x18\x03 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12>\n\x0erectangle_list\x18\x05 \x03(\x0b\x32&.ascend.presenter.proto.Rectangle_Attr\"o\n\x14PresentImageResponse\x12@\n\nerror_code\x18\x01 \x01(\x0e\x32,.ascend.presenter.proto.PresentDataErrorCode\x12\x15\n\rerror_message\x18\x02 \x01(\t*\xa5\x01\n\x14OpenChannelErrorCode\x12\x19\n\x15kOpenChannelErrorNone\x10\x00\x12\"\n\x1ekOpenChannelErrorNoSuchChannel\x10\x01\x12)\n%kOpenChannelErrorChannelAlreadyOpened\x10\x02\x12#\n\x16kOpenChannelErrorOther\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01*P\n\x12\x43hannelContentType\x12\x1c\n\x18kChannelContentTypeImage\x10\x00\x12\x1c\n\x18kChannelContentTypeVideo\x10\x01*#\n\x0bImageFormat\x12\x14\n\x10kImageFormatJpeg\x10\x00*\xa4\x01\n\x14PresentDataErrorCode\x12\x19\n\x15kPresentDataErrorNone\x10\x00\x12$\n kPresentDataErrorUnsupportedType\x10\x01\x12&\n\"kPresentDataErrorUnsupportedFormat\x10\x02\x12#\n\x16kPresentDataErrorOther\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x62\x06proto3')
|
||||
)
|
||||
|
||||
_OPENCHANNELERRORCODE = _descriptor.EnumDescriptor(
|
||||
name='OpenChannelErrorCode',
|
||||
full_name='ascend.presenter.proto.OpenChannelErrorCode',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kOpenChannelErrorNone', index=0, number=0,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kOpenChannelErrorNoSuchChannel', index=1, number=1,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kOpenChannelErrorChannelAlreadyOpened', index=2, number=2,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kOpenChannelErrorOther', index=3, number=-1,
|
||||
options=None,
|
||||
type=None),
|
||||
],
|
||||
containing_type=None,
|
||||
options=None,
|
||||
serialized_start=780,
|
||||
serialized_end=945,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_OPENCHANNELERRORCODE)
|
||||
|
||||
OpenChannelErrorCode = enum_type_wrapper.EnumTypeWrapper(_OPENCHANNELERRORCODE)
|
||||
_CHANNELCONTENTTYPE = _descriptor.EnumDescriptor(
|
||||
name='ChannelContentType',
|
||||
full_name='ascend.presenter.proto.ChannelContentType',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kChannelContentTypeImage', index=0, number=0,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kChannelContentTypeVideo', index=1, number=1,
|
||||
options=None,
|
||||
type=None),
|
||||
],
|
||||
containing_type=None,
|
||||
options=None,
|
||||
serialized_start=947,
|
||||
serialized_end=1027,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CHANNELCONTENTTYPE)
|
||||
|
||||
ChannelContentType = enum_type_wrapper.EnumTypeWrapper(_CHANNELCONTENTTYPE)
|
||||
_IMAGEFORMAT = _descriptor.EnumDescriptor(
|
||||
name='ImageFormat',
|
||||
full_name='ascend.presenter.proto.ImageFormat',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kImageFormatJpeg', index=0, number=0,
|
||||
options=None,
|
||||
type=None),
|
||||
],
|
||||
containing_type=None,
|
||||
options=None,
|
||||
serialized_start=1029,
|
||||
serialized_end=1064,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_IMAGEFORMAT)
|
||||
|
||||
ImageFormat = enum_type_wrapper.EnumTypeWrapper(_IMAGEFORMAT)
|
||||
_PRESENTDATAERRORCODE = _descriptor.EnumDescriptor(
|
||||
name='PresentDataErrorCode',
|
||||
full_name='ascend.presenter.proto.PresentDataErrorCode',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kPresentDataErrorNone', index=0, number=0,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kPresentDataErrorUnsupportedType', index=1, number=1,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kPresentDataErrorUnsupportedFormat', index=2, number=2,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kPresentDataErrorOther', index=3, number=-1,
|
||||
options=None,
|
||||
type=None),
|
||||
],
|
||||
containing_type=None,
|
||||
options=None,
|
||||
serialized_start=1067,
|
||||
serialized_end=1231,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_PRESENTDATAERRORCODE)
|
||||
|
||||
PresentDataErrorCode = enum_type_wrapper.EnumTypeWrapper(_PRESENTDATAERRORCODE)
|
||||
kOpenChannelErrorNone = 0
|
||||
kOpenChannelErrorNoSuchChannel = 1
|
||||
kOpenChannelErrorChannelAlreadyOpened = 2
|
||||
kOpenChannelErrorOther = -1
|
||||
kChannelContentTypeImage = 0
|
||||
kChannelContentTypeVideo = 1
|
||||
kImageFormatJpeg = 0
|
||||
kPresentDataErrorNone = 0
|
||||
kPresentDataErrorUnsupportedType = 1
|
||||
kPresentDataErrorUnsupportedFormat = 2
|
||||
kPresentDataErrorOther = -1
|
||||
|
||||
|
||||
|
||||
_OPENCHANNELREQUEST = _descriptor.Descriptor(
|
||||
name='OpenChannelRequest',
|
||||
full_name='ascend.presenter.proto.OpenChannelRequest',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='channel_name', full_name='ascend.presenter.proto.OpenChannelRequest.channel_name', index=0,
|
||||
number=1, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='content_type', full_name='ascend.presenter.proto.OpenChannelRequest.content_type', index=1,
|
||||
number=2, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=51,
|
||||
serialized_end=159,
|
||||
)
|
||||
|
||||
|
||||
_OPENCHANNELRESPONSE = _descriptor.Descriptor(
|
||||
name='OpenChannelResponse',
|
||||
full_name='ascend.presenter.proto.OpenChannelResponse',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='error_code', full_name='ascend.presenter.proto.OpenChannelResponse.error_code', index=0,
|
||||
number=1, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='error_message', full_name='ascend.presenter.proto.OpenChannelResponse.error_message', index=1,
|
||||
number=2, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=161,
|
||||
serialized_end=271,
|
||||
)
|
||||
|
||||
|
||||
_HEARTBEATMESSAGE = _descriptor.Descriptor(
|
||||
name='HeartbeatMessage',
|
||||
full_name='ascend.presenter.proto.HeartbeatMessage',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=273,
|
||||
serialized_end=291,
|
||||
)
|
||||
|
||||
|
||||
_COORDINATE = _descriptor.Descriptor(
|
||||
name='Coordinate',
|
||||
full_name='ascend.presenter.proto.Coordinate',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='x', full_name='ascend.presenter.proto.Coordinate.x', index=0,
|
||||
number=1, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='y', full_name='ascend.presenter.proto.Coordinate.y', index=1,
|
||||
number=2, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=293,
|
||||
serialized_end=327,
|
||||
)
|
||||
|
||||
|
||||
_RECTANGLE_ATTR = _descriptor.Descriptor(
|
||||
name='Rectangle_Attr',
|
||||
full_name='ascend.presenter.proto.Rectangle_Attr',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='left_top', full_name='ascend.presenter.proto.Rectangle_Attr.left_top', index=0,
|
||||
number=1, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='right_bottom', full_name='ascend.presenter.proto.Rectangle_Attr.right_bottom', index=1,
|
||||
number=2, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='label_text', full_name='ascend.presenter.proto.Rectangle_Attr.label_text', index=2,
|
||||
number=3, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=330,
|
||||
serialized_end=478,
|
||||
)
|
||||
|
||||
|
||||
_PRESENTIMAGEREQUEST = _descriptor.Descriptor(
|
||||
name='PresentImageRequest',
|
||||
full_name='ascend.presenter.proto.PresentImageRequest',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='format', full_name='ascend.presenter.proto.PresentImageRequest.format', index=0,
|
||||
number=1, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='width', full_name='ascend.presenter.proto.PresentImageRequest.width', index=1,
|
||||
number=2, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='height', full_name='ascend.presenter.proto.PresentImageRequest.height', index=2,
|
||||
number=3, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='data', full_name='ascend.presenter.proto.PresentImageRequest.data', index=3,
|
||||
number=4, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='rectangle_list', full_name='ascend.presenter.proto.PresentImageRequest.rectangle_list', index=4,
|
||||
number=5, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=481,
|
||||
serialized_end=664,
|
||||
)
|
||||
|
||||
|
||||
_PRESENTIMAGERESPONSE = _descriptor.Descriptor(
|
||||
name='PresentImageResponse',
|
||||
full_name='ascend.presenter.proto.PresentImageResponse',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='error_code', full_name='ascend.presenter.proto.PresentImageResponse.error_code', index=0,
|
||||
number=1, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='error_message', full_name='ascend.presenter.proto.PresentImageResponse.error_message', index=1,
|
||||
number=2, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=666,
|
||||
serialized_end=777,
|
||||
)
|
||||
|
||||
_OPENCHANNELREQUEST.fields_by_name['content_type'].enum_type = _CHANNELCONTENTTYPE
|
||||
_OPENCHANNELRESPONSE.fields_by_name['error_code'].enum_type = _OPENCHANNELERRORCODE
|
||||
_RECTANGLE_ATTR.fields_by_name['left_top'].message_type = _COORDINATE
|
||||
_RECTANGLE_ATTR.fields_by_name['right_bottom'].message_type = _COORDINATE
|
||||
_PRESENTIMAGEREQUEST.fields_by_name['format'].enum_type = _IMAGEFORMAT
|
||||
_PRESENTIMAGEREQUEST.fields_by_name['rectangle_list'].message_type = _RECTANGLE_ATTR
|
||||
_PRESENTIMAGERESPONSE.fields_by_name['error_code'].enum_type = _PRESENTDATAERRORCODE
|
||||
DESCRIPTOR.message_types_by_name['OpenChannelRequest'] = _OPENCHANNELREQUEST
|
||||
DESCRIPTOR.message_types_by_name['OpenChannelResponse'] = _OPENCHANNELRESPONSE
|
||||
DESCRIPTOR.message_types_by_name['HeartbeatMessage'] = _HEARTBEATMESSAGE
|
||||
DESCRIPTOR.message_types_by_name['Coordinate'] = _COORDINATE
|
||||
DESCRIPTOR.message_types_by_name['Rectangle_Attr'] = _RECTANGLE_ATTR
|
||||
DESCRIPTOR.message_types_by_name['PresentImageRequest'] = _PRESENTIMAGEREQUEST
|
||||
DESCRIPTOR.message_types_by_name['PresentImageResponse'] = _PRESENTIMAGERESPONSE
|
||||
DESCRIPTOR.enum_types_by_name['OpenChannelErrorCode'] = _OPENCHANNELERRORCODE
|
||||
DESCRIPTOR.enum_types_by_name['ChannelContentType'] = _CHANNELCONTENTTYPE
|
||||
DESCRIPTOR.enum_types_by_name['ImageFormat'] = _IMAGEFORMAT
|
||||
DESCRIPTOR.enum_types_by_name['PresentDataErrorCode'] = _PRESENTDATAERRORCODE
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
OpenChannelRequest = _reflection.GeneratedProtocolMessageType('OpenChannelRequest', (_message.Message,), dict(
|
||||
DESCRIPTOR = _OPENCHANNELREQUEST,
|
||||
__module__ = 'presenter_message_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.OpenChannelRequest)
|
||||
))
|
||||
_sym_db.RegisterMessage(OpenChannelRequest)
|
||||
|
||||
OpenChannelResponse = _reflection.GeneratedProtocolMessageType('OpenChannelResponse', (_message.Message,), dict(
|
||||
DESCRIPTOR = _OPENCHANNELRESPONSE,
|
||||
__module__ = 'presenter_message_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.OpenChannelResponse)
|
||||
))
|
||||
_sym_db.RegisterMessage(OpenChannelResponse)
|
||||
|
||||
HeartbeatMessage = _reflection.GeneratedProtocolMessageType('HeartbeatMessage', (_message.Message,), dict(
|
||||
DESCRIPTOR = _HEARTBEATMESSAGE,
|
||||
__module__ = 'presenter_message_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.HeartbeatMessage)
|
||||
))
|
||||
_sym_db.RegisterMessage(HeartbeatMessage)
|
||||
|
||||
Coordinate = _reflection.GeneratedProtocolMessageType('Coordinate', (_message.Message,), dict(
|
||||
DESCRIPTOR = _COORDINATE,
|
||||
__module__ = 'presenter_message_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.Coordinate)
|
||||
))
|
||||
_sym_db.RegisterMessage(Coordinate)
|
||||
|
||||
Rectangle_Attr = _reflection.GeneratedProtocolMessageType('Rectangle_Attr', (_message.Message,), dict(
|
||||
DESCRIPTOR = _RECTANGLE_ATTR,
|
||||
__module__ = 'presenter_message_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.Rectangle_Attr)
|
||||
))
|
||||
_sym_db.RegisterMessage(Rectangle_Attr)
|
||||
|
||||
PresentImageRequest = _reflection.GeneratedProtocolMessageType('PresentImageRequest', (_message.Message,), dict(
|
||||
DESCRIPTOR = _PRESENTIMAGEREQUEST,
|
||||
__module__ = 'presenter_message_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.PresentImageRequest)
|
||||
))
|
||||
_sym_db.RegisterMessage(PresentImageRequest)
|
||||
|
||||
PresentImageResponse = _reflection.GeneratedProtocolMessageType('PresentImageResponse', (_message.Message,), dict(
|
||||
DESCRIPTOR = _PRESENTIMAGERESPONSE,
|
||||
__module__ = 'presenter_message_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.PresentImageResponse)
|
||||
))
|
||||
_sym_db.RegisterMessage(PresentImageResponse)
|
||||
|
||||
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,119 @@
|
||||
# !/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import threading
|
||||
import socket
|
||||
import time
|
||||
import struct
|
||||
import time
|
||||
|
||||
from .presenter_datatype import *
|
||||
|
||||
|
||||
|
||||
class AgentSocket(object):
|
||||
def __init__(self, server_ip, port):
|
||||
self._server_address = (server_ip, port)
|
||||
self._sock_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
|
||||
def connect(self):
|
||||
ret = 0
|
||||
for i in range(0,5):
|
||||
ret = self._sock_client.connect_ex(self._server_address)
|
||||
if ret == 0:
|
||||
break
|
||||
time.sleep(0.2)
|
||||
return ret
|
||||
|
||||
def _read_socket(self, read_len):
|
||||
has_read_len = 0
|
||||
read_buf = b''
|
||||
total_buf = b''
|
||||
|
||||
while has_read_len != read_len:
|
||||
try:
|
||||
read_buf = self._sock_client.recv(read_len - has_read_len)
|
||||
except socket.error:
|
||||
print("ERROR:Read socket failed")
|
||||
return False, None
|
||||
if read_buf == b'':
|
||||
return False, None
|
||||
total_buf += read_buf
|
||||
has_read_len = len(total_buf)
|
||||
|
||||
return True, total_buf
|
||||
|
||||
def _read_msg_head(self, read_len):
|
||||
ret, msg_head = self._read_socket(read_len)
|
||||
#print("msg head data is :", msg_head)
|
||||
if not ret:
|
||||
print("ERROR:socket receive msg head null")
|
||||
return None, None
|
||||
|
||||
# in Struct(), 'I' is unsigned int, 'B' is unsigned char
|
||||
msg_head_data = struct.Struct('IB')
|
||||
(msg_total_len, msg_name_len) = msg_head_data.unpack(msg_head)
|
||||
msg_total_len = socket.ntohl(msg_total_len)
|
||||
#print("msg total length is :", msg_total_len)
|
||||
#print("msg name is :", msg_name_len)
|
||||
return msg_total_len, msg_name_len
|
||||
|
||||
def _read_msg_name(self, msg_name_len):
|
||||
ret, msg_name = self._read_socket(msg_name_len)
|
||||
#print("direct msg name is :", msg_name)
|
||||
if not ret:
|
||||
print("ERROR:socket receive msg name null")
|
||||
return False, None
|
||||
try:
|
||||
msg_name = msg_name.decode("utf-8")
|
||||
#print("decode msg name is :", msg_name)
|
||||
except Exception as e:
|
||||
print("ERROR:msg name decode to utf-8 error")
|
||||
return False, None
|
||||
|
||||
return True, msg_name
|
||||
|
||||
def _read_msg_body(self, msg_body_len):
|
||||
#print("msg body length is :", msg_body_len)
|
||||
ret, msg_body = self._read_socket(msg_body_len)
|
||||
if not ret:
|
||||
print("ERROR:socket receive msg body null")
|
||||
return False, None
|
||||
return True, msg_body
|
||||
|
||||
def recv_msg(self):
|
||||
# Step1: read msg head
|
||||
msg_total_len, msg_name_len = self._read_msg_head(5)
|
||||
if msg_total_len is None:
|
||||
print("ERROR:msg total len is None.")
|
||||
return None
|
||||
|
||||
# Step2: read msg name
|
||||
ret, msg_name = self._read_msg_name(msg_name_len)
|
||||
if not ret:
|
||||
return None
|
||||
|
||||
# Step3: read msg body
|
||||
msg_body_len = msg_total_len - 5 - msg_name_len
|
||||
if msg_body_len < 0:
|
||||
print("ERROR:msg total len is 0")
|
||||
return None
|
||||
ret, msg_body = self._read_msg_body(msg_body_len)
|
||||
if not ret:
|
||||
return None
|
||||
|
||||
return msg_name, msg_body
|
||||
|
||||
|
||||
def send_msg(self, data):
|
||||
try:
|
||||
self._sock_client.sendall(data)
|
||||
except Exception as e:
|
||||
print("ERROR:Send msg failed")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def close(self):
|
||||
self._sock_client.shutdown(socket.SHUT_RDWR)
|
||||
self._sock_client.close()
|
||||
@@ -0,0 +1,71 @@
|
||||
import acl
|
||||
from atlas_utils.constants import *
|
||||
from atlas_utils.lib.atlasutil_so import libatlas
|
||||
|
||||
def check_ret(message, ret):
|
||||
if ret != ACL_ERROR_NONE:
|
||||
raise Exception("{} failed ret={}"
|
||||
.format(message, ret))
|
||||
|
||||
def copy_data_device_to_host(device_data, data_size):
|
||||
host_buffer, ret = acl.rt.malloc_host(data_size)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Malloc host memory failed, error: ", ret)
|
||||
return None
|
||||
|
||||
ret = acl.rt.memcpy(host_buffer, data_size,
|
||||
device_data, data_size,
|
||||
ACL_MEMCPY_DEVICE_TO_HOST)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Copy device data to host memory failed, error: ", ret)
|
||||
acl.rt.free_host(host_buffer)
|
||||
return None
|
||||
|
||||
return host_buffer
|
||||
|
||||
def copy_data_device_to_device(device_data, data_size):
|
||||
device_buffer, ret = acl.rt.malloc(data_size, ACL_MEM_MALLOC_NORMAL_ONLY)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Malloc device memory failed, error: ", ret)
|
||||
return None
|
||||
|
||||
ret = acl.rt.memcpy(device_buffer, data_size,
|
||||
device_data, data_size,
|
||||
ACL_MEMCPY_DEVICE_TO_DEVICE)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Copy device data to device memory failed, error: ", ret)
|
||||
acl.rt.free(device_buffer)
|
||||
return None
|
||||
|
||||
return device_buffer
|
||||
|
||||
def copy_data_host_to_device(host_data, data_size):
|
||||
device_buffer, ret = acl.rt.malloc(data_size, ACL_MEM_MALLOC_NORMAL_ONLY)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Malloc device memory failed, error: ", ret)
|
||||
return None
|
||||
|
||||
ret = acl.rt.memcpy(device_buffer, data_size,
|
||||
host_data, data_size,
|
||||
ACL_MEMCPY_HOST_TO_DEVICE)
|
||||
if ret != ACL_ERROR_NONE:
|
||||
print("Copy device data to device memory failed, error: ", ret)
|
||||
acl.rt.free(device_buffer)
|
||||
return None
|
||||
|
||||
return device_buffer
|
||||
|
||||
def align_up(value, align):
|
||||
return int(int((value + align - 1) / align) * align)
|
||||
|
||||
def align_up16(value):
|
||||
return align_up(value, 16)
|
||||
|
||||
def align_up2(value):
|
||||
return align_up(value, 2)
|
||||
|
||||
def yuv420sp_size(width, height):
|
||||
return width * height * 3 // 2
|
||||
|
||||
def unpack_bytes(dest, dest_size, src, src_size):
|
||||
libatlas.UnpackFloatByteArray(dest, dest_size, src, src_size)
|
||||
@@ -0,0 +1,20 @@
|
||||
[baseconf]
|
||||
# A socket server address to communicate with presenter agent
|
||||
presenter_server_ip=192.168.1.223
|
||||
|
||||
# The port of presenter agent and server communicate with
|
||||
presenter_server_port=7006
|
||||
|
||||
#the ip in presenter server view web url
|
||||
presenter_view_ip=192.168.1.223
|
||||
|
||||
#the ip of atlas200dk board connect with presenter server
|
||||
#presenter_agent_ip=192.168.1.2
|
||||
atlas200dk_board_ip=192.168.1.2
|
||||
|
||||
#view entry label in presenter server view web
|
||||
channel_name=video
|
||||
|
||||
#the data type that send to presenter server from agent, 0:image, 1:video
|
||||
content_type=1
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
2020-09-08 22:16:36,023-INFO-body_pose_server.py:222 presenter server is starting...
|
||||
2020-09-08 22:16:36,024-INFO-presenter_server.py:79 presenter server starting, type: body_pose
|
||||
2020-09-08 22:17:25,532-INFO-presenter_socket_server.py:255 create new connection:client-ip:192.168.1.2, client-port:53428, fd:17
|
||||
2020-09-08 22:17:26,028-ERROR-presenter_socket_server.py:354 channel name video is not exist.
|
||||
2020-09-08 22:17:26,030-INFO-channel_manager.py:216 register channel: video
|
||||
2020-09-08 22:17:26,032-INFO-channel_handler.py:215 create videothread-video...
|
||||
2020-09-08 22:17:26,032-INFO-channel_manager.py:127 create channel resource, channel_name:video, channel_fd:17, media_type:video
|
||||
2020-09-08 22:17:34,188-ERROR-presenter_socket_server.py:142 socket 17 receive msg head null
|
||||
2020-09-08 22:17:34,188-ERROR-presenter_socket_server.py:204 msg_total_len is None.
|
||||
2020-09-08 22:17:34,189-INFO-body_pose_server.py:60 clean fd:17, conns:{17: <socket.socket fd=17, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.1.223', 7006), raddr=('192.168.1.2', 53428)>}
|
||||
2020-09-08 22:17:34,191-INFO-channel_handler.py:124 videothread-video set _close_thread_switch True
|
||||
2020-09-08 22:17:34,191-INFO-channel_manager.py:139 clean channel: video's resource
|
||||
2020-09-08 22:17:34,192-INFO-channel_handler.py:226 Stop thread:videothread-video.
|
||||
2020-09-08 22:18:03,748-INFO-presenter_socket_server.py:255 create new connection:client-ip:192.168.1.2, client-port:53438, fd:17
|
||||
2020-09-08 22:18:04,245-INFO-channel_handler.py:215 create videothread-video...
|
||||
2020-09-08 22:18:04,245-INFO-channel_manager.py:127 create channel resource, channel_name:video, channel_fd:17, media_type:video
|
||||
2020-09-08 22:18:53,726-ERROR-presenter_socket_server.py:142 socket 17 receive msg head null
|
||||
2020-09-08 22:18:53,727-ERROR-presenter_socket_server.py:204 msg_total_len is None.
|
||||
2020-09-08 22:18:53,727-INFO-body_pose_server.py:60 clean fd:17, conns:{17: <socket.socket fd=17, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.1.223', 7006), raddr=('192.168.1.2', 53438)>}
|
||||
2020-09-08 22:18:53,727-INFO-channel_handler.py:124 videothread-video set _close_thread_switch True
|
||||
2020-09-08 22:18:53,727-INFO-channel_manager.py:139 clean channel: video's resource
|
||||
2020-09-08 22:18:53,727-INFO-channel_handler.py:226 Stop thread:videothread-video.
|
||||
@@ -0,0 +1,57 @@
|
||||
import os
|
||||
import cv2
|
||||
import numpy as np
|
||||
import argparse
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from model_processor import ModelProcessor
|
||||
import acl
|
||||
from acl_resource import AclResource
|
||||
|
||||
MODEL_PATH = "../model/body_pose.om"
|
||||
DATA_PATH = './tennis_player.jpg'
|
||||
|
||||
def execute(model_path, frames_input_src, output_dir):
|
||||
|
||||
|
||||
## Initialization ##
|
||||
#initialize acl runtime
|
||||
acl_resource = AclResource()
|
||||
acl_resource.init()
|
||||
|
||||
## Prepare Model ##
|
||||
# parameters for model path and model inputs
|
||||
model_parameters = {
|
||||
'model_dir': model_path,
|
||||
'width': 368, # model input width
|
||||
'height': 368, # model input height
|
||||
}
|
||||
# perpare model instance: init (loading model from file to memory)
|
||||
# model_processor: preprocessing + model inference + postprocessing
|
||||
model_processor = ModelProcessor(acl_resource, model_parameters)
|
||||
|
||||
## Get Input ##
|
||||
# Read the image input using OpenCV
|
||||
img_original = cv2.imread(args.frames_input_src)
|
||||
|
||||
## Model Prediction ##
|
||||
# model_processor.predict: processing + model inference + postprocessing
|
||||
# canvas: the picture overlayed with human body joints and limbs
|
||||
canvas = model_processor.predict(img_original)
|
||||
|
||||
# Save the detected results
|
||||
cv2.imwrite(os.path.join(args.output_dir, 'Result_Pose.jpg'), canvas)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
description = 'Load a model for human pose estimation'
|
||||
parser = argparse.ArgumentParser(description=description)
|
||||
parser.add_argument('--model', type=str, default=MODEL_PATH)
|
||||
parser.add_argument('--frames_input_src', type=str,default=DATA_PATH, help="Directory path for image")
|
||||
parser.add_argument('--output_dir', type=str, default='./outputs', help="Output Path")
|
||||
|
||||
args = parser.parse_args()
|
||||
if not os.path.exists(args.output_dir):
|
||||
os.makedirs(args.output_dir)
|
||||
|
||||
execute(args.model, args.frames_input_src, args.output_dir)
|
||||
|
After Width: | Height: | Size: 2.3 MiB |
@@ -0,0 +1,107 @@
|
||||
import random
|
||||
import os
|
||||
import cv2
|
||||
import numpy as np
|
||||
import argparse
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from model_processor import ModelProcessor
|
||||
from atlas_utils.camera import Camera
|
||||
from atlas_utils import presenteragent
|
||||
from atlas_utils.acl_image import AclImage
|
||||
import acl
|
||||
from acl_resource import AclResource
|
||||
|
||||
MODEL_PATH = "../model/body_pose.om"
|
||||
BODYPOSE_CONF="../body_pose.conf"
|
||||
CAMERA_FRAME_WIDTH = 1280
|
||||
CAMERA_FRAME_HEIGHT = 720
|
||||
|
||||
def execute(model_path):
|
||||
|
||||
## Initialization ##
|
||||
#initialize acl runtime
|
||||
acl_resource = AclResource()
|
||||
acl_resource.init()
|
||||
|
||||
## Prepare Model ##
|
||||
# parameters for model path and model inputs
|
||||
model_parameters = {
|
||||
'model_dir': model_path,
|
||||
'width': 368, # model input width
|
||||
'height': 368, # model input height
|
||||
}
|
||||
# perpare model instance: init (loading model from file to memory)
|
||||
# model_processor: preprocessing + model inference + postprocessing
|
||||
model_processor = ModelProcessor(acl_resource, model_parameters)
|
||||
|
||||
## Get Input ##
|
||||
# Initialize Camera
|
||||
cap = Camera(id = 0, fps = 10)
|
||||
|
||||
## Set Output ##
|
||||
# open the presenter channel
|
||||
chan = presenteragent.presenter_channel.open_channel(BODYPOSE_CONF)
|
||||
if chan == None:
|
||||
print("Open presenter channel failed")
|
||||
return
|
||||
|
||||
|
||||
|
||||
while True:
|
||||
## Read one frame from Camera ##
|
||||
img_original = cap.read()
|
||||
if not img_original:
|
||||
print('Error: Camera read failed')
|
||||
break
|
||||
# Camera Input (YUV) to RGB Image
|
||||
image_byte = img_original.tobytes()
|
||||
image_array = np.frombuffer(image_byte, dtype=np.uint8)
|
||||
img_original = YUVtoRGB(image_array)
|
||||
img_original = cv2.flip(img_original,1)
|
||||
|
||||
## Model Prediction ##
|
||||
# model_processor.predict: processing + model inference + postprocessing
|
||||
# canvas: the picture overlayed with human body joints and limbs
|
||||
canvas = model_processor.predict(img_original)
|
||||
|
||||
## Present Result ##
|
||||
# convert to jpeg image for presenter server display
|
||||
_,jpeg_image = cv2.imencode('.jpg',canvas)
|
||||
# construct AclImage object for presenter server
|
||||
jpeg_image = AclImage(jpeg_image, img_original.shape[0], img_original.shape[1], jpeg_image.size)
|
||||
# send to presenter server
|
||||
chan.send_detection_data(img_original.shape[0], img_original.shape[1], jpeg_image, [])
|
||||
|
||||
# release the resources
|
||||
cap.release()
|
||||
|
||||
def YUVtoRGB(byteArray):
|
||||
e = 1280*720
|
||||
Y = byteArray[0:e]
|
||||
Y = np.reshape(Y, (720,1280))
|
||||
|
||||
s = e
|
||||
V = byteArray[s::2]
|
||||
V = np.repeat(V, 2, 0)
|
||||
V = np.reshape(V, (360,1280))
|
||||
V = np.repeat(V, 2, 0)
|
||||
|
||||
U = byteArray[s+1::2]
|
||||
U = np.repeat(U, 2, 0)
|
||||
U = np.reshape(U, (360,1280))
|
||||
U = np.repeat(U, 2, 0)
|
||||
|
||||
RGBMatrix = (np.dstack([Y,U,V])).astype(np.uint8)
|
||||
RGBMatrix = cv2.cvtColor(RGBMatrix, cv2.COLOR_YUV2RGB, 3)
|
||||
return RGBMatrix
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
description = 'Load a model for human pose estimation'
|
||||
parser = argparse.ArgumentParser(description=description)
|
||||
parser.add_argument('--model', type=str, default=MODEL_PATH)
|
||||
args = parser.parse_args()
|
||||
|
||||
execute(args.model)
|
||||
@@ -0,0 +1,106 @@
|
||||
import random
|
||||
import os
|
||||
import cv2
|
||||
import numpy as np
|
||||
import argparse
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from model_processor import ModelProcessor
|
||||
from atlas_utils.camera import Camera
|
||||
from atlas_utils import presenteragent
|
||||
from atlas_utils.acl_image import AclImage
|
||||
import acl
|
||||
from acl_resource import AclResource
|
||||
|
||||
MODEL_PATH = "../model/body_pose.om"
|
||||
BODYPOSE_CONF="../body_pose.conf"
|
||||
CAMERA_FRAME_WIDTH = 1280
|
||||
CAMERA_FRAME_HEIGHT = 720
|
||||
DATA_PATH = './yoga.mp4'
|
||||
|
||||
|
||||
def execute(model_path, frames_input_src, output_dir, is_presenter_server):
|
||||
|
||||
## Initialization ##
|
||||
#initialize acl runtime
|
||||
acl_resource = AclResource()
|
||||
acl_resource.init()
|
||||
|
||||
## Prepare Model ##
|
||||
# parameters for model path and model inputs
|
||||
model_parameters = {
|
||||
'model_dir': model_path,
|
||||
'width': 368, # model input width
|
||||
'height': 368, # model input height
|
||||
}
|
||||
# perpare model instance: init (loading model from file to memory)
|
||||
# model_processor: preprocessing + model inference + postprocessing
|
||||
model_processor = ModelProcessor(acl_resource, model_parameters)
|
||||
|
||||
## Get Input ##
|
||||
# Read the video input using OpenCV
|
||||
cap = cv2.VideoCapture(frames_input_src)
|
||||
|
||||
## Set Output ##
|
||||
if is_presenter_server:
|
||||
# if using presenter server, then open the presenter channel
|
||||
chan = presenteragent.presenter_channel.open_channel(BODYPOSE_CONF)
|
||||
if chan == None:
|
||||
print("Open presenter channel failed")
|
||||
return
|
||||
else:
|
||||
# if saving result as video file (mp4), then set the output video writer using opencv
|
||||
video_output_path = '{}/demo-{}-{}.mp4'.format(output_dir, os.path.basename(frames_input_src), str(random.randint(1, 100001)))
|
||||
video_writer = cv2.VideoWriter(video_output_path, 0x7634706d, 25,
|
||||
(1280, 720))
|
||||
if video_writer == None:
|
||||
print('Error: cannot get video writer from openCV')
|
||||
|
||||
|
||||
while(cap.isOpened()):
|
||||
## Read one frame of the input video ##
|
||||
ret, img_original = cap.read()
|
||||
|
||||
if not ret:
|
||||
print('Cannot read more, Reach the end of video')
|
||||
break
|
||||
|
||||
## Model Prediction ##
|
||||
# model_processor.predict: processing + model inference + postprocessing
|
||||
# canvas: the picture overlayed with human body joints and limbs
|
||||
canvas = model_processor.predict(img_original)
|
||||
|
||||
## Present Result ##
|
||||
if is_presenter_server:
|
||||
# convert to jpeg image for presenter server display
|
||||
_,jpeg_image = cv2.imencode('.jpg',canvas)
|
||||
# construct AclImage object for presenter server
|
||||
jpeg_image = AclImage(jpeg_image, img_original.shape[0], img_original.shape[1], jpeg_image.size)
|
||||
# send to presenter server
|
||||
chan.send_detection_data(img_original.shape[0], img_original.shape[1], jpeg_image, [])
|
||||
|
||||
else:
|
||||
# save to video
|
||||
video_writer.write(canvas)
|
||||
|
||||
# release the resources
|
||||
cap.release()
|
||||
if not is_presenter_server:
|
||||
video_writer.release()
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
description = 'Load a model for human pose estimation'
|
||||
parser = argparse.ArgumentParser(description=description)
|
||||
parser.add_argument('--model', type=str, default=MODEL_PATH)
|
||||
parser.add_argument('--frames_input_src', type=str,default=DATA_PATH, help="Directory path for video.")
|
||||
parser.add_argument('--output_dir', type=str, default='./outputs', help="Output Path")
|
||||
parser.add_argument('--is_presenter_server', type=bool, default=False, help="Display on presenter server or save to a video mp4 file (T/F)")
|
||||
args = parser.parse_args()
|
||||
if not os.path.exists(args.output_dir):
|
||||
os.makedirs(args.output_dir)
|
||||
|
||||
execute(args.model, args.frames_input_src, args.output_dir, args.is_presenter_server)
|
||||
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 227 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,59 @@
|
||||
import os
|
||||
import cv2
|
||||
import numpy as np
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
sys.path.append('../')
|
||||
|
||||
from src.pose_decode import decode_pose
|
||||
from acl_model import Model
|
||||
|
||||
heatmap_width = 92
|
||||
heatmap_height = 92
|
||||
|
||||
|
||||
class ModelProcessor:
|
||||
|
||||
def __init__(self, acl_resource, params):
|
||||
self._acl_resource = acl_resource
|
||||
self.params = params
|
||||
self._model_width = params['width']
|
||||
self._model_height = params['height']
|
||||
|
||||
assert 'model_dir' in params and params['model_dir'] is not None, 'Review your param: model_dir'
|
||||
assert os.path.exists(params['model_dir']), "Model directory doesn't exist {}".format(params['model_dir'])
|
||||
|
||||
# load model from path, and get model ready for inference
|
||||
self.model = Model(acl_resource, params['model_dir'])
|
||||
|
||||
def predict(self, img_original):
|
||||
|
||||
#preprocess image to get 'model_input'
|
||||
model_input = self.preprocess(img_original)
|
||||
|
||||
# execute model inference
|
||||
result = self.model.execute([model_input])
|
||||
|
||||
# postprocessing: use the heatmaps (the second output of model) to get the joins and limbs for human body
|
||||
# Note: the model has multiple outputs, here we used a simplified method, which only uses heatmap for body joints
|
||||
# and the heatmap has shape of [1,14], each value correspond to the position of one of the 14 joints.
|
||||
# The value is the index in the 92*92 heatmap (flatten to one dimension)
|
||||
heatmaps = result[1]
|
||||
# calculate the scale of original image over heatmap, Note: image_original.shape[0] is height
|
||||
scale = np.array([img_original.shape[1] / heatmap_width, img_original.shape[0]/ heatmap_height])
|
||||
|
||||
canvas = decode_pose(heatmaps[0], scale, img_original)
|
||||
|
||||
return canvas
|
||||
|
||||
def preprocess(self,img_original):
|
||||
'''
|
||||
preprocessing: resize image to model required size, and normalize value between [0,1]
|
||||
'''
|
||||
scaled_img_data = cv2.resize(img_original, (self._model_width, self._model_height))
|
||||
preprocessed_img = np.asarray(scaled_img_data, dtype=np.float32) / 255.
|
||||
|
||||
return preprocessed_img
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.5 (fastrcnn)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/presenterserver.iml" filepath="$PROJECT_DIR$/.idea/presenterserver.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TemplatesService">
|
||||
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
|
||||
<option name="TEMPLATE_FOLDERS">
|
||||
<list>
|
||||
<option value="$MODULE_DIR$/body_pose/ui/templates" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="TestRunnerService">
|
||||
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
|
||||
</component>
|
||||
</module>
|
||||
|
After Width: | Height: | Size: 580 B |
|
After Width: | Height: | Size: 580 B |
|
After Width: | Height: | Size: 394 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 253 B |
|
After Width: | Height: | Size: 580 B |
@@ -0,0 +1,155 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="14eee75f-82cc-4cc5-8088-a98a8c71e208" name="Default" comment="" />
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="TRACKING_ENABLED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FileEditorManager">
|
||||
<leaf>
|
||||
<file leaf-file-name="config_parser.py" pinned="false" current-in-tab="true">
|
||||
<entry file="file://$PROJECT_DIR$/body_pose/src/config_parser.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="688">
|
||||
<caret line="73" column="61" selection-start-line="73" selection-start-column="30" selection-end-line="73" selection-end-column="65" />
|
||||
<folding>
|
||||
<element signature="e#1773#1782#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
</leaf>
|
||||
</component>
|
||||
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||
<component name="JsGulpfileManager">
|
||||
<detection-done>true</detection-done>
|
||||
<sorting>DEFINITION_ORDER</sorting>
|
||||
</component>
|
||||
<component name="NodePackageJsonFileManager">
|
||||
<packageJsonPaths />
|
||||
</component>
|
||||
<component name="ProjectFrameBounds" extendedState="6">
|
||||
<option name="x" value="292" />
|
||||
<option name="y" value="44" />
|
||||
<option name="width" value="1400" />
|
||||
<option name="height" value="908" />
|
||||
</component>
|
||||
<component name="ProjectView">
|
||||
<navigator proportions="" version="1">
|
||||
<foldersAlwaysOnTop value="true" />
|
||||
</navigator>
|
||||
<panes>
|
||||
<pane id="ProjectPane">
|
||||
<subPane>
|
||||
<expand>
|
||||
<path>
|
||||
<item name="presenterserver" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="presenterserver" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="presenterserver" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="presenterserver" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="body_pose" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="presenterserver" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="presenterserver" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="body_pose" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="config" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="presenterserver" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="presenterserver" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="body_pose" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="src" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
</expand>
|
||||
<select />
|
||||
</subPane>
|
||||
</pane>
|
||||
<pane id="Scope" />
|
||||
</panes>
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
||||
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
|
||||
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
|
||||
</component>
|
||||
<component name="RunDashboard">
|
||||
<option name="ruleStates">
|
||||
<list>
|
||||
<RuleState>
|
||||
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
<RuleState>
|
||||
<option name="name" value="StatusDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="SvnConfiguration">
|
||||
<configuration />
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="14eee75f-82cc-4cc5-8088-a98a8c71e208" name="Default" comment="" />
|
||||
<created>1581996809387</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1581996809387</updated>
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="ToolWindowManager">
|
||||
<frame x="64" y="-11" width="1857" height="984" extended-state="6" />
|
||||
<editor active="true" />
|
||||
<layout>
|
||||
<window_info anchor="bottom" id="TODO" order="6" />
|
||||
<window_info anchor="bottom" id="Event Log" side_tool="true" />
|
||||
<window_info anchor="bottom" id="Database Changes" show_stripe_button="false" />
|
||||
<window_info anchor="bottom" id="Run" order="2" />
|
||||
<window_info anchor="bottom" id="Version Control" show_stripe_button="false" />
|
||||
<window_info anchor="bottom" id="Python Console" />
|
||||
<window_info anchor="bottom" id="Terminal" />
|
||||
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.24959569" />
|
||||
<window_info anchor="bottom" id="Docker" show_stripe_button="false" />
|
||||
<window_info anchor="right" id="Database" />
|
||||
<window_info anchor="right" id="SciView" />
|
||||
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
|
||||
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
|
||||
<window_info id="Favorites" side_tool="true" />
|
||||
<window_info anchor="bottom" id="Find" order="1" />
|
||||
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
|
||||
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
|
||||
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
|
||||
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
|
||||
<window_info anchor="bottom" id="Message" order="0" />
|
||||
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
|
||||
</layout>
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="1" />
|
||||
</component>
|
||||
<component name="VcsContentAnnotationSettings">
|
||||
<option name="myLimit" value="2678400000" />
|
||||
</component>
|
||||
<component name="editorHistoryManager">
|
||||
<entry file="file://$PROJECT_DIR$/body_pose/src/config_parser.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="688">
|
||||
<caret line="73" column="61" selection-start-line="73" selection-start-column="30" selection-end-line="73" selection-end-column="65" />
|
||||
<folding>
|
||||
<element signature="e#1773#1782#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,10 @@
|
||||
[baseconf]
|
||||
# A socket server address to communicate with presenter agent
|
||||
# Please ensure that the port does not conflict, only support Ipv4
|
||||
presenter_server_ip=192.168.1.223
|
||||
presenter_server_port=7006
|
||||
|
||||
# A http server address, you can visit the website by "http//web_server_ip:web_server_port".
|
||||
# Only support Chrome now.
|
||||
web_server_ip=192.168.1.223
|
||||
web_server_port=7007
|
||||
@@ -0,0 +1,27 @@
|
||||
[loggers]
|
||||
keys=root,body_pose
|
||||
|
||||
[handlers]
|
||||
keys=rotatingFileHandler
|
||||
|
||||
[formatters]
|
||||
keys=simpleFmt
|
||||
|
||||
[logger_root]
|
||||
level=DEBUG
|
||||
handlers=rotatingFileHandler
|
||||
|
||||
[logger_body_pose]
|
||||
level=DEBUG
|
||||
handlers=rotatingFileHandler
|
||||
qualname=body_pose
|
||||
propagate=0
|
||||
|
||||
[handler_rotatingFileHandler]
|
||||
class=handlers.RotatingFileHandler
|
||||
level=DEBUG
|
||||
formatter=simpleFmt
|
||||
args=("body_pose.log", "a", 10*1024*1024, 2)
|
||||
|
||||
[formatter_simpleFmt]
|
||||
format=%(asctime)s-%(levelname)s-%(filename)s:%(lineno)s %(message)s
|
||||
@@ -0,0 +1,225 @@
|
||||
# =======================================================================
|
||||
#
|
||||
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1 Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2 Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3 Neither the names of the copyright holders nor the names of the
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# =======================================================================
|
||||
#
|
||||
|
||||
"""presenter socket server module"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
from logging.config import fileConfig
|
||||
from google.protobuf.message import DecodeError
|
||||
import common.presenter_message_pb2 as pb2
|
||||
from common.channel_manager import ChannelManager
|
||||
from common.presenter_socket_server import PresenterSocketServer
|
||||
from body_pose.src.config_parser import ConfigParser
|
||||
|
||||
class BodyPoseServer(PresenterSocketServer):
|
||||
'''A server forbody pose'''
|
||||
def __init__(self, server_address):
|
||||
'''init func'''
|
||||
self.channel_manager = ChannelManager(["image", "video"])
|
||||
super(BodyPoseServer, self).__init__(server_address)
|
||||
|
||||
def _clean_connect(self, sock_fileno, epoll, conns, msgs):
|
||||
"""
|
||||
close socket, and clean local variables
|
||||
Args:
|
||||
sock_fileno: a socket fileno, return value of socket.fileno()
|
||||
epoll: a set of select.epoll.
|
||||
conns: all socket connections registered in epoll
|
||||
msgs: msg read from a socket
|
||||
"""
|
||||
logging.info("clean fd:%s, conns:%s", sock_fileno, conns)
|
||||
self.channel_manager.clean_channel_resource_by_fd(sock_fileno)
|
||||
epoll.unregister(sock_fileno)
|
||||
conns[sock_fileno].close()
|
||||
del conns[sock_fileno]
|
||||
del msgs[sock_fileno]
|
||||
|
||||
|
||||
def _process_msg(self, conn, msg_name, msg_data):
|
||||
"""
|
||||
Total entrance to process protobuf msg
|
||||
Args:
|
||||
conn: a socket connection
|
||||
msg_name: name of a msg.
|
||||
msg_data: msg body, serialized by protobuf
|
||||
|
||||
Returns:
|
||||
False:somme error occured
|
||||
True:succeed
|
||||
|
||||
"""
|
||||
# process open channel request
|
||||
if msg_name == pb2._OPENCHANNELREQUEST.full_name:
|
||||
ret = self._process_open_channel(conn, msg_data)
|
||||
# process image request, receive an image data from presenter agent
|
||||
elif msg_name == pb2._PRESENTIMAGEREQUEST.full_name:
|
||||
ret = self._process_image_request(conn, msg_data)
|
||||
# process heartbeat request, it used to keepalive a channel path
|
||||
elif msg_name == pb2._HEARTBEATMESSAGE.full_name:
|
||||
ret = self._process_heartbeat(conn)
|
||||
else:
|
||||
logging.error("Not recognized msg type %s", msg_name)
|
||||
ret = False
|
||||
|
||||
return ret
|
||||
|
||||
def _response_image_request(self, conn, response, err_code):
|
||||
"""
|
||||
Assemble protobuf to response image_request
|
||||
Message structure like this:
|
||||
--------------------------------------------------------------------
|
||||
|total message len | int | 4 bytes |
|
||||
|-------------------------------------------------------------------
|
||||
|message name len | byte | 1 byte |
|
||||
|-------------------------------------------------------------------
|
||||
|message name | string | xx bytes |
|
||||
|-------------------------------------------------------------------
|
||||
|message body | protobuf | xx bytes |
|
||||
--------------------------------------------------------------------
|
||||
|
||||
protobuf structure like this:
|
||||
--------------------------------------------------------------------
|
||||
|error_code | enum | PresentDataErrorCode |
|
||||
|-------------------------------------------------------------------
|
||||
|error_message | string | xx bytes |
|
||||
|-------------------------------------------------------------------
|
||||
|
||||
enum PresentDataErrorCode {
|
||||
kPresentDataErrorNone = 0;
|
||||
kPresentDataErrorUnsupportedType = 1;
|
||||
kPresentDataErrorUnsupportedFormat = 2;
|
||||
kPresentDataErrorOther = -1;
|
||||
}
|
||||
"""
|
||||
response.error_code = err_code
|
||||
ret_code = True
|
||||
if err_code == pb2.kPresentDataErrorUnsupportedFormat:
|
||||
response.error_message = "Present data not support format."
|
||||
logging.error("Present data not support format.")
|
||||
ret_code = False
|
||||
elif err_code == pb2.kPresentDataErrorNone:
|
||||
response.error_message = "Present data ok"
|
||||
ret_code = True
|
||||
else:
|
||||
response.error_message = "Present data not known error."
|
||||
logging.error("Present data not known error.")
|
||||
ret_code = False
|
||||
|
||||
self.send_message(conn, response, pb2._PRESENTIMAGERESPONSE.full_name)
|
||||
return ret_code
|
||||
|
||||
def _process_image_request(self, conn, msg_data):
|
||||
"""
|
||||
Deserialization protobuf and process image_request
|
||||
Args:
|
||||
conn: a socket connection
|
||||
msg_data: a protobuf struct, include image request.
|
||||
|
||||
Returns:
|
||||
|
||||
protobuf structure like this:
|
||||
------------------------------------
|
||||
|format | ImageFormat |
|
||||
|------------------------------------
|
||||
|width | uint32 |
|
||||
|------------------------------------
|
||||
|height | uint32 |
|
||||
|------------------------------------
|
||||
|data | bytes |
|
||||
------------------------------------
|
||||
enum ImageFormat {
|
||||
kImageFormatJpeg = 0;
|
||||
}
|
||||
"""
|
||||
request = pb2.PresentImageRequest()
|
||||
response = pb2.PresentImageResponse()
|
||||
|
||||
# Parse msg_data from protobuf
|
||||
try:
|
||||
request.ParseFromString(msg_data)
|
||||
except DecodeError:
|
||||
logging.error("ParseFromString exception: Error parsing message")
|
||||
err_code = pb2.kPresentDataErrorOther
|
||||
return self._response_image_request(conn, response, err_code)
|
||||
|
||||
sock_fileno = conn.fileno()
|
||||
handler = self.channel_manager.get_channel_handler_by_fd(sock_fileno)
|
||||
if handler is None:
|
||||
logging.error("get channel handler failed")
|
||||
err_code = pb2.kPresentDataErrorOther
|
||||
return self._response_image_request(conn, response, err_code)
|
||||
|
||||
# Currently, image format only support jpeg
|
||||
if request.format != pb2.kImageFormatJpeg:
|
||||
logging.error("image format %s not support", request.format)
|
||||
err_code = pb2.kPresentDataErrorUnsupportedFormat
|
||||
return self._response_image_request(conn, response, err_code)
|
||||
|
||||
rectangle_list = []
|
||||
if request.rectangle_list:
|
||||
for one_rectangle in request.rectangle_list:
|
||||
rectangle = []
|
||||
rectangle.append(one_rectangle.left_top.x)
|
||||
rectangle.append(one_rectangle.left_top.y)
|
||||
rectangle.append(one_rectangle.right_bottom.x)
|
||||
rectangle.append(one_rectangle.right_bottom.y)
|
||||
rectangle.append(one_rectangle.label_text)
|
||||
# add the detection result to list
|
||||
rectangle_list.append(rectangle)
|
||||
|
||||
handler.save_image(request.data, request.width, request.height, rectangle_list)
|
||||
return self._response_image_request(conn, response,
|
||||
pb2.kPresentDataErrorNone)
|
||||
|
||||
def stop_thread(self):
|
||||
channel_manager = ChannelManager([])
|
||||
channel_manager.close_all_thread()
|
||||
self.set_exit_switch()
|
||||
|
||||
def run():
|
||||
'''Entrance function of Body Pose Server '''
|
||||
# read config file
|
||||
config = ConfigParser()
|
||||
|
||||
# config log
|
||||
log_file_path = os.path.join(ConfigParser.root_path, "config/logging.conf")
|
||||
fileConfig(log_file_path)
|
||||
logging.getLogger('body_pose')
|
||||
|
||||
if not config.config_verify():
|
||||
return None
|
||||
|
||||
logging.info("presenter server is starting...")
|
||||
server_address = (config.presenter_server_ip,
|
||||
int(config.presenter_server_port))
|
||||
return BodyPoseServer(server_address)
|
||||
@@ -0,0 +1,83 @@
|
||||
# =======================================================================
|
||||
#
|
||||
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1 Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2 Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3 Neither the names of the copyright holders nor the names of the
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# =======================================================================
|
||||
#
|
||||
|
||||
"""pose detection config parser module"""
|
||||
|
||||
import os
|
||||
import configparser
|
||||
import common.parameter_validation as validate
|
||||
|
||||
class ConfigParser():
|
||||
""" parse configuration from the config.conf"""
|
||||
__instance = None
|
||||
|
||||
def __init__(self):
|
||||
"""init"""
|
||||
|
||||
def __new__(cls):
|
||||
"""ensure class object is a single instance"""
|
||||
if cls.__instance is None:
|
||||
cls.__instance = object.__new__(cls)
|
||||
cls.config_parser()
|
||||
return cls.__instance
|
||||
|
||||
def config_verify(self):
|
||||
'''Verify configuration Parameters '''
|
||||
if not validate.validate_ip(ConfigParser.web_server_ip) or \
|
||||
not validate.validate_ip(ConfigParser.presenter_server_ip) or \
|
||||
not validate.validate_port(ConfigParser.web_server_port) or \
|
||||
not validate.validate_port(ConfigParser.presenter_server_port):
|
||||
return False
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def config_parser(cls):
|
||||
"""parser config from config.conf"""
|
||||
config_parser = configparser.ConfigParser()
|
||||
cls.root_path = ConfigParser.get_rootpath()
|
||||
config_file = os.path.join(cls.root_path, "config/config.conf")
|
||||
config_parser.read(config_file)
|
||||
cls.web_server_ip = config_parser.get('baseconf', 'web_server_ip')
|
||||
cls.presenter_server_ip = \
|
||||
config_parser.get('baseconf', 'presenter_server_ip')
|
||||
cls.web_server_port = config_parser.get('baseconf', 'web_server_port')
|
||||
cls.presenter_server_port = \
|
||||
config_parser.get('baseconf', 'presenter_server_port')
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_rootpath():
|
||||
"""get presenter server's root directory."""
|
||||
path = __file__
|
||||
idx = path.rfind("src")
|
||||
|
||||
return path[0:idx]
|
||||
@@ -0,0 +1,474 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# =======================================================================
|
||||
#
|
||||
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1 Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2 Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3 Neither the names of the copyright holders nor the names of the
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# =======================================================================
|
||||
#
|
||||
"""
|
||||
web application for presenter server.
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import random
|
||||
import base64
|
||||
import threading
|
||||
import time
|
||||
import logging
|
||||
import tornado.ioloop
|
||||
import tornado.web
|
||||
import tornado.gen
|
||||
import tornado.websocket
|
||||
import body_pose.src.config_parser as config_parser
|
||||
from common.channel_manager import ChannelManager
|
||||
|
||||
class WebApp:
|
||||
"""
|
||||
web application
|
||||
"""
|
||||
__instance = None
|
||||
def __init__(self):
|
||||
"""
|
||||
init method
|
||||
"""
|
||||
self.channel_mgr = ChannelManager(["image", "video"])
|
||||
|
||||
self.request_list = set()
|
||||
|
||||
self.lock = threading.Lock()
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
|
||||
# if instance is None than create one
|
||||
if cls.__instance is None:
|
||||
cls.__instance = object.__new__(cls, *args, **kwargs)
|
||||
return cls.__instance
|
||||
|
||||
def add_channel(self, channel_name):
|
||||
"""
|
||||
add channel
|
||||
|
||||
@param channel_name name of channel
|
||||
@return: return add status and message (for error status)
|
||||
|
||||
"""
|
||||
ret = {"ret":"error", "msg":""}
|
||||
|
||||
# check channel_name validate,
|
||||
# channel_name can not be None or length = 0
|
||||
if channel_name is None:
|
||||
logging.info("Channel name is None , add channel failed")
|
||||
ret["msg"] = "Channel name can not be empty"
|
||||
return ret
|
||||
|
||||
# strip channel name
|
||||
channel_name = channel_name.strip()
|
||||
|
||||
# check channel_name emtpy or not
|
||||
if channel_name == "":
|
||||
logging.info("Channel name is emtpy , add channel failed")
|
||||
ret["msg"] = "Channel name can not be empty"
|
||||
return ret
|
||||
|
||||
|
||||
# length of channel name can not over 25
|
||||
if len(channel_name) > 25:
|
||||
logging.info("Length of channel name %s > 25 , add channel failed", channel_name)
|
||||
ret["msg"] = "Length of channel name should less than 25"
|
||||
return ret
|
||||
|
||||
# define pattern support a-z A-Z and /
|
||||
pattern = re.compile(r"[a-z]|[A-Z]|[0-9]|/")
|
||||
tmp = pattern.findall(channel_name)
|
||||
|
||||
# check reuslt changed or not
|
||||
if len(tmp) != len(channel_name):
|
||||
logging.info("%s contain invalidate character, add channel failed", channel_name)
|
||||
ret["msg"] = "Channel name only support 0-9, a-z, A-Z /"
|
||||
return ret
|
||||
|
||||
# register channel
|
||||
flag = self.channel_mgr.register_one_channel(channel_name)
|
||||
|
||||
# check register result
|
||||
if self.channel_mgr.err_code_too_many_channel == flag:
|
||||
logging.info("Only supports up to 10 channels, add channel failed")
|
||||
ret["msg"] = "Only supports up to 10 channels"
|
||||
|
||||
elif self.channel_mgr.err_code_repeat_channel == flag:
|
||||
logging.info("%s already exist, add channel failed", channel_name)
|
||||
ret["msg"] = "Channel %s already exist" % channel_name
|
||||
|
||||
else:
|
||||
logging.info("add channel %s succeed", channel_name)
|
||||
ret["ret"] = "success"
|
||||
|
||||
return ret
|
||||
|
||||
def del_channel(self, names):
|
||||
"""
|
||||
delete channel
|
||||
|
||||
@param names: channel name to be deleted, separated by ','
|
||||
@return: return add status and message (for error status)
|
||||
"""
|
||||
|
||||
# init ret for return
|
||||
ret = {"ret":"error", "msg":""}
|
||||
|
||||
# check length of names
|
||||
if names.strip() == "":
|
||||
logging.info("Channel name is empty, delete channel failed")
|
||||
ret["msg"] = "Channel name should not be empty"
|
||||
return ret
|
||||
|
||||
# split name for multi name
|
||||
listname = names.split(",")
|
||||
|
||||
# unregister name
|
||||
for item in listname:
|
||||
item = item.strip()
|
||||
|
||||
# if name is emtpy continu
|
||||
if item == "":
|
||||
continue
|
||||
|
||||
self.channel_mgr.unregister_one_channel(item)
|
||||
logging.info("delete channel %s succeed", item)
|
||||
|
||||
ret["ret"] = "success"
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def list_channels(self):
|
||||
"""
|
||||
list all channels information
|
||||
"""
|
||||
|
||||
# list register channels
|
||||
ret = self.channel_mgr.list_channels()
|
||||
|
||||
# id for every channel item , start with 1
|
||||
idx = 1
|
||||
|
||||
# set id for channel
|
||||
for item in ret:
|
||||
item['id'] = idx
|
||||
idx = idx + 1
|
||||
|
||||
return ret
|
||||
|
||||
def is_channel_exists(self, name):
|
||||
"""
|
||||
view channel content via browser.
|
||||
|
||||
@param name : channel name
|
||||
@return return True if exists. otherwise return False.
|
||||
"""
|
||||
return self.channel_mgr.is_channel_exist(name)
|
||||
|
||||
|
||||
def add_requst(self, request):
|
||||
"""
|
||||
add request
|
||||
|
||||
@param requst: request item to be stored
|
||||
|
||||
@note: request can not be same with other request.
|
||||
request is identified by (channel name ,random number)
|
||||
so this method do not return value.
|
||||
"""
|
||||
with self.lock:
|
||||
self.request_list.add(request)
|
||||
|
||||
def has_request(self, request):
|
||||
"""
|
||||
whether request exist or not
|
||||
|
||||
@param request: request to be checked.
|
||||
@return: return True if exists, otherwise return False.
|
||||
"""
|
||||
with self.lock:
|
||||
|
||||
for item in self.request_list:
|
||||
|
||||
# check request equal
|
||||
if item[0] == request[0] and item[1] == request[1]:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_media_data(self, channel_name):
|
||||
"""
|
||||
get media data by channel name
|
||||
|
||||
@param channel_name: channel to be quest data.
|
||||
@return return dictionary which have for item
|
||||
type: identify channel type, for image or video.
|
||||
image: data to be returned.
|
||||
fps: just for video type
|
||||
status: can be error, ok, or loading.
|
||||
"""
|
||||
# channel exists or not
|
||||
if self.is_channel_exists(channel_name) is False:
|
||||
return {'type': 'unkown', 'image':'', 'fps':0, 'status':'error'}
|
||||
|
||||
image_data = self.channel_mgr.get_channel_image(channel_name)
|
||||
# only for image type.
|
||||
if image_data is not None:
|
||||
image_data = base64.b64encode(image_data).decode('utf-8')
|
||||
return {'type': 'image', 'image':image_data, 'fps':0, 'status':'ok'}
|
||||
|
||||
|
||||
fps = 0 # fps for video
|
||||
image = None # image for video & image
|
||||
rectangle_list = None
|
||||
handler = self.channel_mgr.get_channel_handler_by_name(channel_name)
|
||||
|
||||
if handler is not None:
|
||||
media_type = handler.get_media_type()
|
||||
|
||||
# if type is image then get image data
|
||||
if media_type == "image":
|
||||
image = handler.get_image_data()
|
||||
|
||||
# for video
|
||||
else:
|
||||
frame_info = handler.get_frame()
|
||||
image = frame_info[0]
|
||||
fps = frame_info[1]
|
||||
rectangle_list = frame_info[4]
|
||||
|
||||
status = "loading"
|
||||
|
||||
# decode binary to utf-8 when image is not None
|
||||
if image is not None:
|
||||
status = "ok"
|
||||
image = base64.b64encode(image).decode('utf-8')
|
||||
|
||||
return {'type': media_type, 'image':image, 'fps':fps, 'status':status, 'rectangle_list':rectangle_list}
|
||||
else:
|
||||
return {'type': 'unkown', 'image':None, 'fps':0, 'status':'loading'}
|
||||
|
||||
# pylint: disable=abstract-method
|
||||
class BaseHandler(tornado.web.RequestHandler):
|
||||
"""
|
||||
base handler.
|
||||
"""
|
||||
|
||||
# pylint: disable=abstract-method
|
||||
class HomeHandler(BaseHandler):
|
||||
"""
|
||||
handler index request
|
||||
"""
|
||||
|
||||
@tornado.web.asynchronous
|
||||
def get(self, *args, **kwargs):
|
||||
"""
|
||||
handle home or index request only for get
|
||||
"""
|
||||
self.render("home.html", listret=G_WEBAPP.list_channels())
|
||||
|
||||
# pylint: disable=abstract-method
|
||||
class AddHandler(BaseHandler):
|
||||
"""
|
||||
handler add request
|
||||
"""
|
||||
@tornado.web.asynchronous
|
||||
def post(self, *args, **kwargs):
|
||||
"""
|
||||
handle reqeust for add channel
|
||||
"""
|
||||
channel_name = self.get_argument('name', '')
|
||||
self.finish(G_WEBAPP.add_channel(channel_name))
|
||||
|
||||
# pylint: disable=abstract-method
|
||||
class DelHandler(BaseHandler):
|
||||
"""
|
||||
handler delete request
|
||||
"""
|
||||
@tornado.web.asynchronous
|
||||
def post(self, *args, **kwargs):
|
||||
"""
|
||||
handel requst for delete channel
|
||||
"""
|
||||
channel_name = self.get_argument('name', '')
|
||||
self.finish(G_WEBAPP.del_channel(channel_name))
|
||||
|
||||
|
||||
# pylint: disable=abstract-method
|
||||
class ViewHandler(BaseHandler):
|
||||
"""
|
||||
handler view request
|
||||
"""
|
||||
@tornado.web.asynchronous
|
||||
def get(self, *args, **kwargs):
|
||||
"""
|
||||
handler request for view channel
|
||||
"""
|
||||
channel_name = self.get_argument('name', '')
|
||||
if G_WEBAPP.is_channel_exists(channel_name):
|
||||
req_id = str(random.random())
|
||||
G_WEBAPP.add_requst((req_id, channel_name))
|
||||
self.render('view.html', channel_name=channel_name, req=req_id)
|
||||
else:
|
||||
raise tornado.web.HTTPError(404)
|
||||
|
||||
|
||||
class WebSocket(tornado.websocket.WebSocketHandler):
|
||||
"""
|
||||
web socket for web page socket quest
|
||||
"""
|
||||
def open(self, *args, **kwargs):
|
||||
"""
|
||||
called when client request by ws or wss
|
||||
"""
|
||||
|
||||
self.req_id = self.get_argument("req", '', True)
|
||||
self.channel_name = self.get_argument("name", '', True)
|
||||
|
||||
# check request valid or not.
|
||||
if not G_WEBAPP.has_request((self.req_id, self.channel_name)):
|
||||
self.close()
|
||||
|
||||
|
||||
@staticmethod
|
||||
def send_message(obj, message, binary=False):
|
||||
"""
|
||||
send message to client.
|
||||
"""
|
||||
|
||||
# check socket exist or not
|
||||
if not obj.ws_connection or not obj.ws_connection.stream.socket:
|
||||
return False
|
||||
|
||||
ret = False
|
||||
try:
|
||||
obj.write_message(message, binary)
|
||||
ret = True
|
||||
except tornado.websocket.WebSocketClosedError:
|
||||
ret = False
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def on_close(self):
|
||||
"""
|
||||
called when closed web socket
|
||||
"""
|
||||
|
||||
@tornado.web.asynchronous
|
||||
@tornado.gen.coroutine
|
||||
def on_message(self, message):
|
||||
"""
|
||||
On recv message from client.
|
||||
"""
|
||||
if message == "next":
|
||||
self.run_task()
|
||||
|
||||
|
||||
def run_task(self):
|
||||
"""
|
||||
send image to client
|
||||
"""
|
||||
|
||||
# check channel valid
|
||||
if not G_WEBAPP.is_channel_exists(self.channel_name) or \
|
||||
not G_WEBAPP.has_request((self.req_id, self.channel_name)):
|
||||
self.close()
|
||||
return
|
||||
|
||||
result = G_WEBAPP.get_media_data(self.channel_name)
|
||||
|
||||
# sleep 100ms if status not ok for frequently query
|
||||
if result['status'] != 'ok':
|
||||
time.sleep(0.1)
|
||||
|
||||
|
||||
|
||||
# if channel not exist close websocket.
|
||||
if result['status'] == "error":
|
||||
self.close()
|
||||
# send message to client
|
||||
else:
|
||||
# close websoket when send failed or for image channel.
|
||||
ret = WebSocket.send_message(self, result)
|
||||
if not ret or result['type'] == "image":
|
||||
self.close()
|
||||
|
||||
|
||||
|
||||
def get_webapp():
|
||||
"""
|
||||
start web applicatioin
|
||||
"""
|
||||
# get template file and static file path.
|
||||
templatepath = os.path.join(config_parser.ConfigParser.get_rootpath(), "ui/templates")
|
||||
staticfilepath = os.path.join(config_parser.ConfigParser.get_rootpath(), "ui/static")
|
||||
|
||||
# create application object.
|
||||
app = tornado.web.Application(handlers=[(r"/", HomeHandler),
|
||||
(r"/index", HomeHandler),
|
||||
(r"/add", AddHandler),
|
||||
(r"/del", DelHandler),
|
||||
(r"/view", ViewHandler),
|
||||
(r"/static/(.*)",
|
||||
tornado.web.StaticFileHandler,
|
||||
{"path": staticfilepath}),
|
||||
(r"/websocket", WebSocket)],
|
||||
template_path=templatepath)
|
||||
|
||||
# create server
|
||||
http_server = tornado.httpserver.HTTPServer(app)
|
||||
|
||||
return http_server
|
||||
|
||||
|
||||
def start_webapp():
|
||||
"""
|
||||
start webapp
|
||||
"""
|
||||
http_server = get_webapp()
|
||||
config = config_parser.ConfigParser()
|
||||
http_server.listen(config.web_server_port, address=config.web_server_ip)
|
||||
|
||||
print("Please visit http://" + config.web_server_ip + ":" +
|
||||
str(config.web_server_port) + " for body pose")
|
||||
tornado.ioloop.IOLoop.instance().start()
|
||||
|
||||
|
||||
def stop_webapp():
|
||||
"""
|
||||
stop web app
|
||||
"""
|
||||
tornado.ioloop.IOLoop.instance().stop()
|
||||
|
||||
global G_WEBAPP
|
||||
G_WEBAPP = WebApp()
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
body, h1, h2, h3, h4, h5, h6, hr, p, blockquote,
|
||||
dl, dt, dd, ul, ol, li,
|
||||
pre,
|
||||
form, fieldset, legend, button, input, textarea,
|
||||
th, td {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body,
|
||||
button, input, select, textarea /* for ie */ {
|
||||
font: 14px/1.5 tahoma, \5b8b\4f53, sans-serif;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 { font-size: 100%; font-weight: normal;}
|
||||
address, cite, dfn, em, var { font-style: normal; }
|
||||
code, kbd, pre, samp { font-family: courier new, courier, monospace; }
|
||||
small { font-size: 12px; }
|
||||
|
||||
ul, ol { list-style: none; }
|
||||
|
||||
a { text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
sup { vertical-align: text-top; }
|
||||
sub { vertical-align: text-bottom; }
|
||||
|
||||
legend { color: #000; } /* for ie6 */
|
||||
fieldset, img { border: 0; }
|
||||
button, input, select, textarea { font-size: 100%; }
|
||||
|
||||
table { border-collapse: collapse; border-spacing: 0; }
|
||||
|
||||
article, aside, details, figcaption, figure, footer,header, hgroup, menu, nav, section,
|
||||
summary, time, mark, audio, video {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
mark { background: #ff0; }
|
||||
@@ -0,0 +1,77 @@
|
||||
#dlg-mask {
|
||||
display: none;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 10000;
|
||||
background-color: rgba(0,0,0,0.75)/*rgba(140,140,140,0.4)*/;
|
||||
}
|
||||
|
||||
#dlg-mask * {
|
||||
color: #000;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box; /* Firefox */
|
||||
-webkit-box-sizing: border-box; /* Safari */
|
||||
}
|
||||
|
||||
#dlg-box {
|
||||
position: absolute;
|
||||
width: 350px;
|
||||
z-index: 200001;
|
||||
padding: 25px;
|
||||
background-color: rgba(255, 255, 255, 0.88);
|
||||
-moz-border-radius: 6px;
|
||||
-webkit-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
#dlg-box h1 {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
}
|
||||
#dlg-box p, #dlg-box input {
|
||||
width: 100%;
|
||||
margin: 20px 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
#dlg-box p {
|
||||
width: 100%;
|
||||
margin: 20px 0;
|
||||
font-size: 15px;
|
||||
line-height: 1.2;
|
||||
word-wrap: break-word;
|
||||
word-break: normal;
|
||||
white-space: normal;
|
||||
}
|
||||
#dlg-box input {
|
||||
height: 29px;
|
||||
cursor: text;
|
||||
}
|
||||
#dlg-box div {
|
||||
height: 30px;
|
||||
}
|
||||
#dlg-box div span {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
width: 64px;
|
||||
height: 30px;
|
||||
font-size: 15px;
|
||||
color: #187be1;
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#dlg-box div span:hover {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.dot {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
body{
|
||||
background-color: #edf7f9;
|
||||
font-family: Arial, 黑体, Tahoma;
|
||||
}
|
||||
|
||||
.nav{
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
background-color: #155070;
|
||||
padding-left: 50px;
|
||||
padding-right: 50px;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-pack: justify;
|
||||
-webkit-justify-content: space-between;
|
||||
justify-content: space-between;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.nav_left{
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-pack: justify;
|
||||
-webkit-justify-content: space-between;
|
||||
justify-content: space-between;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
.nav_left img{
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.nav_left p span{
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.box_top{
|
||||
width: 1024px;
|
||||
margin: 0 auto;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
font-weight: bold;
|
||||
|
||||
}
|
||||
.box_content{
|
||||
width: 1024px;
|
||||
margin: 0 auto;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.content_top{
|
||||
height: 50px;
|
||||
padding-top: 10px;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
}
|
||||
.content_top li{
|
||||
width: 82px;
|
||||
height: 32px;
|
||||
float: left;
|
||||
border: 1px solid #51a8da;
|
||||
margin-right: 5px;
|
||||
color: #51a8da;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
padding-left: 7px;
|
||||
padding-right: 7px;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
}
|
||||
.content_top li:nth-child(3){
|
||||
background-color: #51a8da;
|
||||
color: #ffffff;
|
||||
}
|
||||
.content_mid{
|
||||
border-top:2px solid #51a8da;
|
||||
padding-top: 15px;
|
||||
height: 0;
|
||||
display: none;
|
||||
}
|
||||
.mid_list{
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid #ccc;
|
||||
border-right: 0;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
}
|
||||
.mid_list li{
|
||||
float: left;
|
||||
height: 100%;
|
||||
width: 25%;
|
||||
line-height: 40px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
.mid_list li:nth-child(odd){
|
||||
background-color: #edf7f9;
|
||||
}
|
||||
.mid_list li:nth-child(odd) span:nth-child(2){
|
||||
float: right;
|
||||
}
|
||||
.mid_add{
|
||||
width: 82px;
|
||||
height: 32px;
|
||||
background-color: #51a8da;
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
cursor: pointer;
|
||||
}
|
||||
.content_bot{
|
||||
border-top:2px solid #51a8da;
|
||||
}
|
||||
#mytable th,td{
|
||||
height: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
body{
|
||||
background-color: #edf7f9;
|
||||
font-family: Arial, 宋体, Tahoma;
|
||||
}
|
||||
|
||||
.nav{
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
background-color: #155070;
|
||||
padding-left: 50px;
|
||||
padding-right: 50px;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-pack: justify;
|
||||
-webkit-justify-content: space-between;
|
||||
justify-content: space-between;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.nav_left{
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-pack: justify;
|
||||
-webkit-justify-content: space-between;
|
||||
justify-content: space-between;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
.nav_left img{
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.nav_left p span{
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
}
|
||||
.refresh{
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin: -6px 0 0 -6px ;
|
||||
|
||||
}
|
||||
|
||||
.video_top{
|
||||
width: 1024px;
|
||||
margin: 0 auto;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
font-weight: bold;
|
||||
|
||||
}
|
||||
.video_content{
|
||||
width: 1024px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.video_fps{
|
||||
text-align: right;
|
||||
padding-right: 100px;
|
||||
}
|
||||
.video_inner{
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 367 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 200 B |
@@ -0,0 +1,97 @@
|
||||
var dialog = (function Dialog() {
|
||||
var $mask = $("<div id='dlg-mask'></div>");
|
||||
|
||||
//title--
|
||||
//content--object{type[1 for input, 0 for text], text[display in content]}
|
||||
//btnFlag--1 for OK+Cancel, 0 for OK
|
||||
function initHtml(title, content, btnFlag, ok, cancel) {
|
||||
var div = "";
|
||||
div += "<div id='dlg-box' class='dot'>";
|
||||
div += "<h1 class='dot' style=\"margin-bottom:5px\">" + title + "</h1>"
|
||||
div += "<div style=\"width:100%;height:1px;background-color:#ccc;\"></div>";
|
||||
if (content.type == 0) {
|
||||
div += "<p>" + content.text + "</p>"
|
||||
} else if (content.type == 1) {
|
||||
div += "<input type='text' value='" + content.text + "' placeholder='" + content.placeholder + "' autocomplete='off'/>";
|
||||
}
|
||||
if (btnFlag == 0) {
|
||||
div += "<div><span class='ok'>OK</span></div>";
|
||||
} else if (btnFlag == 1) {
|
||||
div += "<div><span class='ok'>OK</span><span class='cancel'>Cancel</span></div>";
|
||||
}
|
||||
div += "</div>";
|
||||
$mask.html(div);
|
||||
$mask.find("input").val($mask.find("input").val());
|
||||
if (content.type == 1) {
|
||||
$mask.find(".ok").on("click", function() {
|
||||
var retText = $mask.find("input").val();
|
||||
hide();
|
||||
if (ok) {
|
||||
ok(retText);
|
||||
}
|
||||
});
|
||||
$mask.find(".cancel").on("click", function() {
|
||||
var retText = $mask.find("input").val();
|
||||
hide();
|
||||
if (cancel) {
|
||||
cancel(retText);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$mask.find(".ok").on("click", function() {
|
||||
hide();
|
||||
if (ok) {
|
||||
ok();
|
||||
}
|
||||
});
|
||||
$mask.find(".cancel").on("click", function() {
|
||||
hide();
|
||||
if (cancel) {
|
||||
cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function calcBoxPos() {
|
||||
var $box = $mask.find("#dlg-box");
|
||||
var mask_w = $mask.outerWidth();
|
||||
var mask_h = $mask.outerHeight();
|
||||
var box_w = $box.outerWidth();
|
||||
var box_h = $box.outerHeight();
|
||||
var pos_left = (mask_w - box_w) / 2 + "px";
|
||||
var pos_top = (mask_h - box_h) / 2 + "px";
|
||||
$box.css("left", pos_left).css("top", pos_top);
|
||||
}
|
||||
|
||||
function show() {
|
||||
$("body").prepend($mask);
|
||||
$mask.css("display", "block");
|
||||
if ($mask.find("input") && $mask.find("input")[0]) {
|
||||
$mask.find("input")[0].focus();
|
||||
}
|
||||
calcBoxPos();
|
||||
$(window).resize(calcBoxPos);
|
||||
}
|
||||
|
||||
function hide() {
|
||||
$mask.css("display", "none");
|
||||
$mask.remove();
|
||||
}
|
||||
|
||||
return {
|
||||
hide: hide,
|
||||
tip: function(title, text, ok) {
|
||||
initHtml(title, { type: 0, text: text }, 0, ok, null);
|
||||
show();
|
||||
},
|
||||
input: function(title, text, placeholder, ok, cancel) {
|
||||
initHtml(title, { type: 1, text: text, placeholder: placeholder }, 1, ok, cancel);
|
||||
show();
|
||||
},
|
||||
confirm: function(title, text, ok, cancel) {
|
||||
initHtml(title, { type: 0, text: text }, 1, ok, cancel);
|
||||
show();
|
||||
}
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1 @@
|
||||
var dialog = (function Dialog() { var e = $("<div id='dlg-mask'></div>"); function d(j, h, i, f, g) { var k = ""; k += "<div id='dlg-box' class='dot'>"; k += "<h1 class='dot'>" + j + "</h1>"; if (h.type == 0) { k += "<p>" + h.text + "</p>" } else { if (h.type == 1) { k += "<input type='text' value='" + h.text + "' placeholder='" + h.placeholder + "' autocomplete='off'/>" } } if (i == 0) { k += "<div><span class='ok'>OK</span></div>" } else { if (i == 1) { k += "<div><span class='ok'>OK</span><span class='cancel'>Cancel</span></div>" } } k += "</div>"; e.html(k); e.find("input").val(e.find("input").val()); if (h.type == 1) { e.find(".ok").on("click", function() { var l = e.find("input").val(); b(); if (f) { f(l) } }); e.find(".cancel").on("click", function() { var l = e.find("input").val(); b(); if (g) { g(l) } }) } else { e.find(".ok").on("click", function() { b(); if (f) { f() } }); e.find(".cancel").on("click", function() { b(); if (g) { g() } }) } } function c() { var k = e.find("#dlg-box"); var h = e.outerWidth(); var j = e.outerHeight(); var l = k.outerWidth(); var g = k.outerHeight(); var f = (h - l) / 2 + "px"; var i = (j - g) / 2 + "px"; k.css("left", f).css("top", i) } function a() { $("body").prepend(e); e.css("display", "block"); if (e.find("input") && e.find("input")[0]) { e.find("input")[0].focus() } c(); $(window).resize(c) } function b() { e.css("display", "none"); e.remove() } return { hide: b, tip: function(h, g, f) { d(h, { type: 0, text: g }, 0, f, null); a() }, input: function(j, i, h, f, g) { d(j, { type: 1, text: i, placeholder: h }, 1, f, g); a() }, confirm: function(i, h, f, g) { d(i, { type: 0, text: h }, 1, f, g); a() } } })();
|
||||
@@ -0,0 +1,183 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Channels</title>
|
||||
<link rel="stylesheet" href="/static/css/base.css">
|
||||
<link rel="stylesheet" href="/static/css/list.css">
|
||||
<link rel="stylesheet" href="/static/css/dialog.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="box">
|
||||
<div class="nav">
|
||||
<div class="nav_left">
|
||||
<img src="/static/images/logo.png" alt="">
|
||||
<p><span>Presenter Server</span></p>
|
||||
</div>
|
||||
<div class="nav_right">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box_top">
|
||||
<span> >View List</span>
|
||||
</div>
|
||||
<div style="width:100%;height:2px;background-color:#ccc;"></div>
|
||||
<div class="box_content">
|
||||
<ul class="content_top">
|
||||
<li class="top_refresh"><img src="/static/images/u1.png" alt=""><span>Refresh</span></li>
|
||||
<li class="top_del"><img src="/static/images/u2.png" alt=""><span>Delete</span></li>
|
||||
</ul>
|
||||
|
||||
<div class="content_bot">
|
||||
<form name="myForm">
|
||||
<table id="mytable" border="1" width="100%">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><input type="checkbox" id="checkAll"></th>
|
||||
<th>Status</th>
|
||||
<th>View Name</th>
|
||||
</tr>
|
||||
{% for item in listret %}
|
||||
<tr>
|
||||
<td>{{item['id']}}</td>
|
||||
<td><input type="checkbox" name="selectFlag" value="1"></td>
|
||||
{% if item['status'] == 1 %}
|
||||
<td><img src="/static/images/u5.png" alt=""></td>
|
||||
{% else %}
|
||||
<td><img src="/static/images/u6.png" alt=""></td>
|
||||
{% end %}
|
||||
<td ><a class="view_channel" style="cursor:pointer">{{item['name']}}</a></td>
|
||||
</tr>
|
||||
{% end %}
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="/static/js/jquery-1.10.2.min.js"></script>
|
||||
<script src="/static/js/dialog.js"></script>
|
||||
<script>
|
||||
$("#checkAll").click(function() {
|
||||
if (this.checked) {
|
||||
$("input[name='selectFlag']:checkbox").each(function() {
|
||||
$(this).attr("checked", true);
|
||||
})
|
||||
} else { //反之 取消全选
|
||||
$("input[name='selectFlag']:checkbox").each(function() {
|
||||
$(this).attr("checked", false);
|
||||
})
|
||||
}
|
||||
});
|
||||
$(".view_channel").click(function(){
|
||||
var url = "/view?name=" + encodeURIComponent($(this).text());
|
||||
window.open(url);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<script>
|
||||
function checkNameValidate()
|
||||
{
|
||||
var name = $("#cname").val().trim();
|
||||
if (name.length == 0)
|
||||
{
|
||||
dialog.tip("Tips","Channel name can not be empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (name.length > 25)
|
||||
{
|
||||
dialog.tip("Tips", "Length of channel name should less than 25" ,function(){});
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < name.length; i++)
|
||||
{
|
||||
var c = name.charAt(i).charCodeAt();
|
||||
var flag = ((c >= 48 && c <= 57) || (c >= 97 && c<= 122) || (c>= 65 && c <= 90) || (c == 47));
|
||||
if (false == flag)
|
||||
{
|
||||
dialog.tip("Tips", "Channel name only support 0-9, a-z, A-Z /" ,function(){});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
$(".top_create").click(function () {
|
||||
if($(".content_mid").css("display")=="none"){
|
||||
$(".content_mid").css("display","block").animate({height:"100px"});
|
||||
}else{
|
||||
$(".content_mid").animate({height:"0"}).css("display","none");
|
||||
}
|
||||
});
|
||||
$(".mid_add").click(function () {
|
||||
var rowlen = $("#mytable").find("tr").length;
|
||||
if (rowlen >= 11)
|
||||
{
|
||||
dialog.tip("Tips", "Presenter supports up to 10 channels" ,function(){});
|
||||
return;
|
||||
}
|
||||
|
||||
//check
|
||||
if (true == checkNameValidate())
|
||||
{
|
||||
var url = "/add?"+"name=" + encodeURIComponent($("#cname").val().trim()) +"&time="+(new Date().getTime());
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
dataType: "json",
|
||||
success: function(data)
|
||||
{
|
||||
if (data["ret"] == "success")
|
||||
{
|
||||
window.location.reload()
|
||||
}
|
||||
else
|
||||
{
|
||||
dialog.tip("Tips", data["msg"], function(){});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
$(".top_refresh").click(function () {
|
||||
window.location.reload();
|
||||
});
|
||||
$(".top_del").click(function () {
|
||||
if($("input[name='selectFlag']").is(":checked")){
|
||||
var msg = "";
|
||||
$("input[name='selectFlag']:checked").each(function() {
|
||||
// 遍历选中的checkbox
|
||||
tr = $(this).parents("tr");
|
||||
td = $(tr).find("td");
|
||||
msg += encodeURIComponent($(td).eq(3).text());
|
||||
msg += ",";
|
||||
});
|
||||
dialog.confirm("Tips", "Are you sure to delete ?", function(){
|
||||
var url = "/del?"+"time="+(new Date().getTime())+"&name="+msg;
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
dataType: "json",
|
||||
success: function(data)
|
||||
{
|
||||
if (data["ret"] == "success")
|
||||
{
|
||||
window.location.reload()
|
||||
}
|
||||
else
|
||||
{
|
||||
dialog.tip("Tips", data["msg"], function(){});
|
||||
}
|
||||
},
|
||||
});
|
||||
}, function(){});
|
||||
}else{
|
||||
dialog.tip("Tips", "Please select one item at least", function(){});
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
</html>
|
||||
@@ -0,0 +1,155 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>view</title>
|
||||
<link rel="stylesheet" href="/static/css/base.css">
|
||||
<link rel="stylesheet" href="/static/css/testvideo.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="video_box">
|
||||
<div class="nav">
|
||||
<div class="nav_left">
|
||||
<img src="/static/images/logo.png" alt="">
|
||||
<p><span>Presenter Server</span></p>
|
||||
</div>
|
||||
<div class="nav_right">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="video_top">
|
||||
<span> >view</span>
|
||||
</div>
|
||||
<div style="width:100%;height:2px;background-color:#ccc;"></div>
|
||||
<div class="video_content">
|
||||
<div class="video_fps" id='fpswapper' hidden><p><span> channel name: {{ channel_name }} </span> <span> fps:</span><span id='fpsval'></span></p></div>
|
||||
<div class="video_inner">
|
||||
<img src="/static/images/loading.gif" id = "loading" board = "1" alt=""/>
|
||||
<!-- <img id = "load_media" hidden width = "1024px" board = "1" alt=""/> -->
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="/static/js/jquery-1.10.2.min.js"></script>
|
||||
<script>
|
||||
|
||||
var canvas=document.getElementById("canvas")
|
||||
var ctx=canvas.getContext("2d")
|
||||
$('#fpswapper').hide()
|
||||
$('#loading').hide()
|
||||
|
||||
function startViewVideo(){
|
||||
$('#loading').show()
|
||||
$('#canvas').hide()
|
||||
|
||||
var image = new Image();
|
||||
var wsProtocol = "ws://";
|
||||
if (window.location.protocol == "https:"){
|
||||
wsProtocol = "wss://";
|
||||
}
|
||||
var wsUrl = wsProtocol + window.location.host+"/websocket?req={{req}}&name={{channel_name}}";
|
||||
var ws = new WebSocket(wsUrl);
|
||||
var onmessageflag = false;
|
||||
|
||||
ws.onopen = function() {
|
||||
ws.send('next');
|
||||
};
|
||||
var count = 0;
|
||||
var timestart = 0;
|
||||
|
||||
ws.onmessage = function (evt) {
|
||||
$('#loading').hide()
|
||||
$('#canvas').show()
|
||||
var data = JSON.parse(evt.data)
|
||||
var rectangles = []
|
||||
if ('ok' == data['status']){
|
||||
$('#fpsval').text(data.fps);
|
||||
$('#loading').hide();
|
||||
// $('#load_media').show();
|
||||
var src = "data:image/jpeg;base64," + data['image'];
|
||||
// $('#load_media').attr('src', src);
|
||||
if (data['type'] == 'video'){
|
||||
$('#fpswapper').show();
|
||||
rectangles = data['rectangle_list']
|
||||
}
|
||||
var wantedWidth = 1024
|
||||
var img = new Image()
|
||||
img.src = src
|
||||
img.onload=function(){
|
||||
scale_factor = wantedWidth/img.width
|
||||
canvas.setAttribute("width",1024)
|
||||
canvas.setAttribute("height",img.height*scale_factor)
|
||||
ctx.strokeStyle="yellow"
|
||||
ctx.font="30px serif"
|
||||
ctx.fillStyle="yellow"
|
||||
ctx.strokeStyle="yellow"
|
||||
ctx.font="30px serif"
|
||||
ctx.fillStyle="yellow"
|
||||
ctx.drawImage(img,0,0, wantedWidth, img.height*scale_factor)
|
||||
for (var index in rectangles){
|
||||
var pos= rectangles[index].slice(0,4) //
|
||||
for (var i in pos){
|
||||
pos[i] = pos[i]*scale_factor
|
||||
}
|
||||
var msg = rectangles[index].slice(4,5)
|
||||
//add space between msg and face
|
||||
//if upper space is not enough show the msg at the bottom
|
||||
if(50>pos[1]){
|
||||
// ctx.fillText(msg,pos[0],pos[3]+50)
|
||||
}
|
||||
else{
|
||||
// ctx.fillText(msg,pos[0],pos[1]-10)
|
||||
}
|
||||
ctx.beginPath()
|
||||
// 1/3 space draw line
|
||||
if(msg == 'points'){
|
||||
ctx.strokeStyle = "#0F4F00"
|
||||
ctx.arc(pos[0],pos[1],6,0,2*Math.PI)
|
||||
ctx.fillStyle = "#6CFF33"
|
||||
ctx.fill()
|
||||
|
||||
}else if(msg == 'hand_box'){
|
||||
ctx.strokeStyle = "#FF0000"
|
||||
ctx.lineWidth = 5
|
||||
ctx.moveTo(pos[0],pos[1])
|
||||
ctx.lineTo(pos[2],pos[1])
|
||||
ctx.moveTo(pos[2],pos[1])
|
||||
ctx.lineTo(pos[2],pos[3])
|
||||
ctx.moveTo(pos[0],pos[1])
|
||||
ctx.lineTo(pos[0],pos[3])
|
||||
ctx.moveTo(pos[0],pos[3])
|
||||
ctx.lineTo(pos[2],pos[3])
|
||||
// }else if(msg == 'hand_point'){
|
||||
// ctx.strokeStyle = "#33FAFF"
|
||||
// ctx.arc(pos[0],pos[1],3,0,2*Math.PI)
|
||||
// ctx.fillStyle = "#33FAFF"
|
||||
// ctx.fill()
|
||||
// }else if(msg == 'hand'){
|
||||
// ctx.strokeStyle = "#FC33FF"
|
||||
// ctx.lineWidth = 3
|
||||
// ctx.moveTo(pos[0],pos[1])
|
||||
// ctx.lineTo(pos[2],pos[3])
|
||||
|
||||
}else if(msg == 'body'){
|
||||
ctx.strokeStyle = "#FFF700"
|
||||
ctx.lineWidth = 5
|
||||
ctx.moveTo(pos[0],pos[1])
|
||||
ctx.lineTo(pos[2],pos[3])
|
||||
}else{
|
||||
ctx.font = "30px Arial";
|
||||
ctx.lineWidth = 5
|
||||
ctx.fillStyle = "#33FAFF"
|
||||
ctx.fillText(msg, 200, 200);
|
||||
}
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
}
|
||||
ws.send('next');
|
||||
}
|
||||
}
|
||||
startViewVideo();
|
||||
|
||||
</script>
|
||||
</html>
|
||||
@@ -0,0 +1,209 @@
|
||||
# =======================================================================
|
||||
#
|
||||
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1 Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2 Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3 Neither the names of the copyright holders nor the names of the
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# =======================================================================
|
||||
#
|
||||
"""presenter app manager module"""
|
||||
|
||||
import time
|
||||
import threading
|
||||
import logging
|
||||
from common.channel_manager import ChannelManager
|
||||
|
||||
# Heartbeat timeout, exceeding the limit, the socket will disconnect
|
||||
HEARTBEAT_TIMEOUT = 100
|
||||
|
||||
class App():
|
||||
'''App class, When receive an app request from
|
||||
Presenter Agent, creat an object.
|
||||
'''
|
||||
def __init__(self, app_id, conn=None):
|
||||
self.app_id = app_id
|
||||
self.heartbeat = time.time()
|
||||
self.socket_fd = conn.fileno()
|
||||
# set timeout 1 second
|
||||
conn.settimeout(1)
|
||||
self.socket = conn
|
||||
self.frame_num_dict = {}
|
||||
|
||||
class AppManager():
|
||||
'''A class provides app management features'''
|
||||
__instance = None
|
||||
channel_manager = None
|
||||
app_list_lock = threading.Lock()
|
||||
app_list = []
|
||||
thread_switch = False
|
||||
|
||||
def __init__(self):
|
||||
"""init func"""
|
||||
|
||||
|
||||
def __new__(cls):
|
||||
"""ensure only a single instance created. """
|
||||
if cls.__instance is None:
|
||||
cls.__instance = object.__new__(cls)
|
||||
cls.channel_manager = ChannelManager([])
|
||||
cls._create_thread()
|
||||
return cls.__instance
|
||||
|
||||
@classmethod
|
||||
def _create_thread(cls):
|
||||
"""_create_thread."""
|
||||
|
||||
thread = threading.Thread(target=cls._app_thread)
|
||||
thread.start()
|
||||
|
||||
@classmethod
|
||||
def _app_thread(cls):
|
||||
"""background thread to process video"""
|
||||
logging.info('create app manager thread')
|
||||
while True:
|
||||
if cls.thread_switch:
|
||||
break
|
||||
for i in range(len(cls.app_list)):
|
||||
if time.time() - cls.app_list[i].heartbeat > HEARTBEAT_TIMEOUT:
|
||||
app_id = cls.app_list[i].app_id
|
||||
cls.channel_manager.unregister_one_channel(app_id)
|
||||
del cls.app_list[i]
|
||||
logging.info("unregister app: %s", app_id)
|
||||
time.sleep(1)
|
||||
|
||||
def set_thread_switch(self):
|
||||
AppManager.thread_switch = True
|
||||
|
||||
def register_app(self, app_id, socket):
|
||||
"""
|
||||
API for registering an app
|
||||
Args:
|
||||
app_id: app id, must be globally unique
|
||||
socket: a socket communicating with the app
|
||||
"""
|
||||
with self.app_list_lock:
|
||||
for i in range(len(self.app_list)):
|
||||
if self.app_list[i].app_id == app_id:
|
||||
return False
|
||||
|
||||
app = App(app_id, socket)
|
||||
self.app_list.append(app)
|
||||
self.channel_manager.register_one_channel(app_id)
|
||||
logging.info("register app: %s", app_id)
|
||||
return True
|
||||
|
||||
def unregister_app_by_fd(self, sock_fileno):
|
||||
"""
|
||||
API for unregistering an app
|
||||
Args:
|
||||
sock_fileno: sock_fileno is binded to an app.
|
||||
Through it, find the app and delete it.
|
||||
"""
|
||||
with self.app_list_lock:
|
||||
for i in range(len(self.app_list)):
|
||||
if self.app_list[i].socket_fd == sock_fileno:
|
||||
app_id = self.app_list[i].app_id
|
||||
self.channel_manager.unregister_one_channel(app_id)
|
||||
del self.app_list[i]
|
||||
logging.info("unregister app: %s", app_id)
|
||||
break
|
||||
|
||||
def get_socket_by_app_id(self, app_id):
|
||||
"""
|
||||
API for finding an app
|
||||
Args:
|
||||
app_id: the id of an app.
|
||||
"""
|
||||
with self.app_list_lock:
|
||||
for i in range(len(self.app_list)):
|
||||
if self.app_list[i].app_id == app_id:
|
||||
return self.app_list[i].socket
|
||||
return None
|
||||
|
||||
def get_app_id_by_socket(self, sock_fd):
|
||||
"""
|
||||
API for get app id by socket
|
||||
Args:
|
||||
sock_fd: sock_fd is binded to an app.
|
||||
Through it, find the app and delete it.
|
||||
"""
|
||||
with self.app_list_lock:
|
||||
for i in range(len(self.app_list)):
|
||||
if self.app_list[i].socket_fd == sock_fd:
|
||||
return self.app_list[i].app_id
|
||||
return None
|
||||
|
||||
def is_app_exist(self, app_id):
|
||||
"""
|
||||
API for checking if the app exist
|
||||
Args:
|
||||
app_id: the id of an app.
|
||||
"""
|
||||
with self.app_list_lock:
|
||||
for i in range(len(self.app_list)):
|
||||
if self.app_list[i].app_id == app_id:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_app_num(self):
|
||||
"""
|
||||
API for getting the number of apps
|
||||
Args: NA
|
||||
"""
|
||||
with self.app_list_lock:
|
||||
return len(self.app_list)
|
||||
|
||||
def set_heartbeat(self, sock_fileno):
|
||||
with self.app_list_lock:
|
||||
for i in range(len(self.app_list)):
|
||||
if self.app_list[i].socket_fd == sock_fileno:
|
||||
self.app_list[i].heartbeat = time.time()
|
||||
|
||||
def increase_frame_num(self, app_id, channel_id):
|
||||
with self.app_list_lock:
|
||||
for i in range(len(self.app_list)):
|
||||
if self.app_list[i].app_id == app_id:
|
||||
if channel_id in self.app_list[i].frame_num_dict:
|
||||
self.app_list[i].frame_num_dict[channel_id] += 1
|
||||
else:
|
||||
self.app_list[i].frame_num_dict[channel_id] = 1
|
||||
|
||||
def get_frame_num(self, app_id, channel_id):
|
||||
with self.app_list_lock:
|
||||
for i in range(len(self.app_list)):
|
||||
if self.app_list[i].app_id == app_id:
|
||||
if channel_id in self.app_list[i].frame_num_dict:
|
||||
return self.app_list[i].frame_num_dict[channel_id]
|
||||
else:
|
||||
return 0
|
||||
return 0
|
||||
def list_app(self):
|
||||
"""
|
||||
API for listing all apps
|
||||
Args: NA
|
||||
"""
|
||||
with self.app_list_lock:
|
||||
return [self.app_list[i].app_id for i in range(len(self.app_list))]
|
||||
@@ -0,0 +1,227 @@
|
||||
# =======================================================================
|
||||
#
|
||||
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1 Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2 Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3 Neither the names of the copyright holders nor the names of the
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# =======================================================================
|
||||
#
|
||||
|
||||
"""presenter channel manager module"""
|
||||
|
||||
import time
|
||||
import logging
|
||||
import threading
|
||||
from threading import get_ident
|
||||
from common.channel_manager import ChannelManager
|
||||
|
||||
# thread event timeout, The unit is second.
|
||||
WEB_EVENT_TIMEOUT = 2
|
||||
# thread event timeout, The unit is second.
|
||||
IMAGE_EVENT_TIMEOUT = 10
|
||||
|
||||
# heart beat timeout, The unit is second.
|
||||
HEARTBEAT_TIMEOUT = 100
|
||||
|
||||
class ThreadEvent():
|
||||
"""An Event-like class that signals all active clients when a new frame is
|
||||
available.
|
||||
"""
|
||||
def __init__(self, timeout=None):
|
||||
self.events = {}
|
||||
self.timeout = timeout
|
||||
|
||||
def wait(self):
|
||||
"""Invoked from each client's thread to wait for the next frame."""
|
||||
ident = get_ident()
|
||||
if ident not in self.events:
|
||||
# this is a new client
|
||||
# add an entry for it in the self.events dict
|
||||
# each entry has two elements, a threading.Event() and a timestamp
|
||||
self.events[ident] = [threading.Event(), time.time()]
|
||||
return self.events[ident][0].wait(self.timeout)
|
||||
|
||||
def set(self):
|
||||
"""Invoked by the camera thread when a new frame is available."""
|
||||
now = time.time()
|
||||
remove = None
|
||||
for ident, event in self.events.items():
|
||||
if not event[0].isSet():
|
||||
# if this client's event is not set, then set it
|
||||
# also update the last set timestamp to now
|
||||
event[0].set()
|
||||
event[1] = now
|
||||
else:
|
||||
# if the client's event is already set, it means the client
|
||||
# did not process a previous frame
|
||||
# if the event stays set for more than 5 seconds, then assume
|
||||
# the client is gone and remove it
|
||||
if now - event[1] > 5:
|
||||
remove = ident
|
||||
if remove:
|
||||
del self.events[remove]
|
||||
|
||||
def clear(self):
|
||||
"""Invoked from each client's thread after a frame was processed."""
|
||||
self.events[get_ident()][0].clear()
|
||||
|
||||
class ChannelHandler():
|
||||
"""A set of channel handlers, process data received from channel"""
|
||||
def __init__(self, channel_name, media_type):
|
||||
self.channel_name = channel_name
|
||||
self.media_type = media_type
|
||||
self.img_data = None
|
||||
self._frame = None
|
||||
self.thread = None
|
||||
self._frame = None
|
||||
# last time the channel receive data.
|
||||
self.heartbeat = time.time()
|
||||
self.web_event = ThreadEvent(timeout=WEB_EVENT_TIMEOUT)
|
||||
self.image_event = ThreadEvent(timeout=IMAGE_EVENT_TIMEOUT)
|
||||
self.lock = threading.Lock()
|
||||
self.channel_manager = ChannelManager([])
|
||||
self.rectangle_list = None
|
||||
|
||||
if media_type == "video":
|
||||
self.thread_name = "videothread-{}".format(self.channel_name)
|
||||
self.heartbeat = time.time()
|
||||
self.close_thread_switch = False
|
||||
self.fps = 0
|
||||
self.image_number = 0
|
||||
self.time_list = []
|
||||
self._create_thread()
|
||||
|
||||
def close_thread(self):
|
||||
"""close thread if object has created"""
|
||||
if self.thread is None:
|
||||
return
|
||||
|
||||
self.set_thread_switch()
|
||||
self.image_event.set()
|
||||
logging.info("%s set _close_thread_switch True", self.thread_name)
|
||||
|
||||
def set_heartbeat(self):
|
||||
"""record heartbeat"""
|
||||
self.heartbeat = time.time()
|
||||
|
||||
def set_thread_switch(self):
|
||||
"""record heartbeat"""
|
||||
self.close_thread_switch = True
|
||||
|
||||
def save_image(self, data, width, height, rectangle_list):
|
||||
"""save image receive from socket"""
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.rectangle_list = rectangle_list
|
||||
|
||||
# compute fps if type is video
|
||||
if self.media_type == "video":
|
||||
while self.img_data:
|
||||
time.sleep(0.01)
|
||||
|
||||
self.time_list.append(self.heartbeat)
|
||||
self.image_number += 1
|
||||
while self.time_list[0] + 1 < time.time():
|
||||
self.time_list.pop(0)
|
||||
self.image_number -= 1
|
||||
if self.image_number == 0:
|
||||
break
|
||||
|
||||
self.fps = len(self.time_list)
|
||||
self.img_data = data
|
||||
self.image_event.set()
|
||||
else:
|
||||
self.img_data = data
|
||||
self.channel_manager.save_channel_image(self.channel_name,
|
||||
self.img_data, self.rectangle_list)
|
||||
|
||||
self.heartbeat = time.time()
|
||||
|
||||
|
||||
def get_media_type(self):
|
||||
"""get media_type, support image or video"""
|
||||
return self.media_type
|
||||
|
||||
def get_image(self):
|
||||
"""get image_data"""
|
||||
return self.img_data
|
||||
|
||||
def _create_thread(self):
|
||||
"""Start the background video thread if it isn't running yet."""
|
||||
if self.thread is not None and self.thread.isAlive():
|
||||
return
|
||||
|
||||
# start background frame thread
|
||||
self.thread = threading.Thread(target=self._video_thread)
|
||||
self.thread.start()
|
||||
|
||||
def get_frame(self):
|
||||
"""Return the current video frame."""
|
||||
# wait util receive a frame data, and push it to your browser.
|
||||
ret = self.web_event.wait()
|
||||
self.web_event.clear()
|
||||
# True: _web_event return because set()
|
||||
# False: _web_event return because timeout
|
||||
if ret:
|
||||
return (self._frame, self.fps, self.width, self.height, self.rectangle_list)
|
||||
|
||||
return (None, None, None, None, None)
|
||||
|
||||
def frames(self):
|
||||
"""a generator generates image"""
|
||||
while True:
|
||||
self.image_event.wait()
|
||||
self.image_event.clear()
|
||||
if self.img_data:
|
||||
yield self.img_data
|
||||
self.img_data = None
|
||||
|
||||
# if set _close_thread_switch, return immediately
|
||||
if self.close_thread_switch:
|
||||
yield None
|
||||
|
||||
# if no frames or heartbeat coming in the last 100 seconds,
|
||||
# stop the thread and close socket
|
||||
if time.time() - self.heartbeat > HEARTBEAT_TIMEOUT:
|
||||
self.set_thread_switch()
|
||||
self.img_data = None
|
||||
yield None
|
||||
|
||||
def _video_thread(self):
|
||||
"""background thread to process video"""
|
||||
logging.info('create %s...', (self.thread_name))
|
||||
for frame in self.frames():
|
||||
if frame:
|
||||
# send signal to clients
|
||||
self._frame = frame
|
||||
self.web_event.set()
|
||||
|
||||
# exit thread
|
||||
if self.close_thread_switch:
|
||||
self.channel_manager.clean_channel_resource_by_name(
|
||||
self.channel_name)
|
||||
logging.info('Stop thread:%s.', (self.thread_name))
|
||||
break
|
||||
@@ -0,0 +1,291 @@
|
||||
# =======================================================================
|
||||
#
|
||||
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1 Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2 Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3 Neither the names of the copyright holders nor the names of the
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# =======================================================================
|
||||
#
|
||||
"""presenter channel manager module"""
|
||||
|
||||
import logging
|
||||
import threading
|
||||
|
||||
# max support 10 channels
|
||||
MAX_CHANNEL_NUM = 10
|
||||
|
||||
# when a channel have receive data,
|
||||
# the active status will last 3 seconds
|
||||
ACTIVE_LAST_TIME = 3
|
||||
|
||||
class ChannelResource():
|
||||
"""every channel has a ChannelResource object, contains a ChannelHandler object
|
||||
and a socket fileno. it corresponding to the ChannelFd one by one
|
||||
"""
|
||||
def __init__(self, handler, socket=None):
|
||||
self.handler = handler
|
||||
self.socket = socket
|
||||
|
||||
class ChannelFd():
|
||||
"""every channel has a ChannelFd object, contains a ChannelHandler
|
||||
object and channel name. It corresponds to the ChannelResource one by one
|
||||
"""
|
||||
def __init__(self, channel_name, handler):
|
||||
self.channel_name = channel_name
|
||||
self.handler = handler
|
||||
|
||||
class Channel():
|
||||
"""record user register channels
|
||||
self.image: if channel type is image, save the image here
|
||||
"""
|
||||
def __init__(self, channel_name):
|
||||
self.channel_name = channel_name
|
||||
self.image = None
|
||||
self.rectangle_list = None
|
||||
|
||||
class ChannelManager():
|
||||
"""manage all the api about channel
|
||||
__instance: ensure it is a single instance
|
||||
_channel_resources: a dict
|
||||
key: channel name
|
||||
value: a ChannelResource() object.
|
||||
_channel_fds: a dict
|
||||
key: socket fileno
|
||||
value: a ChannelFd() object.
|
||||
_channel_list: a list, member is a Channel() object."""
|
||||
|
||||
__instance = None
|
||||
channel_resources = {}
|
||||
channel_fds = {}
|
||||
channel_list = []
|
||||
channel_resource_lock = threading.Lock()
|
||||
channel_fds_lock = threading.Lock()
|
||||
channel_lock = threading.Lock()
|
||||
err_code_ok = 0
|
||||
err_code_too_many_channel = 1
|
||||
err_code_repeat_channel = 2
|
||||
|
||||
def __init__(self, channel_list=None):
|
||||
"""init func"""
|
||||
|
||||
def __new__(cls, channel_list=None):
|
||||
"""ensure only a single instance created. """
|
||||
if cls.__instance is None:
|
||||
cls.__instance = object.__new__(cls)
|
||||
# default create 2 channels: image and video
|
||||
# if channel_list is not None and isinstance(channel_list, list):
|
||||
# for i in channel_list:
|
||||
# cls.channel_list.append(Channel(channel_name=i))
|
||||
# logging.info("register channel %s", i)
|
||||
return cls.__instance
|
||||
|
||||
def _register_channel_fd(self, sock_fileno, channel_name):
|
||||
"""Internal func, create a ChannelFd object"""
|
||||
if self.channel_fds.get(sock_fileno):
|
||||
del self.channel_fds[sock_fileno]
|
||||
handler = self.channel_resources[channel_name].handler
|
||||
self.channel_fds[sock_fileno] = ChannelFd(channel_name, handler)
|
||||
|
||||
|
||||
def create_channel_resource(self, channel_name,
|
||||
channel_fd,
|
||||
media_type,
|
||||
handler):
|
||||
"""create a ChannelResource object which contains all the resources
|
||||
binding a channel.
|
||||
channel_name: channel name.
|
||||
channel_fd: socket fileno binding the channel.
|
||||
media_type: support image or video.
|
||||
handler: an channel handler process image data.
|
||||
"""
|
||||
with self.channel_resource_lock:
|
||||
log_info = "create channel resource,"
|
||||
log_info += " channel_name:%s, channel_fd:%u, media_type:%s"
|
||||
logging.info(log_info, channel_name, channel_fd, media_type)
|
||||
self.channel_resources[channel_name] = \
|
||||
ChannelResource(handler=handler, socket=channel_fd)
|
||||
self._register_channel_fd(channel_fd, channel_name)
|
||||
|
||||
def _clean_channel_resource(self, channel_name):
|
||||
"""Internal func, clean channel resource by channel name"""
|
||||
if self.channel_resources.get(channel_name):
|
||||
self.channel_resources[channel_name].handler.close_thread()
|
||||
self.channel_resources[channel_name].handler.web_event.set()
|
||||
self.channel_resources[channel_name].handler.image_event.set()
|
||||
del self.channel_resources[channel_name]
|
||||
logging.info("clean channel: %s's resource", channel_name)
|
||||
|
||||
def clean_channel_resource_by_fd(self, sock_fileno):
|
||||
"""
|
||||
clean channel resource by socket fileno
|
||||
sock_fileno: socket fileno which binding to an channel
|
||||
"""
|
||||
with self.channel_fds_lock:
|
||||
with self.channel_resource_lock:
|
||||
if self.channel_fds.get(sock_fileno):
|
||||
self._clean_channel_resource(
|
||||
self.channel_fds[sock_fileno].channel_name)
|
||||
del self.channel_fds[sock_fileno]
|
||||
|
||||
def clean_channel_resource_by_name(self, channel_name):
|
||||
"""clean channel resource by channel_name
|
||||
channel_name: channel name"""
|
||||
if self.channel_resources.get(channel_name):
|
||||
self.clean_channel_resource_by_fd(
|
||||
self.channel_resources[channel_name].socket)
|
||||
|
||||
def get_channel_handler_by_fd(self, sock_fileno):
|
||||
"""get channel handler by socket fileno"""
|
||||
with self.channel_fds_lock:
|
||||
if self.channel_fds.get(sock_fileno):
|
||||
return self.channel_fds[sock_fileno].handler
|
||||
return None
|
||||
|
||||
def is_channel_busy(self, channel_name):
|
||||
"""check if channel is busy """
|
||||
with self.channel_resource_lock:
|
||||
if self.channel_resources.get(channel_name):
|
||||
return True
|
||||
return False
|
||||
|
||||
def close_all_thread(self):
|
||||
"""if a channel process video type, it will create a thread.
|
||||
this func can close the thread.
|
||||
"""
|
||||
with self.channel_resource_lock:
|
||||
for channel_name in self.channel_resources:
|
||||
self.channel_resources[channel_name].handler.close_thread()
|
||||
|
||||
def get_channel_handler_by_name(self, channel_name):
|
||||
"""
|
||||
get the channel handlerby channel name
|
||||
"""
|
||||
with self.channel_resource_lock:
|
||||
if self.channel_resources.get(channel_name):
|
||||
return self.channel_resources[channel_name].handler
|
||||
return None
|
||||
|
||||
def list_channels(self):
|
||||
"""
|
||||
return all the channel name and the status
|
||||
status is indicating active state or not
|
||||
"""
|
||||
with self.channel_lock:
|
||||
return [{'status': self.is_channel_busy(i.channel_name),
|
||||
'name': i.channel_name} for i in self.channel_list]
|
||||
|
||||
def register_one_channel(self, channel_name):
|
||||
"""
|
||||
register a channel path, user create a channel via browser
|
||||
"""
|
||||
with self.channel_lock:
|
||||
if len(self.channel_list) >= MAX_CHANNEL_NUM:
|
||||
logging.info("register channel: %s fail, \
|
||||
exceed max number 10.", channel_name)
|
||||
return self.err_code_too_many_channel
|
||||
for i in range(len(self.channel_list)):
|
||||
if self.channel_list[i].channel_name == channel_name:
|
||||
logging.info("register channel: %s fail, \
|
||||
already exist.", channel_name)
|
||||
return self.err_code_repeat_channel
|
||||
|
||||
self.channel_list.append(Channel(channel_name=channel_name))
|
||||
logging.info("register channel: %s", channel_name)
|
||||
return self.err_code_ok
|
||||
|
||||
def unregister_one_channel(self, channel_name):
|
||||
"""
|
||||
unregister a channel path, user delete a channel via browser
|
||||
"""
|
||||
with self.channel_lock:
|
||||
for i in range(len(self.channel_list)):
|
||||
if self.channel_list[i].channel_name == channel_name:
|
||||
self.clean_channel_resource_by_name(channel_name)
|
||||
logging.info("unregister channel: %s", channel_name)
|
||||
del self.channel_list[i]
|
||||
break
|
||||
|
||||
def is_channel_exist(self, channel_name):
|
||||
"""
|
||||
Check if a channel is exist
|
||||
True: exist
|
||||
False: not exist
|
||||
"""
|
||||
with self.channel_lock:
|
||||
for i in range(len(self.channel_list)):
|
||||
if self.channel_list[i].channel_name == channel_name:
|
||||
return True
|
||||
return False
|
||||
|
||||
def save_channel_image(self, channel_name, image_data, rectangle_list):
|
||||
"""
|
||||
when a channel bounding to image type,
|
||||
server will permanent hold an image for it.
|
||||
this func save a image in memory
|
||||
"""
|
||||
with self.channel_lock:
|
||||
for i in range(len(self.channel_list)):
|
||||
if self.channel_list[i].channel_name == channel_name:
|
||||
self.channel_list[i].image = image_data
|
||||
self.channel_list[i].rectangle_list = rectangle_list
|
||||
break
|
||||
|
||||
def get_channel_image(self, channel_name):
|
||||
"""
|
||||
when a channel bounding to image type,
|
||||
server will permanent hold an image for it.
|
||||
this func get the image
|
||||
"""
|
||||
with self.channel_lock:
|
||||
for i in range(len(self.channel_list)):
|
||||
if self.channel_list[i].channel_name == channel_name:
|
||||
return self.channel_list[i].image
|
||||
|
||||
# channel not exist
|
||||
return None
|
||||
|
||||
def get_channel_image_with_rectangle(self, channel_name):
|
||||
"""
|
||||
A new method for display server,
|
||||
return the image and rectangle list
|
||||
"""
|
||||
with self.channel_lock:
|
||||
for i in range(len(self.channel_list)):
|
||||
if self.channel_list[i].channel_name == channel_name:
|
||||
return (self.channel_list[i].image, self.channel_list[i].rectangle_list)
|
||||
return (None, None)
|
||||
|
||||
def clean_channel_image(self, channel_name):
|
||||
"""
|
||||
when a channel bounding to image type,
|
||||
server will permanent hold an image for it.
|
||||
this func clean the image
|
||||
"""
|
||||
with self.channel_lock:
|
||||
for i in range(len(self.channel_list)):
|
||||
if self.channel_list[i].channel_name == channel_name:
|
||||
self.channel_list[i].image = None
|
||||
break
|
||||
@@ -0,0 +1,98 @@
|
||||
# =======================================================================
|
||||
#
|
||||
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1 Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2 Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3 Neither the names of the copyright holders nor the names of the
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# =======================================================================
|
||||
#
|
||||
"""Parameter Validation module"""
|
||||
import logging
|
||||
|
||||
PORT_INTERVAL_BEGIN = 1024
|
||||
PORT_INTERVAL_END = 49151
|
||||
|
||||
def validate_ip(ip_str):
|
||||
if ip_str == '0.0.0.0':
|
||||
logging.error("IP Addr \"0.0.0.0\" is illegal")
|
||||
print("IP Addr \"0.0.0.0\" is illegal")
|
||||
return False
|
||||
|
||||
sep = ip_str.split('.')
|
||||
if len(sep) != 4:
|
||||
return False
|
||||
for i, x in enumerate(sep):
|
||||
try:
|
||||
int_x = int(x)
|
||||
if int_x < 0 or int_x > 255:
|
||||
logging.error("Illegal ip: %s", ip_str)
|
||||
print("Illegal ip: %s"%ip_str)
|
||||
return False
|
||||
except ValueError:
|
||||
logging.error("IP format error:%s", ip_str)
|
||||
print("IP format error:%s"%ip_str)
|
||||
return False
|
||||
return True
|
||||
|
||||
def validate_port(value_str):
|
||||
try:
|
||||
value = int(value_str)
|
||||
if value < PORT_INTERVAL_BEGIN or value > PORT_INTERVAL_END:
|
||||
logging.error("Illegal port: %d", value)
|
||||
print("Illegal port: %d"%value)
|
||||
return False
|
||||
except ValueError:
|
||||
logging.error("Port format error:%s", value_str)
|
||||
print("Port format error:%s"%value_str)
|
||||
return False
|
||||
return True
|
||||
|
||||
def validate_integer(value_str, begin, end):
|
||||
try:
|
||||
value = int(value_str)
|
||||
if value < begin or value > end:
|
||||
return False
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def Integer_greater(value_str, compared_value):
|
||||
try:
|
||||
value = int(value_str)
|
||||
if value < compared_value:
|
||||
return False
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def validate_float(value_str, begin, end):
|
||||
try:
|
||||
value = float(value_str)
|
||||
if value < begin or value > end:
|
||||
return False
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
@@ -0,0 +1,525 @@
|
||||
# =======================================================================
|
||||
#
|
||||
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1 Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2 Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3 Neither the names of the copyright holders nor the names of the
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# =======================================================================
|
||||
#
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: presenter_message.proto
|
||||
|
||||
import sys
|
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf import descriptor_pb2
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='presenter_message.proto',
|
||||
package='ascend.presenter.proto',
|
||||
syntax='proto3',
|
||||
serialized_pb=_b('\n\x17presenter_message.proto\x12\x16\x61scend.presenter.proto\"l\n\x12OpenChannelRequest\x12\x14\n\x0c\x63hannel_name\x18\x01 \x01(\t\x12@\n\x0c\x63ontent_type\x18\x02 \x01(\x0e\x32*.ascend.presenter.proto.ChannelContentType\"n\n\x13OpenChannelResponse\x12@\n\nerror_code\x18\x01 \x01(\x0e\x32,.ascend.presenter.proto.OpenChannelErrorCode\x12\x15\n\rerror_message\x18\x02 \x01(\t\"\x12\n\x10HeartbeatMessage\"\"\n\nCoordinate\x12\t\n\x01x\x18\x01 \x01(\r\x12\t\n\x01y\x18\x02 \x01(\r\"\x94\x01\n\x0eRectangle_Attr\x12\x34\n\x08left_top\x18\x01 \x01(\x0b\x32\".ascend.presenter.proto.Coordinate\x12\x38\n\x0cright_bottom\x18\x02 \x01(\x0b\x32\".ascend.presenter.proto.Coordinate\x12\x12\n\nlabel_text\x18\x03 \x01(\t\"\xb7\x01\n\x13PresentImageRequest\x12\x33\n\x06\x66ormat\x18\x01 \x01(\x0e\x32#.ascend.presenter.proto.ImageFormat\x12\r\n\x05width\x18\x02 \x01(\r\x12\x0e\n\x06height\x18\x03 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12>\n\x0erectangle_list\x18\x05 \x03(\x0b\x32&.ascend.presenter.proto.Rectangle_Attr\"o\n\x14PresentImageResponse\x12@\n\nerror_code\x18\x01 \x01(\x0e\x32,.ascend.presenter.proto.PresentDataErrorCode\x12\x15\n\rerror_message\x18\x02 \x01(\t*\xa5\x01\n\x14OpenChannelErrorCode\x12\x19\n\x15kOpenChannelErrorNone\x10\x00\x12\"\n\x1ekOpenChannelErrorNoSuchChannel\x10\x01\x12)\n%kOpenChannelErrorChannelAlreadyOpened\x10\x02\x12#\n\x16kOpenChannelErrorOther\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01*P\n\x12\x43hannelContentType\x12\x1c\n\x18kChannelContentTypeImage\x10\x00\x12\x1c\n\x18kChannelContentTypeVideo\x10\x01*#\n\x0bImageFormat\x12\x14\n\x10kImageFormatJpeg\x10\x00*\xa4\x01\n\x14PresentDataErrorCode\x12\x19\n\x15kPresentDataErrorNone\x10\x00\x12$\n kPresentDataErrorUnsupportedType\x10\x01\x12&\n\"kPresentDataErrorUnsupportedFormat\x10\x02\x12#\n\x16kPresentDataErrorOther\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x62\x06proto3')
|
||||
)
|
||||
|
||||
_OPENCHANNELERRORCODE = _descriptor.EnumDescriptor(
|
||||
name='OpenChannelErrorCode',
|
||||
full_name='ascend.presenter.proto.OpenChannelErrorCode',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kOpenChannelErrorNone', index=0, number=0,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kOpenChannelErrorNoSuchChannel', index=1, number=1,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kOpenChannelErrorChannelAlreadyOpened', index=2, number=2,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kOpenChannelErrorOther', index=3, number=-1,
|
||||
options=None,
|
||||
type=None),
|
||||
],
|
||||
containing_type=None,
|
||||
options=None,
|
||||
serialized_start=780,
|
||||
serialized_end=945,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_OPENCHANNELERRORCODE)
|
||||
|
||||
OpenChannelErrorCode = enum_type_wrapper.EnumTypeWrapper(_OPENCHANNELERRORCODE)
|
||||
_CHANNELCONTENTTYPE = _descriptor.EnumDescriptor(
|
||||
name='ChannelContentType',
|
||||
full_name='ascend.presenter.proto.ChannelContentType',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kChannelContentTypeImage', index=0, number=0,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kChannelContentTypeVideo', index=1, number=1,
|
||||
options=None,
|
||||
type=None),
|
||||
],
|
||||
containing_type=None,
|
||||
options=None,
|
||||
serialized_start=947,
|
||||
serialized_end=1027,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CHANNELCONTENTTYPE)
|
||||
|
||||
ChannelContentType = enum_type_wrapper.EnumTypeWrapper(_CHANNELCONTENTTYPE)
|
||||
_IMAGEFORMAT = _descriptor.EnumDescriptor(
|
||||
name='ImageFormat',
|
||||
full_name='ascend.presenter.proto.ImageFormat',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kImageFormatJpeg', index=0, number=0,
|
||||
options=None,
|
||||
type=None),
|
||||
],
|
||||
containing_type=None,
|
||||
options=None,
|
||||
serialized_start=1029,
|
||||
serialized_end=1064,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_IMAGEFORMAT)
|
||||
|
||||
ImageFormat = enum_type_wrapper.EnumTypeWrapper(_IMAGEFORMAT)
|
||||
_PRESENTDATAERRORCODE = _descriptor.EnumDescriptor(
|
||||
name='PresentDataErrorCode',
|
||||
full_name='ascend.presenter.proto.PresentDataErrorCode',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kPresentDataErrorNone', index=0, number=0,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kPresentDataErrorUnsupportedType', index=1, number=1,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kPresentDataErrorUnsupportedFormat', index=2, number=2,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='kPresentDataErrorOther', index=3, number=-1,
|
||||
options=None,
|
||||
type=None),
|
||||
],
|
||||
containing_type=None,
|
||||
options=None,
|
||||
serialized_start=1067,
|
||||
serialized_end=1231,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_PRESENTDATAERRORCODE)
|
||||
|
||||
PresentDataErrorCode = enum_type_wrapper.EnumTypeWrapper(_PRESENTDATAERRORCODE)
|
||||
kOpenChannelErrorNone = 0
|
||||
kOpenChannelErrorNoSuchChannel = 1
|
||||
kOpenChannelErrorChannelAlreadyOpened = 2
|
||||
kOpenChannelErrorOther = -1
|
||||
kChannelContentTypeImage = 0
|
||||
kChannelContentTypeVideo = 1
|
||||
kImageFormatJpeg = 0
|
||||
kPresentDataErrorNone = 0
|
||||
kPresentDataErrorUnsupportedType = 1
|
||||
kPresentDataErrorUnsupportedFormat = 2
|
||||
kPresentDataErrorOther = -1
|
||||
|
||||
|
||||
|
||||
_OPENCHANNELREQUEST = _descriptor.Descriptor(
|
||||
name='OpenChannelRequest',
|
||||
full_name='ascend.presenter.proto.OpenChannelRequest',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='channel_name', full_name='ascend.presenter.proto.OpenChannelRequest.channel_name', index=0,
|
||||
number=1, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='content_type', full_name='ascend.presenter.proto.OpenChannelRequest.content_type', index=1,
|
||||
number=2, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=51,
|
||||
serialized_end=159,
|
||||
)
|
||||
|
||||
|
||||
_OPENCHANNELRESPONSE = _descriptor.Descriptor(
|
||||
name='OpenChannelResponse',
|
||||
full_name='ascend.presenter.proto.OpenChannelResponse',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='error_code', full_name='ascend.presenter.proto.OpenChannelResponse.error_code', index=0,
|
||||
number=1, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='error_message', full_name='ascend.presenter.proto.OpenChannelResponse.error_message', index=1,
|
||||
number=2, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=161,
|
||||
serialized_end=271,
|
||||
)
|
||||
|
||||
|
||||
_HEARTBEATMESSAGE = _descriptor.Descriptor(
|
||||
name='HeartbeatMessage',
|
||||
full_name='ascend.presenter.proto.HeartbeatMessage',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=273,
|
||||
serialized_end=291,
|
||||
)
|
||||
|
||||
|
||||
_COORDINATE = _descriptor.Descriptor(
|
||||
name='Coordinate',
|
||||
full_name='ascend.presenter.proto.Coordinate',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='x', full_name='ascend.presenter.proto.Coordinate.x', index=0,
|
||||
number=1, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='y', full_name='ascend.presenter.proto.Coordinate.y', index=1,
|
||||
number=2, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=293,
|
||||
serialized_end=327,
|
||||
)
|
||||
|
||||
|
||||
_RECTANGLE_ATTR = _descriptor.Descriptor(
|
||||
name='Rectangle_Attr',
|
||||
full_name='ascend.presenter.proto.Rectangle_Attr',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='left_top', full_name='ascend.presenter.proto.Rectangle_Attr.left_top', index=0,
|
||||
number=1, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='right_bottom', full_name='ascend.presenter.proto.Rectangle_Attr.right_bottom', index=1,
|
||||
number=2, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='label_text', full_name='ascend.presenter.proto.Rectangle_Attr.label_text', index=2,
|
||||
number=3, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=330,
|
||||
serialized_end=478,
|
||||
)
|
||||
|
||||
|
||||
_PRESENTIMAGEREQUEST = _descriptor.Descriptor(
|
||||
name='PresentImageRequest',
|
||||
full_name='ascend.presenter.proto.PresentImageRequest',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='format', full_name='ascend.presenter.proto.PresentImageRequest.format', index=0,
|
||||
number=1, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='width', full_name='ascend.presenter.proto.PresentImageRequest.width', index=1,
|
||||
number=2, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='height', full_name='ascend.presenter.proto.PresentImageRequest.height', index=2,
|
||||
number=3, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='data', full_name='ascend.presenter.proto.PresentImageRequest.data', index=3,
|
||||
number=4, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='rectangle_list', full_name='ascend.presenter.proto.PresentImageRequest.rectangle_list', index=4,
|
||||
number=5, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=481,
|
||||
serialized_end=664,
|
||||
)
|
||||
|
||||
|
||||
_PRESENTIMAGERESPONSE = _descriptor.Descriptor(
|
||||
name='PresentImageResponse',
|
||||
full_name='ascend.presenter.proto.PresentImageResponse',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='error_code', full_name='ascend.presenter.proto.PresentImageResponse.error_code', index=0,
|
||||
number=1, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='error_message', full_name='ascend.presenter.proto.PresentImageResponse.error_message', index=1,
|
||||
number=2, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=666,
|
||||
serialized_end=777,
|
||||
)
|
||||
|
||||
_OPENCHANNELREQUEST.fields_by_name['content_type'].enum_type = _CHANNELCONTENTTYPE
|
||||
_OPENCHANNELRESPONSE.fields_by_name['error_code'].enum_type = _OPENCHANNELERRORCODE
|
||||
_RECTANGLE_ATTR.fields_by_name['left_top'].message_type = _COORDINATE
|
||||
_RECTANGLE_ATTR.fields_by_name['right_bottom'].message_type = _COORDINATE
|
||||
_PRESENTIMAGEREQUEST.fields_by_name['format'].enum_type = _IMAGEFORMAT
|
||||
_PRESENTIMAGEREQUEST.fields_by_name['rectangle_list'].message_type = _RECTANGLE_ATTR
|
||||
_PRESENTIMAGERESPONSE.fields_by_name['error_code'].enum_type = _PRESENTDATAERRORCODE
|
||||
DESCRIPTOR.message_types_by_name['OpenChannelRequest'] = _OPENCHANNELREQUEST
|
||||
DESCRIPTOR.message_types_by_name['OpenChannelResponse'] = _OPENCHANNELRESPONSE
|
||||
DESCRIPTOR.message_types_by_name['HeartbeatMessage'] = _HEARTBEATMESSAGE
|
||||
DESCRIPTOR.message_types_by_name['Coordinate'] = _COORDINATE
|
||||
DESCRIPTOR.message_types_by_name['Rectangle_Attr'] = _RECTANGLE_ATTR
|
||||
DESCRIPTOR.message_types_by_name['PresentImageRequest'] = _PRESENTIMAGEREQUEST
|
||||
DESCRIPTOR.message_types_by_name['PresentImageResponse'] = _PRESENTIMAGERESPONSE
|
||||
DESCRIPTOR.enum_types_by_name['OpenChannelErrorCode'] = _OPENCHANNELERRORCODE
|
||||
DESCRIPTOR.enum_types_by_name['ChannelContentType'] = _CHANNELCONTENTTYPE
|
||||
DESCRIPTOR.enum_types_by_name['ImageFormat'] = _IMAGEFORMAT
|
||||
DESCRIPTOR.enum_types_by_name['PresentDataErrorCode'] = _PRESENTDATAERRORCODE
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
OpenChannelRequest = _reflection.GeneratedProtocolMessageType('OpenChannelRequest', (_message.Message,), dict(
|
||||
DESCRIPTOR = _OPENCHANNELREQUEST,
|
||||
__module__ = 'presenter_message_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.OpenChannelRequest)
|
||||
))
|
||||
_sym_db.RegisterMessage(OpenChannelRequest)
|
||||
|
||||
OpenChannelResponse = _reflection.GeneratedProtocolMessageType('OpenChannelResponse', (_message.Message,), dict(
|
||||
DESCRIPTOR = _OPENCHANNELRESPONSE,
|
||||
__module__ = 'presenter_message_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.OpenChannelResponse)
|
||||
))
|
||||
_sym_db.RegisterMessage(OpenChannelResponse)
|
||||
|
||||
HeartbeatMessage = _reflection.GeneratedProtocolMessageType('HeartbeatMessage', (_message.Message,), dict(
|
||||
DESCRIPTOR = _HEARTBEATMESSAGE,
|
||||
__module__ = 'presenter_message_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.HeartbeatMessage)
|
||||
))
|
||||
_sym_db.RegisterMessage(HeartbeatMessage)
|
||||
|
||||
Coordinate = _reflection.GeneratedProtocolMessageType('Coordinate', (_message.Message,), dict(
|
||||
DESCRIPTOR = _COORDINATE,
|
||||
__module__ = 'presenter_message_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.Coordinate)
|
||||
))
|
||||
_sym_db.RegisterMessage(Coordinate)
|
||||
|
||||
Rectangle_Attr = _reflection.GeneratedProtocolMessageType('Rectangle_Attr', (_message.Message,), dict(
|
||||
DESCRIPTOR = _RECTANGLE_ATTR,
|
||||
__module__ = 'presenter_message_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.Rectangle_Attr)
|
||||
))
|
||||
_sym_db.RegisterMessage(Rectangle_Attr)
|
||||
|
||||
PresentImageRequest = _reflection.GeneratedProtocolMessageType('PresentImageRequest', (_message.Message,), dict(
|
||||
DESCRIPTOR = _PRESENTIMAGEREQUEST,
|
||||
__module__ = 'presenter_message_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.PresentImageRequest)
|
||||
))
|
||||
_sym_db.RegisterMessage(PresentImageRequest)
|
||||
|
||||
PresentImageResponse = _reflection.GeneratedProtocolMessageType('PresentImageResponse', (_message.Message,), dict(
|
||||
DESCRIPTOR = _PRESENTIMAGERESPONSE,
|
||||
__module__ = 'presenter_message_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.PresentImageResponse)
|
||||
))
|
||||
_sym_db.RegisterMessage(PresentImageResponse)
|
||||
|
||||
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,463 @@
|
||||
# =======================================================================
|
||||
#
|
||||
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1 Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2 Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3 Neither the names of the copyright holders nor the names of the
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# =======================================================================
|
||||
#
|
||||
"""presenter socket server module"""
|
||||
|
||||
import threading
|
||||
import select
|
||||
import struct
|
||||
import logging
|
||||
import socket
|
||||
from google.protobuf.message import DecodeError
|
||||
import common.presenter_message_pb2 as pb2
|
||||
from common.channel_manager import ChannelManager
|
||||
from common.channel_handler import ChannelHandler
|
||||
|
||||
#read nothing from socket.recv()
|
||||
SOCK_RECV_NULL = b''
|
||||
|
||||
# epool will return if no event coming in 1 s
|
||||
EPOLL_TIMEOUT = 1
|
||||
|
||||
# it specifies the number of unaccepted connections that
|
||||
# the system will allow before refusing new connections.
|
||||
SOCKET_WAIT_QUEUE = 2
|
||||
|
||||
# message head length, include 4 bytes message total length
|
||||
# and 1 byte message name length
|
||||
MSG_HEAD_LENGTH = 5
|
||||
|
||||
|
||||
class PresenterSocketServer():
|
||||
"""a socket server communication with presenter agent.
|
||||
|
||||
"""
|
||||
def __init__(self, server_address):
|
||||
"""
|
||||
Args:
|
||||
server_address: server listen address,
|
||||
include an ipv4 address and a port.
|
||||
"""
|
||||
|
||||
# thread exit switch, if set true, thread must exit immediately.
|
||||
self.thread_exit_switch = False
|
||||
# message head length, include 4 bytes message total length
|
||||
# and 1 byte message name length
|
||||
self.msg_head_len = 5
|
||||
self._create_socket_server(server_address)
|
||||
|
||||
def _create_socket_server(self, server_address):
|
||||
"""
|
||||
create a socket server
|
||||
Args:
|
||||
server_address: server listen address,
|
||||
include an ipv4 address and a port.
|
||||
"""
|
||||
|
||||
# Create a socket server.
|
||||
self._sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self._sock_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self._sock_server.bind(server_address)
|
||||
self._sock_server.listen(SOCKET_WAIT_QUEUE)
|
||||
self._sock_server.setblocking(False)
|
||||
|
||||
# Get server host name and port
|
||||
host, port = self._sock_server.getsockname()[:2]
|
||||
|
||||
# Start presenter socket server thread.
|
||||
threading.Thread(target=self._server_listen_thread).start()
|
||||
|
||||
# Display directly on the screen
|
||||
print('Presenter socket server listen on %s:%s\n' % (host, port))
|
||||
|
||||
def set_exit_switch(self):
|
||||
"""set switch True to stop presenter socket server thread."""
|
||||
self.thread_exit_switch = True
|
||||
|
||||
def _read_socket(self, conn, read_len):
|
||||
'''
|
||||
Read fixed length data
|
||||
Args:
|
||||
conn: a socket connection
|
||||
read_len: read fix byte.
|
||||
Returns:
|
||||
ret: True or False
|
||||
buf: read fix byte buf.
|
||||
'''
|
||||
has_read_len = 0
|
||||
read_buf = SOCK_RECV_NULL
|
||||
total_buf = SOCK_RECV_NULL
|
||||
while has_read_len != read_len:
|
||||
try:
|
||||
read_buf = conn.recv(read_len - has_read_len)
|
||||
except socket.error:
|
||||
logging.error("socket %u exception:socket.error", conn.fileno())
|
||||
return False, None
|
||||
if read_buf == SOCK_RECV_NULL:
|
||||
return False, None
|
||||
total_buf += read_buf
|
||||
has_read_len = len(total_buf)
|
||||
|
||||
return True, total_buf
|
||||
|
||||
def _read_msg_head(self, sock_fileno, conns):
|
||||
'''
|
||||
Args:
|
||||
sock_fileno: a socket fileno
|
||||
conns: all socket connections which created by server.
|
||||
Returns:
|
||||
msg_total_len: total message length.
|
||||
msg_name_len: message name length.
|
||||
'''
|
||||
ret, msg_head = self._read_socket(conns[sock_fileno], self.msg_head_len)
|
||||
if not ret:
|
||||
logging.error("socket %u receive msg head null", sock_fileno)
|
||||
return None, None
|
||||
|
||||
# in Struct(), 'I' is unsigned int, 'B' is unsigned char
|
||||
msg_head_data = struct.Struct('IB')
|
||||
(msg_total_len, msg_name_len) = msg_head_data.unpack(msg_head)
|
||||
msg_total_len = socket.ntohl(msg_total_len)
|
||||
|
||||
return msg_total_len, msg_name_len
|
||||
|
||||
def _read_msg_name(self, sock_fd, conns, msg_name_len):
|
||||
'''
|
||||
Args:
|
||||
sock_fd: a socket fileno
|
||||
conns: all socket connections which created by server.
|
||||
msg_name_len: message name length.
|
||||
Returns:
|
||||
ret: True or False
|
||||
msg_name: message name.
|
||||
'''
|
||||
ret, msg_name = self._read_socket(conns[sock_fd], msg_name_len)
|
||||
if not ret:
|
||||
logging.error("socket %u receive msg name null", sock_fd)
|
||||
return False, None
|
||||
try:
|
||||
msg_name = msg_name.decode("utf-8")
|
||||
except UnicodeDecodeError:
|
||||
logging.error("msg name decode to utf-8 error")
|
||||
return False, None
|
||||
|
||||
return True, msg_name
|
||||
|
||||
def _read_msg_body(self, sock_fd, conns, msg_body_len, msgs):
|
||||
'''
|
||||
Args:
|
||||
sock_fd: a socket fileno
|
||||
conns: all socket connections which created by server.
|
||||
msg_name_len: message name length.
|
||||
msgs: msg read from a socket
|
||||
Returns:
|
||||
ret: True or False
|
||||
'''
|
||||
ret, msg_body = self._read_socket(conns[sock_fd], msg_body_len)
|
||||
if not ret:
|
||||
logging.error("socket %u receive msg body null", sock_fd)
|
||||
return False
|
||||
msgs[sock_fd] = msg_body
|
||||
return True
|
||||
|
||||
def _read_sock_and_process_msg(self, sock_fileno, conns, msgs):
|
||||
'''
|
||||
Args:
|
||||
sock_fileno: a socket fileno, return value of socket.fileno()
|
||||
conns: all socket connections registered in epoll
|
||||
msgs: msg read from a socket
|
||||
Returns:
|
||||
ret: True or False
|
||||
'''
|
||||
|
||||
# Step1: read msg head
|
||||
msg_total_len, msg_name_len = self._read_msg_head(sock_fileno, conns)
|
||||
if msg_total_len is None:
|
||||
logging.error("msg_total_len is None.")
|
||||
return False
|
||||
|
||||
# Step2: read msg name
|
||||
ret, msg_name = self._read_msg_name(sock_fileno, conns, msg_name_len)
|
||||
if not ret:
|
||||
return ret
|
||||
|
||||
# Step3: read msg body
|
||||
msg_body_len = msg_total_len - self.msg_head_len - msg_name_len
|
||||
if msg_body_len < 0:
|
||||
logging.error("msg_total_len:%u, msg_name_len:%u, msg_body_len:%u",
|
||||
msg_total_len, msg_name_len, msg_body_len)
|
||||
return False
|
||||
ret = self._read_msg_body(sock_fileno, conns, msg_body_len, msgs)
|
||||
if not ret:
|
||||
return ret
|
||||
|
||||
# Step4: process msg
|
||||
ret = self._process_msg(conns[sock_fileno], msg_name, msgs[sock_fileno])
|
||||
return ret
|
||||
|
||||
def _process_epollin(self, sock_fileno, epoll, conns, msgs):
|
||||
'''
|
||||
Args:
|
||||
sock_fileno: a socket fileno, return value of socket.fileno()
|
||||
epoll: a set of select.epoll.
|
||||
conns: all socket connections registered in epoll
|
||||
msgs: msg read from a socket
|
||||
'''
|
||||
msgs[sock_fileno] = b''
|
||||
try:
|
||||
ret = self._read_sock_and_process_msg(sock_fileno, conns, msgs)
|
||||
if not ret:
|
||||
self._clean_connect(sock_fileno, epoll, conns, msgs)
|
||||
except socket.error:
|
||||
logging.error("receive socket error.")
|
||||
self._clean_connect(sock_fileno, epoll, conns, msgs)
|
||||
|
||||
def _accept_new_socket(self, epoll, conns):
|
||||
'''
|
||||
Args:
|
||||
epoll: a set of select.epoll.
|
||||
conns: all socket connections registered in epoll
|
||||
'''
|
||||
try:
|
||||
new_conn, address = self._sock_server.accept()
|
||||
new_conn.setblocking(True)
|
||||
epoll.register(new_conn.fileno(), select.EPOLLIN | select.EPOLLHUP)
|
||||
conns[new_conn.fileno()] = new_conn
|
||||
logging.info("create new connection:client-ip:%s, client-port:%s, fd:%s",
|
||||
address[0], address[1], new_conn.fileno())
|
||||
except socket.error:
|
||||
logging.error("socket.error exception when sock.accept()")
|
||||
|
||||
def _server_listen_thread(self):
|
||||
"""socket server thread, epoll listening all the socket events"""
|
||||
epoll = select.epoll()
|
||||
epoll.register(self._sock_server.fileno(), select.EPOLLIN | select.EPOLLHUP)
|
||||
try:
|
||||
conns = {}
|
||||
msgs = {}
|
||||
while True:
|
||||
# thread must exit immediately
|
||||
if self.thread_exit_switch:
|
||||
break
|
||||
|
||||
events = epoll.poll(EPOLL_TIMEOUT)
|
||||
# timeout, but no event come, continue waiting
|
||||
if not events:
|
||||
continue
|
||||
|
||||
for sock_fileno, event in events:
|
||||
# new connection request from presenter agent
|
||||
if self._sock_server.fileno() == sock_fileno:
|
||||
self._accept_new_socket(epoll, conns)
|
||||
|
||||
# remote connection closed
|
||||
# it means presenter agent exit withot close socket.
|
||||
elif event & select.EPOLLHUP:
|
||||
logging.info("receive event EPOLLHUP")
|
||||
self._clean_connect(sock_fileno, epoll, conns, msgs)
|
||||
# new data coming in a socket connection
|
||||
elif event & select.EPOLLIN:
|
||||
self._process_epollin(sock_fileno, epoll, conns, msgs)
|
||||
# receive event not recognize
|
||||
else:
|
||||
logging.error("not recognize event %f", event)
|
||||
self._clean_connect(sock_fileno, epoll, conns, msgs)
|
||||
|
||||
finally:
|
||||
logging.info("conns:%s", conns)
|
||||
logging.info("presenter server listen thread exit.")
|
||||
epoll.unregister(self._sock_server.fileno())
|
||||
epoll.close()
|
||||
self._sock_server.close()
|
||||
|
||||
|
||||
def _process_heartbeat(self, conn):
|
||||
'''
|
||||
set heartbeat
|
||||
Args:
|
||||
conn: a socket connection
|
||||
Returns:
|
||||
True: set heartbeat ok.
|
||||
|
||||
'''
|
||||
sock_fileno = conn.fileno()
|
||||
handler = self.channel_manager.get_channel_handler_by_fd(sock_fileno)
|
||||
if handler is not None:
|
||||
handler.set_heartbeat()
|
||||
|
||||
return True
|
||||
|
||||
def _process_open_channel(self, conn, msg_data):
|
||||
"""
|
||||
Deserialization protobuf and process open_channel request
|
||||
Args:
|
||||
conn: a socket connection
|
||||
msg_data: a protobuf struct, include open channel request.
|
||||
|
||||
Returns:
|
||||
|
||||
protobuf structure like this:
|
||||
----------------------------------------------
|
||||
|channel_name | string |
|
||||
|----------------------------------------------
|
||||
|content_type | ChannelContentType |
|
||||
|----------------------------------------------
|
||||
|
||||
enum ChannelContentType {
|
||||
kChannelContentTypeImage = 0;
|
||||
kChannelContentTypeVideo = 1;
|
||||
}
|
||||
"""
|
||||
request = pb2.OpenChannelRequest()
|
||||
response = pb2.OpenChannelResponse()
|
||||
|
||||
try:
|
||||
request.ParseFromString(msg_data)
|
||||
except DecodeError:
|
||||
logging.error("ParseFromString exception: Error parsing message")
|
||||
channel_name = "unknown channel"
|
||||
return self._response_open_channel(conn, channel_name, response,
|
||||
pb2.kOpenChannelErrorOther)
|
||||
|
||||
channel_name = request.channel_name
|
||||
|
||||
# check channel name if exist
|
||||
if not self.channel_manager.is_channel_exist(channel_name):
|
||||
logging.error("channel name %s is not exist.", channel_name)
|
||||
# if channel is not exist, need to create the channel
|
||||
ret = self.channel_manager.register_one_channel(channel_name)
|
||||
if ret != ChannelManager.err_code_ok:
|
||||
logging.error("Create the channel %s failed!, and ret is %d", channel_name, ret)
|
||||
err_code = pb2.kOpenChannelErrorOther
|
||||
self._response_open_channel(conn, channel_name, response, err_code)
|
||||
|
||||
# check channel path if busy
|
||||
if self.channel_manager.is_channel_busy(channel_name):
|
||||
logging.error("channel path %s is busy.", channel_name)
|
||||
err_code = pb2.kOpenChannelErrorChannelAlreadyOpened
|
||||
return self._response_open_channel(conn, channel_name, response,
|
||||
err_code)
|
||||
|
||||
# if channel type is image, need clean image if exist
|
||||
self.channel_manager.clean_channel_image(channel_name)
|
||||
|
||||
if request.content_type == pb2.kChannelContentTypeImage:
|
||||
media_type = "image"
|
||||
elif request.content_type == pb2.kChannelContentTypeVideo:
|
||||
media_type = "video"
|
||||
else:
|
||||
logging.error("media type %s is not recognized.",
|
||||
request.content_type)
|
||||
return self._response_open_channel(conn, channel_name, response,
|
||||
pb2.kOpenChannelErrorOther)
|
||||
|
||||
handler = ChannelHandler(channel_name, media_type)
|
||||
self.channel_manager.create_channel_resource(
|
||||
channel_name, conn.fileno(), media_type, handler)
|
||||
|
||||
return self._response_open_channel(conn, channel_name, response,
|
||||
pb2.kOpenChannelErrorNone)
|
||||
|
||||
def _response_open_channel(self, conn, channel_name, response, err_code):
|
||||
"""
|
||||
Assemble protobuf to response open_channel request
|
||||
Args:
|
||||
conn: a socket connection
|
||||
channel_name: name of a channel.
|
||||
response: a protobuf response to presenter agent
|
||||
err_code: part of the response
|
||||
|
||||
Returns:
|
||||
ret_code:True or False
|
||||
|
||||
Message structure like this:
|
||||
--------------------------------------------------------------------
|
||||
|total message len | int | 4 bytes |
|
||||
|-------------------------------------------------------------------
|
||||
|message name len | byte | 1 byte |
|
||||
|-------------------------------------------------------------------
|
||||
|message name | string | xx bytes |
|
||||
|-------------------------------------------------------------------
|
||||
|message body | protobuf | xx bytes |
|
||||
--------------------------------------------------------------------
|
||||
|
||||
protobuf structure like this:
|
||||
--------------------------------------------------------------------
|
||||
|error_code | enum | OpenChannelErrorCode |
|
||||
|-------------------------------------------------------------------
|
||||
|error_message | string | xx bytes |
|
||||
|-------------------------------------------------------------------
|
||||
|
||||
enum OpenChannelErrorCode {
|
||||
kOpenChannelErrorNone = 0;
|
||||
kOpenChannelErrorNoSuchChannel = 1;
|
||||
kOpenChannelErrorChannelAlreadyOpened = 2;
|
||||
kOpenChannelErrorOther = -1;
|
||||
}
|
||||
"""
|
||||
response.error_code = err_code
|
||||
ret_code = False
|
||||
if err_code == pb2.kOpenChannelErrorNoSuchChannel:
|
||||
response.error_message = "channel {} not exist." \
|
||||
.format(channel_name)
|
||||
elif err_code == pb2.kOpenChannelErrorChannelAlreadyOpened:
|
||||
response.error_message = "channel {} is busy.".format(channel_name)
|
||||
elif err_code == pb2.kOpenChannelErrorNone:
|
||||
response.error_message = "open channel succeed"
|
||||
ret_code = True
|
||||
else:
|
||||
response.error_message = "Unknown err open channel {}." \
|
||||
.format(channel_name)
|
||||
|
||||
self.send_message(conn, response, pb2._OPENCHANNELRESPONSE.full_name)
|
||||
return ret_code
|
||||
|
||||
def send_message(self, conn, protobuf, msg_name):
|
||||
'''
|
||||
API for send message
|
||||
Args:
|
||||
conn: a socket connection.
|
||||
protobuf: message body defined in protobuf.
|
||||
msg_name: msg name.
|
||||
Returns: NA
|
||||
'''
|
||||
message_data = protobuf.SerializeToString()
|
||||
message_len = len(message_data)
|
||||
|
||||
msg_name_size = len(msg_name)
|
||||
msg_total_size = self.msg_head_len + msg_name_size + message_len
|
||||
# in Struct(), 'I' is unsigned int, 'B' is unsigned char
|
||||
s = struct.Struct('IB')
|
||||
msg_head = (socket.htonl(msg_total_size), msg_name_size)
|
||||
packed_msg_head = s.pack(*msg_head)
|
||||
msg_data = packed_msg_head + \
|
||||
bytes(msg_name, encoding="utf-8") + message_data
|
||||
conn.sendall(msg_data)
|
||||
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python3
|
||||
# =======================================================================
|
||||
#
|
||||
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1 Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2 Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3 Neither the names of the copyright holders nor the names of the
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# =======================================================================
|
||||
#
|
||||
|
||||
"""presenter server module"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import signal
|
||||
import argparse
|
||||
import logging
|
||||
|
||||
WEB_SERVER = None
|
||||
APP_SERVER = None
|
||||
RUN_SERVER = None
|
||||
SERVER_TYPE = ""
|
||||
USAGE_INFO = "python3 prensenter_server.py [-h] --app \n\t\t\t\t{body_pose}"
|
||||
|
||||
BODY_MAP = {"web_server": "body_pose.src.web",
|
||||
"app_server": "body_pose.src.body_pose_server"
|
||||
}
|
||||
|
||||
APP_CONF_MAP = {"body_pose": BODY_MAP}
|
||||
|
||||
|
||||
def arg_parse():
|
||||
'''arg_parse'''
|
||||
global WEB_SERVER
|
||||
global APP_SERVER
|
||||
global SERVER_TYPE
|
||||
|
||||
parser = argparse.ArgumentParser(usage=USAGE_INFO)
|
||||
parser.add_argument('--app', type=str, required=True,
|
||||
choices=['body_pose'],
|
||||
help="Application type corresponding to Presenter Server.")
|
||||
args = parser.parse_args()
|
||||
SERVER_TYPE = args.app
|
||||
app_conf = APP_CONF_MAP.get(SERVER_TYPE)
|
||||
|
||||
WEB_SERVER = __import__(app_conf.get("web_server"), fromlist=True)
|
||||
APP_SERVER = __import__(app_conf.get("app_server"), fromlist=True)
|
||||
|
||||
def start_app():
|
||||
global RUN_SERVER
|
||||
# start socket server for presenter agent communication
|
||||
RUN_SERVER = APP_SERVER.run()
|
||||
if RUN_SERVER is None:
|
||||
return False
|
||||
|
||||
logging.info("presenter server starting, type: %s", SERVER_TYPE)
|
||||
# start web ui
|
||||
return WEB_SERVER.start_webapp()
|
||||
|
||||
def stop_app():
|
||||
WEB_SERVER.stop_webapp()
|
||||
RUN_SERVER.stop_thread()
|
||||
|
||||
|
||||
def close_all_thread(signum, frame):
|
||||
'''close all thread of the process, and exit.'''
|
||||
logging.info("receive signal, signum:%s, frame:%s", signum, frame)
|
||||
stop_app()
|
||||
|
||||
logging.info("presenter server exit by Ctrl + c")
|
||||
|
||||
sys.exit()
|
||||
|
||||
def check_server_exist():
|
||||
pid = os.getpid()
|
||||
|
||||
cmd = "ps -ef|grep -v {}|grep -w presenter_server|grep {}" \
|
||||
.format(pid, SERVER_TYPE)
|
||||
|
||||
ret = os.system(cmd)
|
||||
|
||||
return ret
|
||||
|
||||
def main_process():
|
||||
'''Main function entrance'''
|
||||
arg_parse()
|
||||
|
||||
if check_server_exist() == 0:
|
||||
print("Presenter Server type \"%s\" already exist!" %(SERVER_TYPE))
|
||||
return True
|
||||
# process signal, when receive "Ctrl + c" signal,
|
||||
# stop all thead and exit the progress.
|
||||
signal.signal(signal.SIGINT, close_all_thread)
|
||||
signal.signal(signal.SIGTERM, close_all_thread)
|
||||
start_app()
|
||||
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
main_process()
|
||||
@@ -0,0 +1,2 @@
|
||||
tornado == 5.1.0
|
||||
protobuf == 3.11.3
|
||||
@@ -0,0 +1,267 @@
|
||||
#!/bin/bash
|
||||
app_script_path="$( cd "$(dirname ${BASH_SOURCE})" ; pwd -P )"
|
||||
app_path=$app_script_path/../
|
||||
app_name="body_pose"
|
||||
|
||||
# ************************convert CIDR to netmask****************************************
|
||||
# Description: convert CIDR to netmask
|
||||
# $1: CIDR
|
||||
# ******************************************************************************
|
||||
function cidr2mask()
|
||||
{
|
||||
# Number of args to shift, 255..255, first non-255 byte, zeroes
|
||||
set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
|
||||
[ $1 -gt 1 ] && shift $1 || shift
|
||||
echo ${1-0}.${2-0}.${3-0}.${4-0}
|
||||
}
|
||||
|
||||
function check_ip_addr()
|
||||
{
|
||||
echo "check ip $1"
|
||||
|
||||
ip_addr=$1
|
||||
ip_addr=$(echo "$ip_addr" | grep "^[0-9]\{1,3\}\.\([0-9]\{1,3\}\.\)\{2\}[0-9]\{1,3\}$")
|
||||
if [ -z "$ip_addr" ]
|
||||
then
|
||||
echo "ip_addr $ip_addr invalid"
|
||||
return 1
|
||||
fi
|
||||
|
||||
for num in `echo ${ip_addr} | sed "s/./ /g"`
|
||||
do
|
||||
if [ $num -gt 255 ] || [ $num -lt 0 ]
|
||||
then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
function check_board_ip()
|
||||
{
|
||||
#check format of remost_host ip
|
||||
board_ip=$(cat ${app_path}/body_pose.conf | grep "presenter_agent_ip" | awk -F'[ =]+' '{print $2}')
|
||||
board_ip=$(echo $board_ip | sed -e 's/\r//' | sed -e 's/\n//' | sed -e 's/ //')
|
||||
if [[ "$board_ip" = "" ]];then
|
||||
echo "please check your body_pose.conf to make sure that each parameter has a value"
|
||||
return 1
|
||||
fi
|
||||
check_ip_addr $board_ip
|
||||
if [ $? -ne 0 ];then
|
||||
echo "ERROR: invalid board_ip ip, please check your settings in configuration file"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function check_python3_lib()
|
||||
{
|
||||
echo "Check python3 libs ......"
|
||||
|
||||
tornado_obj=$(cat ${app_path}/presenterserver/requirements | grep tornado | awk -F'[ =]+' '{print $2}')
|
||||
if [ $? -ne 0 ];then
|
||||
echo "ERROR: please check your env."
|
||||
return 1
|
||||
elif [ 5.1.0 = ${tornado_obj} ];then
|
||||
tornado_obj=5.1
|
||||
fi
|
||||
|
||||
|
||||
protobuf_obj=$(cat ${app_path}/presenterserver/requirements | grep protobuf | awk -F'[ =]+' '{print $2}')
|
||||
if [ $? -ne 0 ];then
|
||||
echo "ERROR: please check your env."
|
||||
return 1
|
||||
fi
|
||||
|
||||
numpy_obj=$(cat ${app_path}/presenterserver/requirements | grep numpy | awk -F'[ =]+' '{print $2}')
|
||||
if [ $? -ne 0 ];then
|
||||
echo "ERROR: please check your env."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if tornado=$(python3 -c "import tornado;print(tornado.version)" 2>/dev/null);then
|
||||
if [ ${tornado} != ${tornado_obj} ];then
|
||||
pip3 install tornado==${tornado_obj} 2>/dev/null
|
||||
if [ $? -ne 0 ];then
|
||||
echo "ERROR: install tornado failed, please check your env."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
pip3 install tornado==${tornado_obj} 2>/dev/null
|
||||
if [ $? -ne 0 ];then
|
||||
echo "ERROR: install tornado failed, please check your env."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if protobuf=$(python3 -c "import google.protobuf;print(google.protobuf.__version__)" 2>/dev/null);then
|
||||
if [ ${protobuf} != ${protobuf_obj} ];then
|
||||
pip3 install protobuf==${protobuf_obj} 2>/dev/null
|
||||
if [ $? -ne 0 ];then
|
||||
echo "ERROR: install protobuf failed, please check your env."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
pip3 install protobuf==${protobuf_obj} 2>/dev/null
|
||||
if [ $? -ne 0 ];then
|
||||
echo "ERROR: install protobuf failed, please check your env."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if numpy=$(python3 -c "import numpy;print(numpy.__version__)" 2>/dev/null);then
|
||||
if [ ${numpy} != ${numpy_obj} ];then
|
||||
pip3 install numpy==${numpy_obj} 2>/dev/null
|
||||
if [ $? -ne 0 ];then
|
||||
echo "ERROR: install numpy failed, please check your env."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
pip3 install numpy==${numpy_obj} 2>/dev/null
|
||||
if [ $? -ne 0 ];then
|
||||
echo "ERROR: install numpy failed, please check your env."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
echo "python3 libs have benn prepared."
|
||||
}
|
||||
|
||||
function parse_presenter_view_ip()
|
||||
{
|
||||
|
||||
presenter_view_ip=$(cat ${app_path}/body_pose.conf | grep "presenter_view_ip" | awk -F'[ =]+' '{print $2}')
|
||||
presenter_view_ip=$(echo $presenter_view_ip | sed -e 's/\r//' | sed -e 's/\n//' | sed -e 's/ //')
|
||||
if [[ "presenter_view_ip" = "" ]];then
|
||||
echo "please check your body_pose.conf to make sure that each parameter has a value"
|
||||
return 1
|
||||
fi
|
||||
echo "presenter_view_ip is $presenter_view_ip"
|
||||
check_ip_addr $presenter_view_ip
|
||||
if [ $? -ne 0 ];then
|
||||
echo "ERROR: invalid presenter_view_ip ip, please check your settings in configuration file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function check_ips_in_same_segment()
|
||||
{
|
||||
ip=$1
|
||||
mask=$2
|
||||
board_ip=$3
|
||||
|
||||
OLD_IFS_IP="${IFS}"
|
||||
IFS="."
|
||||
board_ip_attr=(${board_ip})
|
||||
ip_attr=(${ip})
|
||||
mask_attr=(${mask})
|
||||
IFS=${OLD_IFS_IP}
|
||||
for i in `seq 0 3`
|
||||
do
|
||||
((calc_remote=${board_ip_attr[${i}]}&${mask_attr[${i}]}))
|
||||
((calc_ip=${ip_attr[${i}]}&${mask_attr[${i}]}))
|
||||
|
||||
if [[ calc_remote -ne calc_ip ]];then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
# ************************parse presenter_altasdk ip****************************
|
||||
# Description: parse presenter_altasdk ip right or not
|
||||
# $1: board_ip ip
|
||||
# ******************************************************************************
|
||||
|
||||
function parse_presenter_altasdk_ip()
|
||||
{
|
||||
valid_ips=""
|
||||
board_ip=$1
|
||||
for ip_info in `/sbin/ip addr | grep "inet " | awk -F ' ' '{print $2}'`
|
||||
do
|
||||
ip=`echo ${ip_info} | awk -F '/' '{print $1}'`
|
||||
cidr=`echo ${ip_info} | awk -F '/' '{print $2}'`
|
||||
|
||||
valid_ips="${valid_ips}\t${ip}\n"
|
||||
mask=`cidr2mask ${cidr}`
|
||||
if [[ ${ip}"X" == "X" ]];then
|
||||
continue
|
||||
fi
|
||||
check_ips_in_same_segment ${ip} ${mask} ${board_ip}
|
||||
if [[ $? -eq 0 ]];then
|
||||
presenter_atlasdk_ip=${ip}
|
||||
echo "Find ${presenter_atlasdk_ip} which is in the same segment with ${board_ip}."
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
if [[ ${presenter_atlasdk_ip}"X" != "X" ]];then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Can not find ip in the same segment with ${board_ip}."
|
||||
while [[ ${presenter_atlasdk_ip}"X" == "X" ]]
|
||||
do
|
||||
echo -en "Current environment valid ip list:\n${valid_ips}Please choose one which can connect to Atlas DK Developerment Board:"
|
||||
read presenter_atlasdk_ip
|
||||
if [[ ${presenter_atlasdk_ip}"X" != "X" ]];then
|
||||
check_ip_addr ${presenter_atlasdk_ip}
|
||||
if [[ $? -ne 0 ]];then
|
||||
echo "Invlid ip, please choose again..."
|
||||
presenter_atlasdk_ip=""
|
||||
else
|
||||
# using grep to detect the field, using "$?" return non-zero value if corresponding filed is not found
|
||||
ret=`/sbin/ifconfig | grep ${presenter_atlasdk_ip}`
|
||||
if [[ $? -ne 0 ]];then
|
||||
presenter_atlasdk_ip=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
function main()
|
||||
{
|
||||
stop_pid=`ps -ef | grep "presenter_server\.py" | grep "${app_name}" | awk -F ' ' '{print $2}'`
|
||||
if [[ ${stop_pid}"X" != "X" ]];then
|
||||
echo -e "\033[33mNow do presenter server configuration, kill existing presenter process: kill -9 ${stop_pid}.\033[0m"
|
||||
kill -9 ${stop_pid}
|
||||
fi
|
||||
|
||||
check_python3_lib
|
||||
if [ $? -ne 0 ];then
|
||||
return 1
|
||||
fi
|
||||
|
||||
#get and check format of remost_host ip
|
||||
check_board_ip
|
||||
if [ $? -ne 0 ];then
|
||||
return 1
|
||||
fi
|
||||
|
||||
parse_presenter_altasdk_ip ${board_ip}
|
||||
|
||||
parse_presenter_view_ip
|
||||
|
||||
# 1. copy ip value to config.config after checking ip
|
||||
echo "Use ${presenter_atlasdk_ip} to connect to Atlas DK Developerment Board..."
|
||||
sed -i "s/presenter_server_ip=[0-9.]*/presenter_server_ip=${presenter_atlasdk_ip}/g" ${app_path}/presenterserver/body_pose/config/config.conf
|
||||
|
||||
echo "Use ${presenter_view_ip} to show information in browser..."
|
||||
sed -i "s/web_server_ip=[0-9.]*/web_server_ip=${presenter_view_ip}/g" ${app_path}/presenterserver/body_pose/config/config.conf
|
||||
|
||||
echo "Finish to prepare ${app_name} presenter server ip configuration."
|
||||
|
||||
python3 ${app_path}/presenterserver/presenter_server.py --app ${app_name} &
|
||||
|
||||
return 0
|
||||
}
|
||||
main
|
||||
@@ -0,0 +1,39 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
import math
|
||||
import os, sys
|
||||
sys.path.append('../..')
|
||||
|
||||
heatmap_width = 92
|
||||
heatmap_height = 92
|
||||
|
||||
"""
|
||||
14 joints:
|
||||
0-right shoulder, 1-right elbow, 2-right wrist, 3-left shoulder, 4-left elbow, 5-left wrist,
|
||||
6-right hip, 7-right knee, 8-right ankle, 9-left hip, 10-left knee, 11-left ankle,
|
||||
12-top of the head and 13-neck
|
||||
"""
|
||||
|
||||
JOINT_LIMB = [[0, 1], [1, 2], [3, 4], [4, 5], [6, 7], [7, 8], [9, 10], [10, 11], [12, 13], [13, 0], [13, 3], [13, 6], [13, 9]]
|
||||
COLOR = [[0, 255, 255], [0, 255, 255],[0, 255, 255],[0, 255, 255],[0, 255, 0],[0, 255, 0],[0, 255, 0],[0, 255, 0], [0, 0, 255], [255, 0, 0],[255, 0, 0],[255, 0, 0], [255, 0, 0]]
|
||||
|
||||
def decode_pose(heatmaps, scale, image_original):
|
||||
|
||||
#obtain joint list from heatmap
|
||||
joint_list = [peak_index_to_coords(heatmap)*scale for heatmap in heatmaps]
|
||||
|
||||
#plot the pose on original image
|
||||
canvas = image_original
|
||||
for idx, limb in enumerate(JOINT_LIMB):
|
||||
joint_from, joint_to = joint_list[limb[0]], joint_list[limb[1]]
|
||||
canvas = cv2.line(canvas, tuple(joint_from.astype(int)), tuple(joint_to.astype(int)), color=COLOR[idx], thickness=4)
|
||||
return canvas
|
||||
|
||||
|
||||
def peak_index_to_coords(peak_index):
|
||||
'''
|
||||
@peak_index is the index of max value in flatten heatmap
|
||||
This function convert it back to the coordinates of the original heatmap
|
||||
'''
|
||||
peak_coords = np.unravel_index(int(peak_index),(heatmap_height, heatmap_width))
|
||||
return np.flip(peak_coords)
|
||||