460 lines
12 KiB
C
Executable File
460 lines
12 KiB
C
Executable File
#include "bk_private/bk_init.h"
|
|
#include <components/system.h>
|
|
#include <os/os.h>
|
|
#include <components/shell_task.h>
|
|
|
|
#include "media_service.h"
|
|
#include "driver/media_types.h"
|
|
#include <modules/jpeg_decode_sw.h>
|
|
#include <modules/tjpgd.h>
|
|
#include <driver/uvc_camera.h>
|
|
|
|
#include "camera_client.h"
|
|
#include "ilock_client.h"
|
|
|
|
#include "components/webclient.h"
|
|
#include "cJSON.h"
|
|
#if (CONFIG_SYS_CPU1) || (CONFIG_SYS_CPU0)
|
|
#include "media_app.h"
|
|
#include "media_evt.h"
|
|
#endif
|
|
|
|
#define TAG "camera_client"
|
|
|
|
#define LOGI(...) BK_LOGW(TAG, ##__VA_ARGS__)
|
|
#define LOGW(...) BK_LOGW(TAG, ##__VA_ARGS__)
|
|
#define LOGE(...) BK_LOGE(TAG, ##__VA_ARGS__)
|
|
#define LOGD(...) BK_LOGD(TAG, ##__VA_ARGS__)
|
|
|
|
static bk_uvc_config_t uvc_config_info_param = {0};
|
|
// static sw_jpeg_dec_res_t result;
|
|
static int camera_client_is_take_photo = 0;
|
|
static int uvc_connected = 0;
|
|
|
|
static camera_cb_ops_t *event_cb;
|
|
static beken2_timer_t g_take_photo_timer;
|
|
// #if (CONFIG_SYS_CPU0)
|
|
|
|
void uvc_close();
|
|
void uvc_init();
|
|
media_camera_device_t camera_device = {
|
|
.type = UVC_CAMERA,
|
|
.mode = JPEG_MODE,
|
|
.fmt = PIXEL_FMT_JPEG,
|
|
.info.fps = FPS20,
|
|
//.info.resolution.width = 800,
|
|
//.info.resolution.height = 480,
|
|
.info.resolution.width = 1280,
|
|
.info.resolution.height = 720,
|
|
};
|
|
|
|
static int take_start = 0;
|
|
static beken_queue_t take_photo_msg_que = NULL;
|
|
|
|
typedef enum
|
|
{
|
|
// 启动拍照
|
|
TAKE_PHOTO,
|
|
// 拍照完成
|
|
TAKE_PHOTO_FINISH,
|
|
// 退出
|
|
TAKE_PHOTO_EXIT,
|
|
} take_photo_msg_type;
|
|
|
|
typedef struct
|
|
{
|
|
take_photo_msg_type type;
|
|
uint8_t *photo_addr;
|
|
uint32_t photo_len;
|
|
} take_photo_msg_t;
|
|
|
|
static void media_checkout_uvc_device_info(bk_uvc_device_brief_info_t *info, uvc_state_t state)
|
|
{
|
|
|
|
LOGE("!!! uvc_state_t:%d \r\n",state);
|
|
if (state == UVC_CONNECTED)
|
|
{
|
|
uvc_connected = 1;
|
|
uint8_t format_index = 0;
|
|
uint8_t frame_num = 0;
|
|
uint8_t index = 0, i = 0;
|
|
uvc_config_info_param.vendor_id = info->vendor_id;
|
|
uvc_config_info_param.product_id = info->product_id;
|
|
LOGE("%s uvc_get_param VID:0x%x\r\n", __func__, info->vendor_id);
|
|
LOGE("%s uvc_get_param PID:0x%x\r\n", __func__, info->product_id);
|
|
|
|
format_index = info->format_index.mjpeg_format_index;
|
|
frame_num = info->all_frame.mjpeg_frame_num;
|
|
if (format_index > 0)
|
|
{
|
|
LOGI("%s uvc_get_param MJPEG format_index:%d\r\n", __func__, format_index);
|
|
for (index = 0; index < frame_num; index++)
|
|
{
|
|
LOGI("uvc_get_param MJPEG width:%d heigth:%d index:%d\r\n",
|
|
info->all_frame.mjpeg_frame[index].width,
|
|
info->all_frame.mjpeg_frame[index].height,
|
|
info->all_frame.mjpeg_frame[index].index);
|
|
for (i = 0; i < info->all_frame.mjpeg_frame[index].fps_num; i++)
|
|
{
|
|
LOGI("uvc_get_param MJPEG fps:%d\r\n", info->all_frame.mjpeg_frame[index].fps[i]);
|
|
}
|
|
|
|
if (info->all_frame.mjpeg_frame[index].width == camera_device.info.resolution.width && info->all_frame.mjpeg_frame[index].height == camera_device.info.resolution.height)
|
|
{
|
|
uvc_config_info_param.frame_index = info->all_frame.mjpeg_frame[index].index;
|
|
uvc_config_info_param.fps = info->all_frame.mjpeg_frame[index].fps[0];
|
|
uvc_config_info_param.width = camera_device.info.resolution.width;
|
|
uvc_config_info_param.height = camera_device.info.resolution.height;
|
|
}
|
|
}
|
|
}
|
|
|
|
uvc_config_info_param.format_index = format_index;
|
|
|
|
if (media_app_set_uvc_device_param(&uvc_config_info_param) != BK_OK)
|
|
{
|
|
LOGE("%s, failed\r\n, __func__");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOGI("%s, %d\r\n", __func__, state);
|
|
}
|
|
}
|
|
int count = 0;
|
|
static void media_read_frame_info_callback(frame_buffer_t *frame)
|
|
{
|
|
os_printf("##MJPEG:camera_type:%d(1:dvp 2:uvc) frame_id:%d, length:%d, frame_addr:%p \r\n", frame->type, frame->sequence,
|
|
frame->length, frame->frame);
|
|
|
|
if (count > 10)
|
|
{
|
|
if (camera_client_is_take_photo == 0)
|
|
{
|
|
// if (event_cb != NULL)
|
|
// event_cb->on_take_photo_event(frame);
|
|
camera_client_post_photo(frame->frame, frame->length);
|
|
camera_client_is_take_photo = 1;
|
|
}
|
|
}
|
|
|
|
count++;
|
|
}
|
|
|
|
void uvc_init(void)
|
|
{
|
|
bk_err_t ret;
|
|
bk_jpeg_dec_sw_init(NULL, 0);
|
|
|
|
ret = media_app_uvc_register_info_notify_cb(media_checkout_uvc_device_info);
|
|
if (ret != BK_OK)
|
|
{
|
|
os_printf("media_app_uvc_register_info_notify_cb failed\r\n");
|
|
}
|
|
|
|
ret = media_app_camera_open(&camera_device);
|
|
if (ret != BK_OK)
|
|
{
|
|
os_printf("media_app_camera_open failed\r\n");
|
|
}
|
|
|
|
ret = media_app_register_read_frame_callback(camera_device.fmt, media_read_frame_info_callback);
|
|
if (ret != BK_OK)
|
|
{
|
|
os_printf("media_app_register_read_frame_callback failed\r\n");
|
|
}
|
|
}
|
|
|
|
void uvc_close(void)
|
|
{
|
|
bk_jpeg_dec_sw_deinit();
|
|
bk_err_t ret;
|
|
ret = media_app_unregister_read_frame_callback();
|
|
if (ret != BK_OK)
|
|
{
|
|
LOGE("%s unregister read_frame_cb failed\n", __func__);
|
|
}
|
|
ret = media_app_camera_close(camera_device.type);
|
|
if (ret != BK_OK)
|
|
{
|
|
LOGE("%s media_app_camera_close failed\n", __func__);
|
|
}
|
|
LOGE("%s media_app_camera_close success!!\n", __func__);
|
|
}
|
|
|
|
void camera_client_set_cb(camera_cb_ops_t *cb_ops)
|
|
{
|
|
if (cb_ops == NULL)
|
|
return;
|
|
event_cb = cb_ops;
|
|
}
|
|
|
|
#define BOUNDARY "RTTHREAD_FORM_DATA_BOUNDARY"
|
|
// #define HOST "http://your.server.com/upload"
|
|
|
|
/* 构建multipart请求体 */
|
|
static int build_multipart_data(char **body, int *content_length,
|
|
uint8_t *data, int data_len, char *field_name)
|
|
{
|
|
|
|
// char * filepath = "/data/a.jpg";
|
|
/* 计算各部分长度 */
|
|
char *header_fmt =
|
|
"--" BOUNDARY "\r\n"
|
|
"Content-Disposition: form-data; name=\"file\"; filename=\"a.jpg\"\r\n"
|
|
"Content-Type: image/jpeg\r\n\r\n";
|
|
|
|
char *footer = "\r\n--" BOUNDARY "--\r\n";
|
|
|
|
// int header_len = strlen(header_fmt) + strlen(field_name) + strlen(filepath);
|
|
int header_len = strlen(header_fmt);
|
|
int total_len = header_len + data_len + strlen(footer);
|
|
|
|
/* 分配内存并拼接数据 */
|
|
*body = psram_malloc(total_len + 1);
|
|
char *ptr = *body;
|
|
memset(ptr, 0, total_len);
|
|
|
|
ptr += sprintf(ptr, header_fmt);
|
|
|
|
BK_LOGE(TAG, "%s\n", ptr);
|
|
memcpy(ptr, data, data_len);
|
|
ptr += data_len;
|
|
sprintf(ptr, "%s", footer);
|
|
BK_LOGE(TAG, "%s\n", footer);
|
|
*content_length = total_len;
|
|
LOGE("%s data_len:%d\n", __func__, data_len);
|
|
return 0;
|
|
}
|
|
|
|
// static uint8_t *photo_addr;
|
|
// static int photo_len;
|
|
// static beken_thread_t upload_thread_hdl = NULL;
|
|
static beken_thread_t take_photo_thread_hdl = NULL;
|
|
static void send_photo_task(uint8_t *photo_addr, int photo_len)
|
|
{
|
|
if (photo_addr == NULL)
|
|
return;
|
|
BK_LOGE(TAG, "send_photo_task 111.\n");
|
|
// rtos_delay_milliseconds(1000);
|
|
unsigned char *buffer = NULL;
|
|
// int ret = 0;
|
|
char rep_data[2 * 1024] = {0};
|
|
int bytes_read, resp_status;
|
|
int RCV_BUF_SIZE = 1024 * 2;
|
|
buffer = (unsigned char *)psram_malloc(RCV_BUF_SIZE);
|
|
if (buffer == NULL)
|
|
{
|
|
BK_LOGE(TAG, "no memory for receive response buffer.\n");
|
|
}
|
|
BK_LOGE(TAG, "send_photo_task 222.\n");
|
|
struct webclient_session *session = NULL;
|
|
/* create webclient session and set header response size */
|
|
session = webclient_session_create(10 * 1024);
|
|
if (session == NULL)
|
|
{
|
|
BK_LOGE(TAG, "webclient_session_create failed\r\n");
|
|
}
|
|
BK_LOGE(TAG, "send_photo_task 333.\n");
|
|
char *post_data = NULL;
|
|
int content_length = 0;
|
|
if (build_multipart_data(&post_data, &content_length, photo_addr, photo_len, "file") != 0)
|
|
{
|
|
BK_LOGE(TAG, "Build multipart data failed!\n");
|
|
return;
|
|
}
|
|
BK_LOGE(TAG, "send_photo_task 444.\n");
|
|
webclient_header_fields_add(session, "Accept: */*\r\n");
|
|
webclient_header_fields_add(session, "User-Agent: Apifox/1.0.0 (https://apifox.com)\r\n");
|
|
webclient_header_fields_add(session, "Connection: keep-alive\r\n");
|
|
webclient_header_fields_add(session, "Content-Length: %d\r\n", content_length);
|
|
webclient_header_fields_add(session, "Content-Type: multipart/form-data; boundary=" BOUNDARY "\r\n");
|
|
|
|
/* send POST request by default header */
|
|
if ((resp_status = webclient_post(session, CAMERA_CLIENT_UPLOAD_PHOTO_URL, post_data, content_length)) != 200)
|
|
{
|
|
BK_LOGE(TAG, "webclient POST request failed, response(%d) error.\n", resp_status);
|
|
}
|
|
|
|
BK_LOGE(TAG, "webclient post response data: \n");
|
|
do
|
|
{
|
|
bytes_read = webclient_read(session, buffer, RCV_BUF_SIZE);
|
|
if (bytes_read <= 0)
|
|
{
|
|
break;
|
|
}
|
|
strncat(rep_data, (char *)buffer, bytes_read);
|
|
|
|
} while (1);
|
|
BK_LOGE(TAG, "rep_data %s.\n", rep_data);
|
|
// 解析
|
|
cJSON *json_resp = cJSON_Parse(rep_data);
|
|
if (json_resp)
|
|
{
|
|
cJSON *error_code = cJSON_GetObjectItem(json_resp, "error_code");
|
|
BK_LOGE(TAG, "error_code: %d \n", error_code->valueint);
|
|
if (error_code != NULL && error_code->valueint == 200)
|
|
{
|
|
cJSON *result = cJSON_GetObjectItem(json_resp, "result");
|
|
BK_LOGE(TAG, "error_code: %d \n", error_code->valueint);
|
|
BK_LOGE(TAG, "result: %s \n", result->valuestring);
|
|
if (event_cb != NULL)
|
|
event_cb->on_take_photo_event(result->valuestring, 0);
|
|
}
|
|
|
|
cJSON_Delete(json_resp);
|
|
}
|
|
|
|
if (photo_addr != NULL)
|
|
{
|
|
psram_free(photo_addr);
|
|
}
|
|
if (buffer != NULL)
|
|
{
|
|
psram_free(buffer);
|
|
}
|
|
if (post_data != NULL)
|
|
{
|
|
psram_free(post_data);
|
|
}
|
|
if (session != NULL)
|
|
{
|
|
webclient_close(session);
|
|
}
|
|
BK_LOGE(TAG, "send_photo_task finish.\n");
|
|
// 退出
|
|
take_photo_msg_t msg;
|
|
msg.type = TAKE_PHOTO_EXIT;
|
|
if (take_photo_msg_que)
|
|
{
|
|
rtos_push_to_queue(&take_photo_msg_que, &msg, BEKEN_NO_WAIT);
|
|
}
|
|
}
|
|
|
|
void camera_client_post_photo(uint8_t *mjpeg_data, int data_len)
|
|
{
|
|
|
|
BK_LOGE(TAG, "------webclient_post_photo ----len:%d\r\n", data_len);
|
|
|
|
take_photo_msg_t msg;
|
|
|
|
msg.photo_len = data_len;
|
|
msg.photo_addr = psram_malloc(data_len);
|
|
if (msg.photo_addr == NULL)
|
|
{
|
|
BK_LOGE(TAG, "post_photo malloc ram failed\r\n");
|
|
return;
|
|
}
|
|
memcpy(msg.photo_addr, mjpeg_data, data_len);
|
|
msg.type = TAKE_PHOTO_FINISH;
|
|
if (take_photo_msg_que)
|
|
{
|
|
rtos_push_to_queue(&take_photo_msg_que, &msg, BEKEN_NO_WAIT);
|
|
}
|
|
}
|
|
|
|
// 拍照超时
|
|
void camera_client_take_photo_timeout_callback()
|
|
{
|
|
LOGI("take_photo_timeout!!\n");
|
|
uvc_close();
|
|
}
|
|
|
|
static void take_photo_task(void *arg)
|
|
{
|
|
bk_err_t ret = BK_OK;
|
|
while (take_start)
|
|
{
|
|
take_photo_msg_t msg;
|
|
ret = rtos_pop_from_queue(&take_photo_msg_que, &msg, BEKEN_WAIT_FOREVER);
|
|
if (kNoErr == ret)
|
|
{
|
|
switch (msg.type)
|
|
{
|
|
// 收到启动拍照消息
|
|
case TAKE_PHOTO:
|
|
//rtos_delay_milliseconds(5000);
|
|
// 启动10s 超时定时器
|
|
if (g_take_photo_timer.handle == NULL)
|
|
{
|
|
bk_err_t result;
|
|
result = rtos_init_oneshot_timer(&g_take_photo_timer, 8 * 1024, camera_client_take_photo_timeout_callback, NULL, NULL);
|
|
if (kNoErr == result)
|
|
{
|
|
result = rtos_start_oneshot_timer(&g_take_photo_timer);
|
|
}
|
|
}
|
|
// 启动拍照
|
|
uvc_init();
|
|
// 复位USB相机
|
|
ilock_close_camera();
|
|
ilock_close_camera();
|
|
rtos_delay_milliseconds(100);
|
|
ilock_open_camera();
|
|
ilock_open_camera();
|
|
|
|
break;
|
|
case TAKE_PHOTO_FINISH:
|
|
// 关闭超时定时
|
|
rtos_stop_oneshot_timer(&g_take_photo_timer);
|
|
// 关闭相机
|
|
uvc_close();
|
|
// 启动上传
|
|
send_photo_task(msg.photo_addr, msg.photo_len);
|
|
break;
|
|
case TAKE_PHOTO_EXIT:
|
|
|
|
take_start = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* delete msg queue */
|
|
ret = rtos_deinit_queue(&take_photo_msg_que);
|
|
if (ret != kNoErr)
|
|
{
|
|
LOGE("delete take_photo_msg_que fail\n");
|
|
}
|
|
take_photo_msg_que = NULL;
|
|
/* delete task */
|
|
take_photo_thread_hdl = NULL;
|
|
LOGI("delete take_photo_thread task\n");
|
|
|
|
rtos_delete_thread(NULL);
|
|
ilock_close_camera();
|
|
}
|
|
|
|
void camera_client_take_photo()
|
|
{
|
|
count = 0;
|
|
camera_client_is_take_photo = 0;
|
|
take_start = 1;
|
|
bk_err_t ret = BK_OK;
|
|
ret = rtos_init_queue(&take_photo_msg_que, "take_photo_msg_que", sizeof(take_photo_msg_t), 2);
|
|
if (ret != kNoErr)
|
|
{
|
|
LOGE("create take_photo_msg queue fail\n");
|
|
}
|
|
ret = rtos_create_thread(&take_photo_thread_hdl,
|
|
9,
|
|
"take_photo",
|
|
(beken_thread_function_t)take_photo_task,
|
|
20 * 1024,
|
|
NULL);
|
|
if (ret != kNoErr)
|
|
{
|
|
take_photo_thread_hdl = NULL;
|
|
}
|
|
rtos_delay_milliseconds(20);
|
|
// 拍照
|
|
take_photo_msg_t msg;
|
|
msg.type = TAKE_PHOTO;
|
|
if (take_photo_msg_que)
|
|
{
|
|
rtos_push_to_queue(&take_photo_msg_que, &msg, BEKEN_NO_WAIT);
|
|
}
|
|
}
|
|
|
|
// #endif
|