helloyifa 31f179cb76 init
2025-05-15 14:19:56 +08:00

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