You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

802 lines
26 KiB

//===----------------------------------------------------------------------===//
//
// Copyright (C) 2022 Sophgo Technologies Inc. All rights reserved.
//
// SOPHON-DEMO is licensed under the 2-Clause BSD License except for the
// third-party components.
//
//===----------------------------------------------------------------------===//
/*
* This is a wrapper header of BMruntime & BMCV, aiming to simplify user's program.
*/
#ifndef _BM_WRAPPER_HPP_
#define _BM_WRAPPER_HPP_
#include "bmruntime_interface.h"
#include "bmcv_api_ext.h"
#include "bmlib_runtime.h"
#include <sys/time.h>
#include <iostream>
#include <vector>
#include <string.h>
#ifndef BMCV_VERSION_MAJOR
#define BMCV_VERSION_MAJOR 1
#endif
/*for multi version compatible*/
#if BMCV_VERSION_MAJOR > 1
typedef bmcv_padding_attr_t bmcv_padding_atrr_t;
/**
* @name bm_image_destroy
* @brief To solve incompatible issue in a2 sdk.
* @ingroup bmcv
*
* @param [image] input bm_image
* @retval BM_SUCCESS change success.
* @retval other values change failed.
*/
static inline bm_status_t bm_image_destroy(bm_image& image){
return bm_image_destroy(&image);
}
#endif
/* Define this macro in advance to enable following APIs */
#ifdef USE_OPENCV
#include <opencv2/opencv.hpp>
/**
* @name bm_image_from_mat
* @brief Convert opencv a Mat object to a BMCV bm_image object
* @ingroup bmruntime
*
* @param [in] bm_handle the low level device handle
* @param [in] in a read-only OPENCV mat object
* @param [out] out an uninitialized BMCV bm_image object
* @retval BM_SUCCESS change success.
* @retval other values change failed.
*/
static inline bm_status_t bm_image_from_mat (bm_handle_t &bm_handle,
cv::Mat &in,
bm_image &out) {
bm_status_t ret = cv::bmcv::toBMI(in, &out, true);
if (ret != BM_SUCCESS) {
std::cout << "Error! bm_image_from_mat: " << ret << std::endl;
}
return ret;
}
/**
* @name bm_image_from_mat
* @brief Convert opencv Mat object to BMCV bm_image object
* @ingroup bmruntime
*
* @param [in] bm_handle the low level device handle
* @param [in] in a read-only OPENCV mat vector
* @param [out] out an uninitialized BMCV bm_image vector
* @retval BM_SUCCESS change success.
* @retval other values change failed.
*/
static inline bm_status_t bm_image_from_mat (bm_handle_t &bm_handle,
std::vector<cv::Mat> &in,
std::vector<bm_image> &out) {
/* sanity check */
if (in.empty()) {
std::cout << "bm_image_from_mat: input empty!!" << std::endl;
return BM_ERR_PARAM;
}
if (!out.empty()) {
out.clear();
}
/* convert mat to bm_image one by one */
for (size_t i = 0; i < in.size(); i++) {
bm_image tmp;
bm_image_from_mat (bm_handle, in[i], tmp);
out.push_back (tmp);
}
return BM_SUCCESS ;
}
#endif // USE_OPENCV
/* Define USE_FFMPEG macro in advance to enable following APIs */
#ifdef USE_FFMPEG
extern "C"{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <libavformat/avformat.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/opt.h>
#include <libavutil/pixdesc.h>
}
typedef struct{
bm_image *bmImg;
uint8_t* buf0;
uint8_t* buf1;
uint8_t* buf2;
}transcode_t;
static inline int map_bmformat_to_avformat(int bmformat)
{
int format;
switch(bmformat){
case FORMAT_YUV420P: format = AV_PIX_FMT_YUV420P; break;
case FORMAT_YUV422P: format = AV_PIX_FMT_YUV422P; break;
case FORMAT_YUV444P: format = AV_PIX_FMT_YUV444P; break;
case FORMAT_NV12: format = AV_PIX_FMT_NV12; break;
case FORMAT_NV16: format = AV_PIX_FMT_NV16; break;
case FORMAT_GRAY: format = AV_PIX_FMT_GRAY8; break;
case FORMAT_RGBP_SEPARATE: format = AV_PIX_FMT_GBRP; break;
default: printf("unsupported image format %d\n", bmformat); return -1;
}
return format;
}
static inline void bmBufferDeviceMemFree(void *opaque, uint8_t *data)
{
if(opaque == NULL){
printf("parameter error\n");
}
transcode_t *testTranscoed = (transcode_t *)opaque;
av_freep(&testTranscoed->buf0);
testTranscoed->buf0 = NULL;
int ret = 0;
ret = bm_image_destroy(*(testTranscoed->bmImg));
if(testTranscoed->bmImg){
free(testTranscoed->bmImg);
testTranscoed->bmImg =NULL;
}
if(ret != 0)
printf("bm_image destroy failed\n");
free(testTranscoed);
testTranscoed = NULL;
return ;
}
static inline void bmBufferDeviceMemFree2(void *opaque, uint8_t *data)
{
return ;
}
/**
* @name bm_image_to_avframe
* @brief Convert bmcv bm_image object to ffmpeg a avframe object
* @ingroup bmruntime
*
* @param [in] bm_handle the low level device handle
* @param [in] in a read-only BMCV bm_image object.
* @param [out] out a output avframe
just support YUV420P ,NV12 format.
* @retval BM_SUCCESS convert success.
* @retval other values convert failed.
*/
static inline bm_status_t bm_image_to_avframe(bm_handle_t &bm_handle,bm_image *in,AVFrame *out){
transcode_t *ImgOut = NULL;
ImgOut = (transcode_t *)malloc(sizeof(transcode_t));
ImgOut->bmImg = in;
bm_image_format_info_t image_info;
int idx = 0;
int plane = 0;
if(in == NULL || out == NULL){
free(ImgOut);
return BM_ERR_FAILURE;
}
if(ImgOut->bmImg->image_format == FORMAT_NV12){
plane = 2;
}
else if(ImgOut->bmImg->image_format == FORMAT_YUV420P){
plane = 3;
}
else{
free(ImgOut);
free(in);
return BM_ERR_FAILURE;
}
out->format = (AVPixelFormat)map_bmformat_to_avformat(ImgOut->bmImg->image_format);
out->height = ImgOut->bmImg->height;
out->width = ImgOut->bmImg->width;
if(ImgOut->bmImg->width > 0 && ImgOut->bmImg->height > 0
&& ImgOut->bmImg->height * ImgOut->bmImg->width <= 8192*4096) {
ImgOut->buf0 = (uint8_t*)av_malloc(ImgOut->bmImg->height * ImgOut->bmImg->width * 3 / 2);
ImgOut->buf1 = ImgOut->buf0 + (unsigned int)(ImgOut->bmImg->height * ImgOut->bmImg->width);
if(plane == 3){
ImgOut->buf2 = ImgOut->buf0 + (unsigned int)(ImgOut->bmImg->height * ImgOut->bmImg->width * 5 / 4);
}
}
out->buf[0] = av_buffer_create(ImgOut->buf0,ImgOut->bmImg->width * ImgOut->bmImg->height,
bmBufferDeviceMemFree,ImgOut,AV_BUFFER_FLAG_READONLY);
out->buf[1] = av_buffer_create(ImgOut->buf1,ImgOut->bmImg->width * ImgOut->bmImg->height / 2 /2 ,
bmBufferDeviceMemFree2,NULL,AV_BUFFER_FLAG_READONLY);
out->data[0] = ImgOut->buf0;
out->data[1] = ImgOut->buf0;
if(plane == 3){
out->buf[2] = av_buffer_create(ImgOut->buf2,ImgOut->bmImg->width * ImgOut->bmImg->height / 2 /2 ,
bmBufferDeviceMemFree2,NULL,AV_BUFFER_FLAG_READONLY);
out->data[2] = ImgOut->buf0;
}
if(plane == 3 && !out->buf[2]){
av_buffer_unref(&out->buf[0]);
av_buffer_unref(&out->buf[1]);
av_buffer_unref(&out->buf[2]);
free(ImgOut);
free(in);
return BM_ERR_FAILURE;
}
else if(plane == 2 && !out->buf[1]){
av_buffer_unref(&out->buf[0]);
av_buffer_unref(&out->buf[1]);
free(ImgOut);
free(in);
return BM_ERR_FAILURE;
}
bm_device_mem_t mem_tmp[3];
if(bm_image_get_device_mem(*(ImgOut->bmImg),mem_tmp) != BM_SUCCESS ){
free(ImgOut);
free(in);
return BM_ERR_FAILURE;
}
if(bm_image_get_format_info(ImgOut->bmImg, &image_info) != BM_SUCCESS ){
free(ImgOut);
free(in);
return BM_ERR_FAILURE;
}
for (idx=0; idx< plane; idx++) {
out->data[4+idx] = (uint8_t *)mem_tmp[idx].u.device.device_addr;
out->linesize[idx] = image_info.stride[idx];
out->linesize[4+idx] = image_info.stride[idx];
}
return BM_SUCCESS;
}
/**
* @name bm_image_from_frame
* @brief Convert ffmpeg a avframe object to a BMCV bm_image object
* @ingroup bmruntime
*
* @param [in] bm_handle the low level device handle
* @param [in] in a read-only avframe
* @param [out] out an uninitialized BMCV bm_image object.
if avframe is compressed format,you need use
bm_image_destroy function to free out parameter until you
no longer useing it.
* @retval BM_SUCCESS change success.
* @retval other values change failed.
*/
static inline bm_status_t bm_image_from_frame (bm_handle_t &bm_handle,
AVFrame &in,
bm_image &out) {
if (in.format != AV_PIX_FMT_NV12) {
std::cout << "format donot support" << std::endl;
return BM_NOT_SUPPORTED;
}
if (in.channel_layout == 101) { /* COMPRESSED NV12 FORMAT */
/* sanity check */
if ((0 == in.height) || (0 == in.width) || \
(0 == in.linesize[4]) || (0 == in.linesize[5]) || (0 == in.linesize[6]) || (0 == in.linesize[7]) || \
(0 == in.data[4]) || (0 == in.data[5]) || (0 == in.data[6]) || (0 == in.data[7])) {
std::cout << "bm_image_from_frame: get yuv failed!!" << std::endl;
return BM_ERR_PARAM;
}
bm_image cmp_bmimg;
bm_image_create (bm_handle,
in.height,
in.width,
FORMAT_COMPRESSED,
DATA_TYPE_EXT_1N_BYTE,
&cmp_bmimg);
/* calculate physical address of avframe */
bm_device_mem_t input_addr[4];
int size = in.height * in.linesize[4];
input_addr[0] = bm_mem_from_device((unsigned long long)in.data[6], size);
size = (in.height / 2) * in.linesize[5];
input_addr[1] = bm_mem_from_device((unsigned long long)in.data[4], size);
size = in.linesize[6];
input_addr[2] = bm_mem_from_device((unsigned long long)in.data[7], size);
size = in.linesize[7];
input_addr[3] = bm_mem_from_device((unsigned long long)in.data[5], size);
bm_image_attach(cmp_bmimg, input_addr);
bm_image_create (bm_handle,
in.height,
in.width,
FORMAT_YUV420P,
DATA_TYPE_EXT_1N_BYTE,
&out);
bm_image_alloc_dev_mem(out);
bmcv_rect_t crop_rect = {0, 0, in.width, in.height};
bmcv_image_vpp_convert(bm_handle, 1, cmp_bmimg, &out, &crop_rect);
bm_image_destroy(cmp_bmimg);
} else { /* UNCOMPRESSED NV12 FORMAT */
/* sanity check */
if ((0 == in.height) || (0 == in.width) || \
(0 == in.linesize[4]) || (0 == in.linesize[5]) || \
(0 == in.data[4]) || (0 == in.data[5])) {
std::cout << "bm_image_from_frame: get yuv failed!!" << std::endl;
return BM_ERR_PARAM;
}
/* create bm_image with YUV-nv12 format */
int stride[2];
stride[0] = in.linesize[4];
stride[1] = in.linesize[5];
bm_image_create (bm_handle,
in.height,
in.width,
FORMAT_NV12,
DATA_TYPE_EXT_1N_BYTE,
&out,
stride);
/* calculate physical address of yuv mat */
bm_device_mem_t input_addr[2];
int size = in.height * stride[0];
input_addr[0] = bm_mem_from_device((unsigned long long)in.data[4], size);
size = in.height * stride[1];
input_addr[1] = bm_mem_from_device((unsigned long long)in.data[5], size);
/* attach memory from mat to bm_image */
bm_image_attach(out, input_addr);
}
return BM_SUCCESS;
}
/**
* @name bm_image_from_frame
* @brief Convert ffmpeg avframe to BMCV bm_image object
* @ingroup bmruntime
*
* @param [in] bm_handle the low level device handle
* @param [in] in a read-only ffmpeg avframe vector
* @param [out] out an uninitialized BMCV bm_image vector
* @retval BM_SUCCESS change success.
* @retval other values change failed.
*/
static inline bm_status_t bm_image_from_frame (bm_handle_t &bm_handle,
std::vector<AVFrame> &in,
std::vector<bm_image> &out) {
/* sanity check */
if (in.empty()) {
std::cout << "bm_image_from_mat: input empty!!" << std::endl;
return BM_ERR_PARAM;
}
if (!out.empty()) {
out.clear();
}
/* convert avframe to bm_image one by one */
for (size_t i = 0; i < in.size(); i++) {
bm_image tmp;
bm_image_from_frame (bm_handle, in[i], tmp);
out.push_back (tmp);
}
return BM_SUCCESS;
}
#endif // USE_FFMPEG
/**
* @name bm_image_copy_buffer
* @brief Copy a malloc() buffer to BMCV bm_image object
* @ingroup bmruntime
*
* @param [in] in input buffer
* @param [in] size input buffer size which must be equal to bm_image's size
* @param [out] out an BMCV bm_image object initialized with bm_image_create()
* @retval BM_SUCCESS change success.
* @retval other values change failed.
*/
static inline bm_status_t bm_image_copy_buffer (void *in, int size, bm_image &out) {
/* sanity check */
if (NULL == in) {
std::cout << "bm_image_copy_buffer: input is NULL!!" << std::endl;
return BM_ERR_PARAM;
}
/* get bm_image size */
bm_status_t res;
int length = 0;
res = bm_image_get_byte_size (out , &length);
if (BM_SUCCESS != res) {
std::cout << "bm_image_copy_buffer: get bm_image size failed!!" << std::endl;
return res;
}
/* input buffer size must be equal to bm_image's size */
if (size != length) {
std::cout << "bm_image_copy_buffer: input size match bm_image failed!!" << std::endl;
return BM_ERR_PARAM;
}
/* copy memory from system to device */
res = bm_image_copy_host_to_device (out, &in);
if (BM_SUCCESS != res) {
std::cout << "bm_image_copy_buffer: copy data to bm_image failed!!" << std::endl;
return res;
}
return BM_SUCCESS;
}
/**
* @name bm_image_copy_buffer
* @brief Copy malloc buffers to BMCV bm_image objects
* @ingroup bmruntime
*
* @param [in] in an input buffer vector
* @param [in] size an input buffer size vector
* @param [out] out an initialized BMCV bm_image object vector
* @retval BM_SUCCESS change success.
* @retval other values change failed.
*/
static inline bm_status_t bm_image_copy_buffer (const std::vector<void *> &in,
const std::vector<int> &size,
std::vector<bm_image> &out) {
/* sanity check */
if ((in.size() != size.size()) || (in.size() != out.size())) {
std::cout << "bm_image_copy_buffer: inputs size match failed!!" << std::endl;
return BM_ERR_PARAM;
}
/* copy buffer to bm_image one by one */
for (size_t i = 0; i < in.size(); i++) {
bm_status_t res = bm_image_copy_buffer (in[i], size[i], out[i]);
if (!res) {
std::cout << "bm_image_copy_buffer: change the buffer " << " i " << "failed!!" << std::endl;
return res;
}
}
return BM_SUCCESS;
}
/**
* @name bm_image_create_batch
* @brief create bm images with continuous device memory
* @ingroup bmruntime
*
* @param [in] handle handle of low level device
* @param [in] img_h image height
* @param [in] img_w image width
* @param [in] img_format format of image: BGR or YUV
* @param [in] data_type data type of image: INT8 or FP32
* @param [out] image pointer of bm image object
* @param [in] batch_num batch size
* @param [in] stride bm_image stride
* @param [in] head_id bm_image head id
* @retval BM_SUCCESS change success.
* @retval other values change failed.
*/
static inline bm_status_t bm_image_create_batch (bm_handle_t handle,
int img_h,
int img_w,
bm_image_format_ext img_format,
bm_image_data_format_ext data_type,
bm_image *image,
int batch_num,
int *stride = NULL,
int heap_mask = -1) {
bm_status_t res;
// init images
for (int i = 0; i < batch_num; i++) {
if (stride != NULL)
bm_image_create(handle, img_h, img_w, img_format, data_type, &image[i], stride);
else
bm_image_create(handle, img_h, img_w, img_format, data_type, &image[i]);
}
// alloc continuous memory for multi-batch
if (-1 == heap_mask)
res = bm_image_alloc_contiguous_mem (batch_num, image);
else
res = bm_image_alloc_contiguous_mem_heap_mask (batch_num, image, heap_mask);
return res;
}
/**
* @name bm_image_destroy_batch
* @brief destroy bm images with continuous device memory
* @ingroup bmruntime
*
* @param [in] image pointer of bm image object
* @param [in] batch_num batch size
* @retval BM_SUCCESS change success.
* @retval other values change failed.
*/
static inline bm_status_t bm_image_destroy_batch (bm_image *image, int batch_num) {
bm_status_t res;
// free memory
res = bm_image_free_contiguous_mem (batch_num, image);
// deinit bm image
for (int i = 0; i < batch_num; i++) {
#if BMCV_VERSION_MAJOR > 1
bm_image_destroy (&image[i]);
#else
bm_image_destroy (image[i]);
#endif
}
return res;
}
/**
* @name bm_inference
* @brief a inference wrapper call supporting multi-input & multi-output
* @ingroup bmruntime
*
* @param [in] p_bmrt the pointer of contxt
* @param [in] inputs a vector of bm_images containing multi-input data
* @param [out] outputs a vector of output buffer pointers
* @param [in] input_shapes a vector of input shapes
* @param [in] net_name a string of certain neuron network name
*
* @retval true Launch success.
* @retval false Launch failed.
*/
static inline bool bm_inference (void *p_bmrt,
std::vector<bm_image*> &inputs,
std::vector<void*> &outputs,
std::vector<bm_shape_t> &input_shapes,
const char *net_name) {
/* sanity check */
if ((NULL == p_bmrt) || (NULL == net_name)) {
std::cout << "bm_inference: input error!" << std::endl;
return false;
}
if ((inputs.empty()) || (outputs.empty()) || (input_shapes.empty())) {
std::cout << "bm_inference: input error!" << std::endl;
return false;
}
if (inputs.size() != input_shapes.size()) {
std::cout << "bm_inference: input error!" << std::endl;
return false;
}
auto net_info = bmrt_get_network_info(p_bmrt, net_name);
if (NULL == net_info) {
std::cout << "ERROR: get net-info failed!" << std::endl;
return false;
}
if (inputs.size() != (size_t)net_info->input_num) {
std::cout << "ERROR: input number error!!" << std::endl;
return false;
}
if (outputs.size() != (size_t)net_info->output_num) {
std::cout << "ERROR: output number error!!" << std::endl;
return false;
}
/* initialize input tensors */
bm_tensor_t input_tensors[net_info->input_num];
bm_tensor_t output_tensors[net_info->output_num];
for (size_t i =0; i < inputs.size(); i++) {
if (NULL == inputs[i]) {
std::cout << "bm_inference: input " << i <<"NULL!" << std::endl;
return false;
}
if (DATA_TYPE_EXT_FLOAT32 == inputs[i]->data_type) {
input_tensors[i].dtype = BM_FLOAT32;
} else if (DATA_TYPE_EXT_1N_BYTE_SIGNED == inputs[i]->data_type) {
input_tensors[i].dtype = BM_INT8;
} else if (DATA_TYPE_EXT_1N_BYTE == inputs[i]->data_type) {
input_tensors[i].dtype = BM_UINT8;
} else {
std::cout << "bm_inference: input type error !" << std::endl;
return false;
}
input_tensors[i].shape = input_shapes[i];
input_tensors[i].st_mode = BM_STORE_1N;
/* attach input memory from bm_images to input tensors */
int batch_number = input_shapes[i].dims[0];
bm_image_get_contiguous_device_mem (batch_number, inputs[i], &input_tensors[i].device_mem);
}
/* do inference, unblock call */
bm_handle_t bm_handle = (bm_handle_t)bmrt_get_bm_handle (p_bmrt);
bool ret = bmrt_launch_tensor (p_bmrt, net_name, input_tensors, inputs.size(), output_tensors, outputs.size());
if (!ret) {
std::cout << "bm_inference: Failed to launch network" << net_name << "inference" << std::endl;
return false;
}
/* wait for inference done */
bm_status_t res = (bm_status_t)bm_thread_sync (bm_handle);
if (res != BM_SUCCESS) {
std::cout << "bm_inference: Failed to sync" << net_name << "inference" << std::endl;
for (size_t i =0; i < outputs.size(); i++) {
bm_free_device (bm_handle, output_tensors[i].device_mem);
}
return false;
}
/* copy device inference results to system output buffers */
for (size_t i =0; i < outputs.size(); i++) {
if (NULL == outputs[i]) {
std::cout << "bm_inference: out "<< i << "is NULL!" << std::endl;
return false;
}
size_t size_o = bmrt_tensor_bytesize(&output_tensors[i]);
bm_memcpy_d2s_partial (bm_handle, outputs[i], output_tensors[i].device_mem, size_o);
bm_free_device (bm_handle, output_tensors[i].device_mem);
}
return true;
}
/**
* @name bm_inference
* @brief a inference wrapper call supporting single-input & single-output
* @ingroup bmruntime
*
* @param [in] p_bmrt the pointer of contxt
* @param [in] input a pointer of bm_image containing input data
* @param [out] output a pointer of output buffer
* @param [in] input_shape input shape
* @param [in] net_name a string of certain neuron network name
*
* @retval true Launch success.
* @retval false Launch failed.
*/
static inline bool bm_inference (void *p_bmrt,
bm_image *input,
void *output,
bm_shape_t input_shape,
const char *net_name) {
/* sanity check */
if ((NULL == p_bmrt) || (NULL == input) || (NULL == output) || (NULL == net_name)) {
std::cout << "bm_inference: input error!" << std::endl;
return false;
}
std::vector<bm_image*> inputs;
inputs.push_back (input);
std::vector<void*> outputs;
outputs.push_back (output);
std::vector<bm_shape_t> input_shapes;
input_shapes.push_back (input_shape);
/* inference */
bool result = bm_inference (p_bmrt, inputs, outputs, input_shapes, net_name);
return result;
}
/**
* @name bm_inference
* @brief a inference wrapper call supporting single-input & multi-output
* @ingroup bmruntime
*
* @param [in] p_bmrt the pointer of contxt
* @param [in] input a pointer of bm_image containing input data
* @param [out] outputs a vector of output buffer pointers
* @param [in] input_shape input shape
* @param [in] net_name a string of certain neuron network name
*
* @retval true Launch success.
* @retval false Launch failed.
*/
static inline bool bm_inference (void *p_bmrt,
bm_image *input,
std::vector<void*> outputs,
bm_shape_t input_shape,
const char *net_name) {
/* sanity check */
if ((NULL == p_bmrt) || (NULL == input) || (NULL == net_name) || (outputs.empty())) {
std::cout << "bm_inference: input error!" << std::endl;
return false;
}
std::vector<bm_image*> inputs;
inputs.push_back (input);
std::vector<bm_shape_t> input_shapes;
input_shapes.push_back (input_shape);
/* inference */
bool result = bm_inference (p_bmrt, inputs, outputs, input_shapes, net_name);
return result;
}
/**
* @name bm_image_dumpdata
* @brief Convert BMCV bm_image memory to bin
* @ingroup bmcv
*
* @param [in] in bm_image object
* @param [out] output_name a save file name ,if not exit would build it , if exit would clear it
* @retval BM_SUCCESS change success.
* @retval other values change failed.
*/
static inline bm_status_t bm_image_dumpdata (bm_image &in ,
const char *output_name) {
/* sanity check */
if (NULL == output_name) {
std::cout << "bm_image_dumpdata: OUT file name err!!" << std::endl;
return BM_ERR_PARAM;
}
if ((0 == in.width) || (0 == in.height)) {
std::cout << "input image err!!" << std::endl;
return BM_ERR_PARAM;
}
int size = 0;
bm_status_t ret = bm_image_get_byte_size (in , &size);
if (ret != BM_SUCCESS) {
std::cout << "get image size err!!" << std::endl;
return ret;
}
unsigned char *data;
data = new unsigned char[size];
if (NULL == data) {
std::cout << "malloc memory failed!!" << std::endl;
return BM_ERR_PARAM;
}
memset (data , 0, size);
FILE *fp;
fp = fopen (output_name , "wb+");
if (NULL == fp) {
std::cout << "open file failed!!" << std::endl;
return BM_ERR_PARAM;
}
ret = bm_image_copy_device_to_host (in , (void**)&data);
if (ret != BM_SUCCESS) {
std::cout << "copy device data err!!" << std::endl;
return ret;
}
fwrite (data , size , 1 , fp);
delete (data);
fclose (fp);
return BM_SUCCESS;
}
#endif // _BM_WRAPPER_HPP_