// Copyright 2019 Fuzhou Rockchip Electronics Co., Ltd. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "media_config.h" #include #include #include "encoder.h" #include "key_string.h" #include "media_type.h" #include "utils.h" namespace easymedia { const char* rc_quality_strings[7] = {KEY_LOWEST, KEY_LOWER, KEY_LOW, KEY_MEDIUM, KEY_HIGH, KEY_HIGHER, KEY_HIGHEST}; const char* rc_mode_strings[3] = {KEY_VBR, KEY_CBR, KEY_FIXQP}; static const char* convert2constchar(const std::string& s, const char* array[], size_t array_len) { for (size_t i = 0; i < array_len; i++) if (!strcasecmp(s.c_str(), array[i])) { return array[i]; } return nullptr; } const char* ConvertRcQuality(const std::string& s) { return convert2constchar(s, rc_quality_strings, ARRAY_ELEMS(rc_quality_strings)); } const char* ConvertRcMode(const std::string& s) { return convert2constchar(s, rc_mode_strings, ARRAY_ELEMS(rc_mode_strings)); } static int ParseMediaConfigFps(std::map& params, VideoConfig& vid_cfg) { std::string value = params[KEY_FPS]; char* num = NULL; char* den = NULL; if (value.empty()) { LOG("ERROR: MediaCfg: fps: KEY_FPS is null!\n"); return -1; } num = strtok((char*)value.c_str(), "/"); den = strtok(NULL, "/"); if (!num || !den || (strlen(num) > 2) || (strlen(den) > 2)) { LOG("ERROR: MediaCfg: fps: KEY_FPS=%s is invalid!\n", value.c_str()); return -1; } vid_cfg.frame_rate = std::atoi(num); vid_cfg.frame_rate_den = std::atoi(den); value = params[KEY_FPS_IN]; if (value.empty()) { LOG("ERROR: MediaCfg: fps: KEY_FPS_IN is null!\n"); return -1; } num = strtok((char*)value.c_str(), "/"); den = strtok(NULL, "/"); if (!num || !den || (strlen(num) > 2) || (strlen(den) > 2)) { LOG("ERROR: MediaCfg: fps: KEY_FPS_IN(%s) is null!\n", value.c_str()); return -1; } vid_cfg.frame_in_rate = std::atoi(num); vid_cfg.frame_in_rate_den = std::atoi(den); return 0; } bool ParseMediaConfigFromMap(std::map& params, MediaConfig& mc) { std::string value = params[KEY_OUTPUTDATATYPE]; if (value.empty()) { LOG("miss %s\n", KEY_OUTPUTDATATYPE); return false; } bool image_in = string_start_withs(value, IMAGE_PREFIX); bool video_in = string_start_withs(value, VIDEO_PREFIX); bool audio_in = string_start_withs(value, AUDIO_PREFIX); if (!image_in && !video_in && !audio_in) { LOG("unsupport outtype %s\n", value.c_str()); return false; } ImageInfo info; CodecType codec_type = StringToCodecType(value.c_str()); if (codec_type == CODEC_TYPE_NONE) { LOG("ERROR: unsupport outtype %s\n", value.c_str()); return false; } if (image_in || video_in) { if (!ParseImageInfoFromMap(params, info)) { return false; } } else { // audio AudioConfig& aud_cfg = mc.aud_cfg; if (!ParseSampleInfoFromMap(params, aud_cfg.sample_info)) { return false; } CHECK_EMPTY(value, params, KEY_COMPRESS_BITRATE) aud_cfg.bit_rate = std::stoi(value); CHECK_EMPTY(value, params, KEY_FLOAT_QUALITY) aud_cfg.quality = std::stof(value); // CHECK_EMPTY(value, params, KEY_CODECTYPE) aud_cfg.codec_type = codec_type; mc.type = Type::Audio; return true; } if (image_in) { ImageConfig& img_cfg = mc.img_cfg; img_cfg.image_info = info; GET_STRING_TO_INT(img_cfg.qfactor, params, KEY_JPEG_QFACTOR, 0) img_cfg.codec_type = codec_type; mc.type = Type::Image; } else if (video_in) { VideoConfig& vid_cfg = mc.vid_cfg; ImageConfig& img_cfg = vid_cfg.image_cfg; img_cfg.image_info = info; img_cfg.codec_type = codec_type; GET_STRING_TO_INT(img_cfg.qfactor, params, KEY_JPEG_QFACTOR, 0) GET_STRING_TO_INT(vid_cfg.qp_init, params, KEY_COMPRESS_QP_INIT, 0) GET_STRING_TO_INT(vid_cfg.qp_step, params, KEY_COMPRESS_QP_STEP, 0) GET_STRING_TO_INT(vid_cfg.qp_min, params, KEY_COMPRESS_QP_MIN, 0) GET_STRING_TO_INT(vid_cfg.qp_max, params, KEY_COMPRESS_QP_MAX, 0) GET_STRING_TO_INT(vid_cfg.bit_rate, params, KEY_COMPRESS_BITRATE, 0) GET_STRING_TO_INT(vid_cfg.bit_rate_min, params, KEY_COMPRESS_BITRATE_MIN, 0) GET_STRING_TO_INT(vid_cfg.bit_rate_max, params, KEY_COMPRESS_BITRATE_MAX, 0) GET_STRING_TO_INT(vid_cfg.qp_max_i, params, KEY_COMPRESS_QP_MAX_I, 0) GET_STRING_TO_INT(vid_cfg.qp_min_i, params, KEY_COMPRESS_QP_MIN_I, 0) GET_STRING_TO_INT(vid_cfg.trans_8x8, params, KEY_H264_TRANS_8x8, 0) GET_STRING_TO_INT(vid_cfg.level, params, KEY_LEVEL, 0) GET_STRING_TO_INT(vid_cfg.gop_size, params, KEY_VIDEO_GOP, 0) GET_STRING_TO_INT(vid_cfg.profile, params, KEY_PROFILE, 0) GET_STRING_TO_INT(vid_cfg.full_range, params, KEY_FULL_RANGE, 0) GET_STRING_TO_INT(vid_cfg.ref_frm_cfg, params, KEY_REF_FRM_CFG, 0) GET_STRING_TO_INT(vid_cfg.rotation, params, KEY_ROTATION, 0) if (ParseMediaConfigFps(params, vid_cfg) < 0) { return false; } const std::string rc_q = params[KEY_COMPRESS_RC_QUALITY]; if (rc_q.empty()) { vid_cfg.rc_quality = NULL; } else { vid_cfg.rc_quality = ConvertRcQuality(rc_q); } const std::string rc_m = params[KEY_COMPRESS_RC_MODE]; if (rc_m.empty()) { vid_cfg.rc_mode = NULL; } else { vid_cfg.rc_mode = ConvertRcMode(rc_m); } mc.type = Type::Video; } return true; } // roi_regions:(x,x,x,x,x,x,x,x,x)(x,x,x,x,x,x,x,x,x)... std::vector StringToRoiRegions(const std::string& str_regions) { std::vector ret; const char* start = nullptr; if (str_regions.empty()) { return std::move(ret); } start = str_regions.c_str(); while (start) { EncROIRegion region = {0, 0, 0, 0, 0, 0, 0, 0, 0}; start = strstr(start, "("); if (!start) { break; } const char* end = strstr(start, ")"); if (!end) { LOG("ERROR: RoiRegions string is invalid! end error! Value:%s\n", str_regions.c_str()); break; } int commas_cnt = 0; const char* commas_str = start; while (commas_str && (commas_str < end)) { commas_str = strstr(commas_str, ","); if (!commas_str) { break; } else if (commas_str < end) { commas_cnt++; } commas_str++; } if (commas_cnt != 8) { LOG("ERROR: RoiRegions string is invalid! Value:%s\n", str_regions.c_str()); break; } int x, y, w, h, intra, quality, qp_area_idx, area_map_en, abs_qp_en; int r = sscanf(start, "(%d,%d,%d,%d,%d,%d,%d,%d,%d)", &x, &y, &w, &h, &intra, &quality, &qp_area_idx, &area_map_en, &abs_qp_en); if (r != 9) { LOG("ERROR: Fail to sscanf(ret=%d) : %m\n", r); ret.clear(); return std::move(ret); } region.x = (uint16_t)x; region.y = (uint16_t)y; region.w = (uint16_t)w; region.h = (uint16_t)h; region.intra = (uint16_t)intra; region.quality = (int16_t)quality; region.qp_area_idx = (uint16_t)qp_area_idx; region.area_map_en = (uint8_t)area_map_en; region.abs_qp_en = (uint8_t)abs_qp_en; ret.push_back(std::move(region)); start = end; } return std::move(ret); } std::string to_param_string(const ImageConfig& img_cfg) { std::string ret = to_param_string(img_cfg.image_info); PARAM_STRING_APPEND_TO(ret, KEY_JPEG_QFACTOR, img_cfg.qfactor); PARAM_STRING_APPEND_TO(ret, KEY_CODECTYPE, img_cfg.codec_type); return ret; } std::string to_param_string(const VideoConfig& vid_cfg) { const ImageConfig& img_cfg = vid_cfg.image_cfg; std::string ret = to_param_string(img_cfg); PARAM_STRING_APPEND_TO(ret, KEY_COMPRESS_QP_INIT, vid_cfg.qp_init); PARAM_STRING_APPEND_TO(ret, KEY_COMPRESS_QP_STEP, vid_cfg.qp_step); PARAM_STRING_APPEND_TO(ret, KEY_COMPRESS_QP_MIN, vid_cfg.qp_min); PARAM_STRING_APPEND_TO(ret, KEY_COMPRESS_QP_MAX, vid_cfg.qp_max); PARAM_STRING_APPEND_TO(ret, KEY_COMPRESS_BITRATE, vid_cfg.bit_rate); PARAM_STRING_APPEND_TO(ret, KEY_COMPRESS_BITRATE_MAX, vid_cfg.bit_rate_max); PARAM_STRING_APPEND_TO(ret, KEY_COMPRESS_BITRATE_MIN, vid_cfg.bit_rate_min); std::stringstream str_stream; std::string fps; str_stream << vid_cfg.frame_rate; str_stream << "/"; str_stream << vid_cfg.frame_rate_den; str_stream >> fps; PARAM_STRING_APPEND(ret, KEY_FPS, fps); str_stream.clear(); str_stream << vid_cfg.frame_in_rate; str_stream << "/"; str_stream << vid_cfg.frame_in_rate_den; str_stream >> fps; PARAM_STRING_APPEND(ret, KEY_FPS_IN, fps); PARAM_STRING_APPEND_TO(ret, KEY_LEVEL, vid_cfg.level); PARAM_STRING_APPEND_TO(ret, KEY_VIDEO_GOP, vid_cfg.gop_size); PARAM_STRING_APPEND_TO(ret, KEY_PROFILE, vid_cfg.profile); if (vid_cfg.rc_quality) { PARAM_STRING_APPEND(ret, KEY_COMPRESS_RC_QUALITY, vid_cfg.rc_quality); } if (vid_cfg.rc_mode) { PARAM_STRING_APPEND(ret, KEY_COMPRESS_RC_MODE, vid_cfg.rc_mode); } PARAM_STRING_APPEND_TO(ret, KEY_COMPRESS_QP_MAX_I, vid_cfg.qp_max_i); PARAM_STRING_APPEND_TO(ret, KEY_COMPRESS_QP_MIN_I, vid_cfg.qp_min_i); PARAM_STRING_APPEND_TO(ret, KEY_H264_TRANS_8x8, vid_cfg.trans_8x8); PARAM_STRING_APPEND_TO(ret, KEY_FULL_RANGE, vid_cfg.full_range); PARAM_STRING_APPEND_TO(ret, KEY_REF_FRM_CFG, vid_cfg.ref_frm_cfg); PARAM_STRING_APPEND_TO(ret, KEY_ROTATION, vid_cfg.rotation); return ret; } std::string to_param_string(const AudioConfig& aud_cfg) { std::string ret = to_param_string(aud_cfg.sample_info); PARAM_STRING_APPEND_TO(ret, KEY_COMPRESS_BITRATE, aud_cfg.bit_rate); PARAM_STRING_APPEND_TO(ret, KEY_FLOAT_QUALITY, aud_cfg.quality); PARAM_STRING_APPEND_TO(ret, KEY_CODECTYPE, aud_cfg.codec_type); return ret; } std::string to_param_string(const MediaConfig& mc, const std::string& out_type) { std::string ret; MediaConfig mc_temp = mc; bool image_in = string_start_withs(out_type, IMAGE_PREFIX); bool video_in = string_start_withs(out_type, VIDEO_PREFIX); bool audio_in = string_start_withs(out_type, AUDIO_PREFIX); if (!image_in && !video_in && !audio_in) { LOG("unsupport outtype %s\n", out_type.c_str()); return ret; } PARAM_STRING_APPEND(ret, KEY_OUTPUTDATATYPE, out_type); if (image_in) { mc_temp.img_cfg.codec_type = StringToCodecType(out_type.c_str()); ret.append(to_param_string(mc_temp.img_cfg)); } if (video_in) { mc_temp.vid_cfg.image_cfg.codec_type = StringToCodecType(out_type.c_str()); ret.append(to_param_string(mc_temp.vid_cfg)); } if (audio_in) { mc_temp.aud_cfg.codec_type = StringToCodecType(out_type.c_str()); ret.append(to_param_string(mc_temp.aud_cfg)); } return ret; } std::string get_video_encoder_config_string(const ImageInfo& info, const VideoEncoderCfg& cfg) { if (!info.width || !info.height || (info.pix_fmt >= PIX_FMT_NB) || (info.pix_fmt <= PIX_FMT_NONE)) { LOG("ERROR: %s image info is wrong!\n", __func__); return NULL; } if (StringToCodecType(cfg.type) < 0) { LOG("ERROR: %s not support enc type:%s!\n", __func__, cfg.type); return NULL; } if (cfg.rc_quality && strcmp(cfg.rc_quality, KEY_HIGHEST) && strcmp(cfg.rc_quality, KEY_HIGHER) && strcmp(cfg.rc_quality, KEY_HIGH) && strcmp(cfg.rc_quality, KEY_MEDIUM) && strcmp(cfg.rc_quality, KEY_LOW) && strcmp(cfg.rc_quality, KEY_LOWER) && strcmp(cfg.rc_quality, KEY_LOWEST)) { LOG("ERROR: %s rc_quality is invalid!" "should be [KEY_LOWEST, KEY_HIGHEST]\n", __func__); return NULL; } if (cfg.rc_mode && strcmp(cfg.rc_mode, KEY_VBR) && strcmp(cfg.rc_mode, KEY_CBR)) { LOG("ERROR: %s rc_mode is invalid! should be KEY_VBR/KEY_VBR\n", __func__); return NULL; } MediaConfig enc_config; memset(&enc_config, 0, sizeof(enc_config)); VideoConfig& vid_cfg = enc_config.vid_cfg; ImageConfig& img_cfg = vid_cfg.image_cfg; img_cfg.image_info.pix_fmt = info.pix_fmt; img_cfg.image_info.width = info.width; img_cfg.image_info.height = info.height; img_cfg.image_info.vir_width = info.vir_width; img_cfg.image_info.vir_height = info.vir_height; img_cfg.codec_type = StringToCodecType(cfg.type); if (cfg.fps) { vid_cfg.frame_rate = vid_cfg.frame_in_rate = cfg.fps; } else { vid_cfg.frame_rate = vid_cfg.frame_in_rate = 30; LOG("INFO: VideoEnc: frame rate use defalut value:30\n"); } vid_cfg.gop_size = cfg.gop; if (cfg.max_bps) { vid_cfg.bit_rate_max = cfg.max_bps; } else { int den, num; GetPixFmtNumDen(info.pix_fmt, num, den); int wh_product = info.width * info.height; if (wh_product > 2073600) { vid_cfg.bit_rate_max = wh_product * vid_cfg.frame_rate * num / den / 20; } else if (wh_product > 921600) { vid_cfg.bit_rate_max = wh_product * vid_cfg.frame_rate * num / den / 17; } else if (wh_product > 101376) { vid_cfg.bit_rate_max = wh_product * vid_cfg.frame_rate * num / den / 15; } else { vid_cfg.bit_rate_max = wh_product * vid_cfg.frame_rate * num / den / 8; } LOG("INFO: VideoEnc: maxbps use defalut value:%d\n", vid_cfg.bit_rate); } vid_cfg.rc_quality = cfg.rc_quality; vid_cfg.rc_mode = cfg.rc_mode; std::string enc_param = ""; enc_param.append(easymedia::to_param_string(enc_config, cfg.type)); return enc_param; } int video_encoder_set_bps(std::shared_ptr& enc_flow, unsigned int target, unsigned int min, unsigned int max) { if (!enc_flow) { return -EINVAL; } auto pbuff = std::make_shared(0); int* bps_array = (int*)malloc(3 * sizeof(int)); bps_array[0] = min; bps_array[1] = target; bps_array[2] = max; pbuff->SetPtr(bps_array, 3 * sizeof(int)); enc_flow->Control(VideoEncoder::kBitRateChange, pbuff); return 0; } int video_encoder_set_rc_quality(std::shared_ptr& enc_flow, const char* rc_quality) { if (!enc_flow || !rc_quality) { return -EINVAL; } if (strcmp(rc_quality, KEY_HIGHEST) && strcmp(rc_quality, KEY_HIGHER) && strcmp(rc_quality, KEY_HIGH) && strcmp(rc_quality, KEY_MEDIUM) && strcmp(rc_quality, KEY_LOW) && strcmp(rc_quality, KEY_LOWER) && strcmp(rc_quality, KEY_LOWEST)) { LOG("ERROR: %s rc_quality:%s is invalid! " "should be [KEY_LOWEST, KEY_HIGHEST]\n", __func__, rc_quality); return -EINVAL; } auto pbuff = std::make_shared(0); int str_len = strlen(rc_quality); char* quality = (char*)malloc(str_len + 1); memcpy(quality, rc_quality, strlen(rc_quality)); quality[str_len] = '\0'; pbuff->SetPtr(quality, strlen(rc_quality)); enc_flow->Control(VideoEncoder::kRcQualityChange, pbuff); return 0; } int video_encoder_set_rc_mode(std::shared_ptr& enc_flow, const char* rc_mode) { if (!enc_flow || !rc_mode) { return -EINVAL; } if (strcmp(rc_mode, KEY_VBR) && strcmp(rc_mode, KEY_CBR)) { LOG("ERROR: %s rc_mode is invalid! should be KEY_VBR/KEY_VBR\n", __func__); return -EINVAL; } auto pbuff = std::make_shared(0); int str_len = strlen(rc_mode); char* mode = (char*)malloc(str_len + 1); memcpy(mode, rc_mode, strlen(rc_mode)); mode[str_len] = '\0'; pbuff->SetPtr(mode, strlen(rc_mode)); enc_flow->Control(VideoEncoder::kRcModeChange, pbuff); return 0; } int video_encoder_set_qp(std::shared_ptr& enc_flow, VideoEncoderQp& qps) { if (!enc_flow) { return -EINVAL; } // qp_max - 8 ~ 51 // qp_min - 0 ~ 48 if ((qps.qp_max && ((qps.qp_max > 51) || (qps.qp_max < 8))) || (qps.qp_max_i && ((qps.qp_max_i > 51) || (qps.qp_max_i < 8))) || (qps.qp_min < 0) || (qps.qp_min > 48) || (qps.qp_min_i < 0) || (qps.qp_min_i > 48) || (qps.qp_min > qps.qp_max) || (qps.qp_min_i > qps.qp_max_i)) { LOG("ERROR: qp range error. qp_min:[0, 48]; qp_max:[8, 51]\n"); return -EINVAL; } if ((qps.qp_init > qps.qp_max) || (qps.qp_init < qps.qp_min)) { LOG("ERROR: qp_init should be within [qp_min, qp_max]\n"); return -EINVAL; } if (!qps.qp_step || (qps.qp_step > (qps.qp_max - qps.qp_min))) { LOG("ERROR: qp_step should be within (0, qp_max - qp_min]\n"); return -EINVAL; } auto pbuff = std::make_shared(0); VideoEncoderQp* qp_struct = (VideoEncoderQp*)malloc(sizeof(VideoEncoderQp)); memcpy(qp_struct, &qps, sizeof(VideoEncoderQp)); pbuff->SetPtr(qp_struct, sizeof(VideoEncoderQp)); enc_flow->Control(VideoEncoder::kQPChange, pbuff); return 0; } int jpeg_encoder_set_qfactor(std::shared_ptr& enc_flow, int qfactor) { if (!enc_flow) { return -EINVAL; } if ((qfactor > 99) || (qfactor < 1)) { LOG("ERROR: %s: qfactor should be within [1, 99]\n", __func__); return -EINVAL; } auto pbuff = std::make_shared(0); pbuff->SetValue(qfactor); enc_flow->Control(VideoEncoder::kQPChange, pbuff); return 0; } int video_encoder_force_idr(std::shared_ptr& enc_flow) { if (!enc_flow) { return -EINVAL; } auto pbuff = std::make_shared(0); enc_flow->Control(VideoEncoder::kForceIdrFrame, pbuff); return 0; } int video_encoder_set_fps(std::shared_ptr& enc_flow, uint8_t out_num, uint8_t out_den, uint8_t in_num, uint8_t in_den) { if (!enc_flow) { return -EINVAL; } if (!out_den || !out_num || (out_den > 16) || (out_num > 120) || (in_den > 16) || (in_num > 120)) { LOG("ERROR: fps(%d/%d) is invalid! num:[1,120], den:[1, 16].\n", out_num, out_den); return -EINVAL; } auto pbuff = std::make_shared(0); uint8_t* fps_array = (uint8_t*)malloc(4 * sizeof(uint8_t)); fps_array[0] = in_num; fps_array[1] = in_den; fps_array[2] = out_num; fps_array[3] = out_den; pbuff->SetPtr(fps_array, 4); enc_flow->Control(VideoEncoder::kFrameRateChange, pbuff); return 0; } // input palette should be yuva formate. int video_encoder_set_osd_plt(std::shared_ptr& enc_flow, const uint32_t* yuv_plt) { if (!enc_flow) { return -EINVAL; } uint32_t* plt = (uint32_t*)malloc(256 * sizeof(uint32_t)); memcpy(plt, yuv_plt, 256 * sizeof(uint32_t)); auto pbuff = std::make_shared(0); pbuff->SetPtr(plt, 256 * sizeof(uint32_t)); enc_flow->Control(VideoEncoder::kOSDPltChange, pbuff); return 0; } int video_encoder_set_gop_size(std::shared_ptr& enc_flow, int gop) { if (!enc_flow || (gop < 0)) { return -EINVAL; } auto pbuff = std::make_shared(0); pbuff->SetValue(gop); enc_flow->Control(VideoEncoder::kGopChange, pbuff); return 0; } int video_encoder_set_osd_region(std::shared_ptr& enc_flow, OsdRegionData* region_data) { if (!enc_flow || !region_data) { return -EINVAL; } if (region_data->enable && ((region_data->width % 16) || (region_data->height % 16))) { LOG("ERROR: osd region size must be a multiple of 16x16."); return -EINVAL; } int buffer_size = region_data->width * region_data->height; OsdRegionData* rdata = (OsdRegionData*)malloc(sizeof(OsdRegionData) + buffer_size); memcpy((void*)rdata, (void*)region_data, sizeof(OsdRegionData)); if (buffer_size) { rdata->buffer = (uint8_t*)rdata + sizeof(OsdRegionData); memcpy(rdata->buffer, region_data->buffer, buffer_size); } auto pbuff = std::make_shared(0); pbuff->SetPtr(rdata, sizeof(OsdRegionData) + buffer_size); enc_flow->Control(VideoEncoder::kOSDDataChange, pbuff); return 0; } int video_encoder_set_move_detection(std::shared_ptr& enc_flow, std::shared_ptr& md_flow) { int ret = 0; void** rdata = (void**)malloc(sizeof(void*)); *rdata = md_flow.get(); auto pbuff = std::make_shared(0); pbuff->SetPtr(rdata, sizeof(sizeof(void*))); ret = enc_flow->Control(easymedia::VideoEncoder::kMoveDetectionFlow, pbuff); return ret; } int video_encoder_set_roi_regions(std::shared_ptr& enc_flow, EncROIRegion* regions, int region_cnt) { if (!enc_flow) { return -EINVAL; } int rsize = 0; void* rdata = NULL; if (regions && region_cnt) { rsize = sizeof(EncROIRegion) * region_cnt; rdata = (void*)malloc(rsize); memcpy(rdata, (void*)regions, rsize); } auto pbuff = std::make_shared(0); pbuff->SetPtr(rdata, rsize); enc_flow->Control(VideoEncoder::kROICfgChange, pbuff); return 0; } int video_encoder_set_roi_regions(std::shared_ptr& enc_flow, std::string roi_param) { if (!enc_flow) { return -EINVAL; } auto regions = StringToRoiRegions(roi_param); int region_cnt = regions.size(); if (!region_cnt) { return -EINVAL; } EncROIRegion* rdata = NULL; int rsize = sizeof(EncROIRegion) * region_cnt; rdata = (EncROIRegion*)malloc(rsize); if (!rdata) { return -EINVAL; } int i = 0; for (auto iter : regions) { memcpy((void*)&rdata[i++], (void*)&iter, sizeof(EncROIRegion)); } auto pbuff = std::make_shared(0); pbuff->SetPtr(rdata, rsize); enc_flow->Control(VideoEncoder::kROICfgChange, pbuff); return 0; } int video_move_detect_set_rects(std::shared_ptr& md_flow, ImageRect* rects, int rect_cnt) { if (!md_flow || !rects || !rect_cnt) { return -EINVAL; } return md_flow->Control(easymedia::S_MD_ROI_RECTS, rects, rect_cnt); } int video_move_detect_set_rects(std::shared_ptr& md_flow, std::string rects_param) { if (!md_flow) { return -EINVAL; } std::vector rect_vector; rect_vector = StringToImageRect(rects_param); if (rect_vector.empty()) { return -EINVAL; } int rect_cnt = (int)rect_vector.size(); ImageRect* rects = (ImageRect*)malloc(rect_cnt * sizeof(ImageRect)); if (!rects) { return -ENOSPC; } int i = 0; for (auto iter : rect_vector) { memcpy((void*)&rects[i++], (void*)&iter, sizeof(ImageRect)); } int ret = md_flow->Control(easymedia::S_MD_ROI_RECTS, rects, rect_cnt); free(rects); return ret; } int video_encoder_set_split(std::shared_ptr& enc_flow, unsigned int mode, unsigned int size) { if (!enc_flow) { return -EINVAL; } uint32_t* param = (uint32_t*)malloc(2 * sizeof(uint32_t)); *param = mode; *(param + 1) = size; auto pbuff = std::make_shared(0); pbuff->SetPtr(param, 2 * sizeof(uint32_t)); enc_flow->Control(VideoEncoder::kSplitChange, pbuff); return 0; } int video_encoder_set_gop_mode(std::shared_ptr& enc_flow, EncGopModeParam* mode_params) { if (!enc_flow || !mode_params) { return -EINVAL; } uint8_t* param = (uint8_t*)malloc(sizeof(EncGopModeParam)); if (!param) { return -ENOSPC; } memcpy(param, mode_params, sizeof(EncGopModeParam)); auto pbuff = std::make_shared(0); pbuff->SetPtr(param, sizeof(EncGopModeParam)); enc_flow->Control(VideoEncoder::kGopModeChange, pbuff); return 0; } int video_encoder_set_avc_profile(std::shared_ptr& enc_flow, int profile_idc, int level) { if (!enc_flow) { return -EINVAL; } if ((profile_idc != 66) && (profile_idc != 77) && (profile_idc != 100)) { LOG("ERROR: %s profile_idc:%d is invalid!" "Only supprot: 66:Baseline, 77:Main Profile, 100: High Profile\n", __func__, profile_idc); return -EINVAL; } int* param = (int*)malloc(2 * sizeof(int)); *param = profile_idc; *(param + 1) = level; auto pbuff = std::make_shared(0); pbuff->SetPtr(param, 2 * sizeof(int)); enc_flow->Control(VideoEncoder::kProfileChange, pbuff); return 0; } int video_encoder_set_userdata(std::shared_ptr& enc_flow, void* data, int len, int all_frames) { if (!enc_flow) { return -EINVAL; } if (!data && len) { LOG("ERROR: invalid userdata size!\n"); return -EINVAL; } // Param formate: allFrameEnableFlag(8bit) + dataPoint uint8_t* param = (uint8_t*)malloc(len + 1); *param = all_frames ? 1 : 0; if (len) { memcpy(param + 1, data, len); } auto pbuff = std::make_shared(0); pbuff->SetPtr(param, len + 1); enc_flow->Control(VideoEncoder::kUserDataChange, pbuff); return 0; } int video_encoder_enable_statistics(std::shared_ptr& enc_flow, int enable) { if (!enc_flow) { return -EINVAL; } auto pbuff = std::make_shared(0); pbuff->SetValue(enable); enc_flow->Control(VideoEncoder::kEnableStatistics, pbuff); return 0; } } // namespace easymedia