#include "bk_private/bk_init.h" #include #include #include #include "media_service.h" #include "driver/media_types.h" #include #include #include #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