├── Demo ├── Linux │ └── Media SDK │ │ ├── main.cc │ │ └── realtime_stitcher_demo.cc └── Windows │ └── Media SDK │ ├── main.cc │ └── realtime_stitcher_demo.cc ├── README.md └── README_zh.md /Demo/Linux/Media SDK/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef WIN32 13 | #include 14 | #include 15 | #endif // WIN32 16 | 17 | using namespace std::chrono; 18 | using namespace ins; 19 | 20 | const std::string helpstr = 21 | "{-help | default | print this message }\n" 22 | "{-inputs | None | input files }\n" 23 | "{-output | None | out path }\n" 24 | "{-stitch_type | template | template }\n" 25 | "{ | optflow }\n" 26 | "{ | dynamicstitch }\n" 27 | "{ | aistitch }\n" 28 | "{-ai_stitching_model | | ai stitching model path }\n" 29 | "{-bitrate | same as input video | the bitrate of ouput file }\n" 30 | "{-enable_flowstate | OFF | enable flowstate }\n" 31 | "{-enable_directionlock | OFF | enable directionlock }\n" 32 | "{-output_size | 1920x960 | the resolution of output }\n" 33 | "{-enable_h265_encoder | h264 | encode format }\n" 34 | "{-disable_cuda | true | disable cuda }\n" 35 | "{-enable_soft_encode | false | use soft encoder }\n" 36 | "{-enable_soft_decode | false | use soft decoder }\n" 37 | "{-enable_stitchfusion | OFF | stitch_fusion }\n" 38 | "{-enable_denoise | OFF | enable denoise }\n" 39 | "{-image_denoise_model | OFF | image denoise model path }\n" 40 | "{-enable_colorplus | OFF | enable colorplus }\n" 41 | "{-colorplus_model | | colorplus model path }\n" 42 | "{-enable_deflicker | OFF | enable deflicker }\n" 43 | "{-deflicker_model | | deflicker model path }\n" 44 | "{-image_sequence_dir | None | the output dir of image sequence }\n" 45 | "{-image_type | jpg | jpg }\n" 46 | "{ | png }\n" 47 | "{-camera_accessory_type | default 0 | refer to 'common.h' }\n" 48 | "{-export_frame_index | | Derived frame number sequence, example: 20-50-30 }\n"; 49 | 50 | static std::string stringToUtf8(const std::string& original_str) { 51 | #ifdef WIN32 52 | const char* std_origin_str = original_str.c_str(); 53 | const int std_origin_str_len = static_cast(original_str.length()); 54 | 55 | int nwLen = MultiByteToWideChar(CP_ACP, 0, std_origin_str, -1, NULL, 0); 56 | 57 | wchar_t* pwBuf = new wchar_t[nwLen + 1]; 58 | ZeroMemory(pwBuf, nwLen * 2 + 2); 59 | 60 | MultiByteToWideChar(CP_ACP, 0, std_origin_str, std_origin_str_len, pwBuf, nwLen); 61 | 62 | int nLen = WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL); 63 | 64 | char* pBuf = new char[nLen + 1]; 65 | ZeroMemory(pBuf, nLen + 1); 66 | 67 | WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL); 68 | 69 | std::string ret_str(pBuf); 70 | 71 | delete[] pwBuf; 72 | delete[] pBuf; 73 | 74 | pwBuf = NULL; 75 | pBuf = NULL; 76 | 77 | return ret_str; 78 | #else 79 | return original_str; 80 | #endif 81 | } 82 | 83 | std::vector split(const std::string& s, char delimiter) { 84 | std::vector tokens; 85 | std::string token; 86 | std::istringstream tokenStream(s); 87 | 88 | while (std::getline(tokenStream, token, delimiter)) { 89 | tokens.push_back(token); 90 | } 91 | 92 | return tokens; 93 | } 94 | 95 | int main(int argc, char* argv[]) { 96 | ins::SetLogLevel(ins::InsLogLevel::ERR); 97 | ins::InitEnv(); 98 | 99 | std::vector input_paths; 100 | std::string output_path; 101 | std::string image_sequence_dir; 102 | std::string ai_stitching_model; 103 | std::string color_plus_model_path; 104 | std::string denoise_model_path; 105 | std::string exported_frame_number_sequence; 106 | std::string deflicker_model_path; 107 | 108 | STITCH_TYPE stitch_type = STITCH_TYPE::OPTFLOW; 109 | IMAGE_TYPE image_type = IMAGE_TYPE::JPEG; 110 | CameraAccessoryType accessory_type = CameraAccessoryType::kNormal; 111 | 112 | int output_width = 1920; 113 | int output_height = 960; 114 | int output_bitrate = 0; 115 | 116 | bool enable_flowstate = false; 117 | bool enable_cuda = true; 118 | bool enable_soft_encode = false; 119 | bool enable_soft_decode = false; 120 | bool enalbe_stitchfusion = true; 121 | bool enable_colorplus = false; 122 | bool enable_directionlock = false; 123 | bool enable_sequence_denoise = false; 124 | bool enable_H265_encoder = false; 125 | bool enable_deflicker = false; 126 | 127 | for (int i = 1; i < argc; i++) { 128 | if (std::string("-inputs") == std::string(argv[i])) { 129 | std::string input_path = argv[++i]; 130 | while (input_path[0] != '-') { 131 | input_paths.push_back(stringToUtf8(input_path)); 132 | input_path = argv[++i]; 133 | } 134 | } 135 | if (std::string("-output") == std::string(argv[i])) { 136 | output_path = stringToUtf8(argv[++i]); 137 | } 138 | if (std::string("-colorplus_model") == std::string(argv[i])) { 139 | color_plus_model_path = stringToUtf8(argv[++i]); 140 | } 141 | else if (std::string("-stitch_type") == std::string(argv[i])) { 142 | std::string stitchType = argv[++i]; 143 | if (stitchType == std::string("optflow")) { 144 | stitch_type = STITCH_TYPE::OPTFLOW; 145 | } 146 | else if (stitchType == std::string("dynamicstitch")) { 147 | stitch_type = STITCH_TYPE::DYNAMICSTITCH; 148 | } 149 | else if (stitchType == std::string("aistitch")) { 150 | stitch_type = STITCH_TYPE::AIFLOW; 151 | } 152 | } 153 | else if (std::string("-enable_flowstate") == std::string(argv[i])) { 154 | enable_flowstate = true; 155 | } 156 | else if (std::string("-disable_cuda") == std::string(argv[i])) { 157 | enable_cuda = false; 158 | } 159 | else if (std::string("-enable_stitchfusion") == std::string(argv[i])) { 160 | enalbe_stitchfusion = true; 161 | } 162 | else if (std::string("-enable_denoise") == std::string(argv[i])) { 163 | enable_sequence_denoise = true; 164 | } 165 | else if (std::string("-enable_colorplus") == std::string(argv[i])) { 166 | enable_colorplus = true; 167 | } 168 | else if (std::string("-enable_directionlock") == std::string(argv[i])) { 169 | enable_directionlock = true; 170 | } 171 | else if (std::string("-enable_h265_encoder") == std::string(argv[i])) { 172 | enable_H265_encoder = true; 173 | } 174 | else if (std::string("-bitrate") == std::string(argv[i])) { 175 | output_bitrate = atoi(argv[++i]); 176 | } 177 | else if (std::string("-output_size") == std::string(argv[i])) { 178 | auto res = split(std::string(argv[++i]), 'x'); 179 | if (res.size() == 2) { 180 | output_width = std::atoi(res[0].c_str()); 181 | output_height = std::atoi(res[1].c_str()); 182 | } 183 | } 184 | else if (std::string("-image_sequence_dir") == std::string(argv[i])) { 185 | image_sequence_dir = std::string(argv[++i]); 186 | } 187 | else if (std::string("-image_type") == std::string(argv[i])) { 188 | std::string type = argv[++i]; 189 | if (type == std::string("jpg")) { 190 | image_type = IMAGE_TYPE::JPEG; 191 | } 192 | else if (type == std::string("png")) { 193 | image_type = IMAGE_TYPE::PNG; 194 | } 195 | } 196 | else if (std::string("-camera_accessory_type") == std::string(argv[i])) { 197 | accessory_type = static_cast(std::atoi(argv[++i])); 198 | } 199 | else if (std::string("-ai_stitching_model") == std::string(argv[i])) { 200 | ai_stitching_model = stringToUtf8(argv[++i]); 201 | } 202 | else if (std::string("-image_denoise_model") == std::string(argv[i])) { 203 | denoise_model_path = stringToUtf8(argv[++i]); 204 | } 205 | else if (std::string("-export_frame_index") == std::string(argv[i])) { 206 | exported_frame_number_sequence = argv[++i]; 207 | } 208 | else if (std::string("-deflicker_model") == std::string(argv[i])) { 209 | deflicker_model_path = stringToUtf8(argv[++i]); 210 | } 211 | else if (std::string("-enable_deflicker") == std::string(argv[i])) { 212 | enable_deflicker = true; 213 | } 214 | else if (std::string("-enable_soft_encode") == std::string(argv[i])) { 215 | enable_soft_encode = true; 216 | } 217 | else if (std::string("-enable_soft_decode") == std::string(argv[i])) { 218 | enable_soft_decode = true; 219 | } 220 | else if (std::string("-help") == std::string(argv[i])) { 221 | std::cout << helpstr << std::endl; 222 | } 223 | } 224 | 225 | if (input_paths.empty()) { 226 | std::cout << "can not find input_file" << std::endl; 227 | std::cout << helpstr << std::endl; 228 | return -1; 229 | } 230 | 231 | if (output_path.empty() && image_sequence_dir.empty()) { 232 | std::cout << "can not find output_file" << std::endl; 233 | std::cout << helpstr << std::endl; 234 | return -1; 235 | } 236 | 237 | std::vector export_frame_nums; 238 | if (!image_sequence_dir.empty()) { 239 | auto frame_index_vec = split(exported_frame_number_sequence, '-'); 240 | for (auto& frame_index : frame_index_vec) { 241 | int index = atoi(frame_index.c_str()); 242 | export_frame_nums.push_back(index); 243 | } 244 | } 245 | 246 | if (color_plus_model_path.empty()) { 247 | enable_colorplus = false; 248 | } 249 | 250 | int count = 1; 251 | while (count--) { 252 | std::mutex mutex; 253 | std::condition_variable cond; 254 | bool is_finished = false; 255 | bool has_error = false; 256 | int stitch_progress = 0; 257 | std::string suffix = input_paths[0].substr(input_paths[0].find_last_of(".") + 1); 258 | std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower); 259 | if (suffix == "insp" || suffix == "jpg") { 260 | auto image_stitcher = std::make_shared(); 261 | image_stitcher->SetInputPath(input_paths); 262 | image_stitcher->SetStitchType(stitch_type); 263 | image_stitcher->SetOutputPath(output_path); 264 | image_stitcher->SetOutputSize(output_width, output_height); 265 | image_stitcher->EnableFlowState(enable_flowstate); 266 | image_stitcher->EnableDenoise(enable_sequence_denoise, denoise_model_path); 267 | image_stitcher->EnableCuda(enable_cuda); 268 | image_stitcher->EnableStitchFusion(enalbe_stitchfusion); 269 | image_stitcher->SetCameraAccessoryType(accessory_type); 270 | image_stitcher->SetAiStitchModelFile(ai_stitching_model); 271 | image_stitcher->EnableColorPlus(enable_colorplus, color_plus_model_path); 272 | image_stitcher->Stitch(); 273 | } 274 | else if (suffix == "mp4" || suffix == "insv" || suffix == "lrv") { 275 | auto start_time = steady_clock::now(); 276 | auto video_stitcher = std::make_shared(); 277 | video_stitcher->SetInputPath(input_paths); 278 | if (image_sequence_dir.empty()) { 279 | video_stitcher->SetOutputPath(output_path); 280 | } 281 | else { 282 | if (!export_frame_nums.empty()) { 283 | video_stitcher->SetExportFrameSequence(export_frame_nums); 284 | } 285 | 286 | video_stitcher->SetImageSequenceInfo(image_sequence_dir, image_type); 287 | } 288 | video_stitcher->SetStitchType(stitch_type); 289 | video_stitcher->EnableCuda(enable_cuda); 290 | video_stitcher->EnableStitchFusion(enalbe_stitchfusion); 291 | video_stitcher->EnableColorPlus(enable_colorplus, color_plus_model_path); 292 | video_stitcher->SetOutputSize(output_width, output_height); 293 | video_stitcher->SetOutputBitRate(output_bitrate); 294 | video_stitcher->EnableFlowState(enable_flowstate); 295 | video_stitcher->SetAiStitchModelFile(ai_stitching_model); 296 | video_stitcher->EnableDenoise(enable_sequence_denoise); 297 | video_stitcher->EnableDirectionLock(enable_directionlock); 298 | video_stitcher->SetCameraAccessoryType(accessory_type); 299 | video_stitcher->SetSoftwareCodecUsage(enable_soft_encode, enable_soft_decode); 300 | if (enable_H265_encoder) { 301 | video_stitcher->EnableH265Encoder(); 302 | } 303 | video_stitcher->EnableDeflicker(enable_deflicker, deflicker_model_path); 304 | video_stitcher->SetStitchProgressCallback([&](int process, int error) { 305 | if (stitch_progress != process) { 306 | const std::string process_desc = "process = " + std::to_string(process) + std::string("%"); 307 | std::cout << "\r" << process_desc << std::flush; 308 | stitch_progress = process; 309 | } 310 | 311 | if (stitch_progress == 100) { 312 | std::cout << std::endl; 313 | std::unique_lock lck(mutex); 314 | cond.notify_one(); 315 | is_finished = true; 316 | } 317 | }); 318 | 319 | video_stitcher->SetStitchStateCallback([&](int error, const char* err_info) { 320 | std::cout << "error: " << err_info << std::endl; 321 | has_error = true; 322 | cond.notify_one(); 323 | }); 324 | 325 | std::cout << "start stitch " << std::endl; 326 | video_stitcher->StartStitch(); 327 | 328 | std::unique_lock lck(mutex); 329 | cond.wait(lck, [&] { 330 | std::cout << "progress: " << video_stitcher->GetStitchProgress() << "; finished: " << is_finished << std::endl; 331 | return is_finished || has_error; 332 | }); 333 | 334 | std::cout << "end stitch " << std::endl; 335 | 336 | auto end_time = steady_clock::now(); 337 | std::cout << "cost = " << duration_cast>(end_time - start_time).count() << std::endl; 338 | } 339 | } 340 | return 0; 341 | } -------------------------------------------------------------------------------- /Demo/Linux/Media SDK/realtime_stitcher_demo.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | const std::string window_name = "realtime_stitcher"; 16 | 17 | std::vector split(const std::string& s, char delimiter) { 18 | std::vector tokens; 19 | std::string token; 20 | std::istringstream tokenStream(s); 21 | 22 | while (std::getline(tokenStream, token, delimiter)) { 23 | tokens.push_back(token); 24 | } 25 | 26 | return tokens; 27 | } 28 | 29 | class StitchDelegate : public ins_camera::StreamDelegate { 30 | public: 31 | StitchDelegate(const std::shared_ptr& stitcher) :stitcher_(stitcher) { 32 | } 33 | 34 | virtual ~StitchDelegate() { 35 | } 36 | 37 | void OnAudioData(const uint8_t* data, size_t size, int64_t timestamp) override {} 38 | 39 | void OnVideoData(const uint8_t* data, size_t size, int64_t timestamp, uint8_t streamType, int stream_index) override { 40 | stitcher_->HandleVideoData(data, size, timestamp, streamType, stream_index); 41 | } 42 | 43 | void OnGyroData(const std::vector& data) override { 44 | std::vector data_vec(data.size()); 45 | memcpy(data_vec.data(), data.data(), data.size() * sizeof(ins_camera::GyroData)); 46 | stitcher_->HandleGyroData(data_vec); 47 | } 48 | 49 | void OnExposureData(const ins_camera::ExposureData& data) override { 50 | ins::ExposureData exposure_data{}; 51 | exposure_data.exposure_time = data.exposure_time; 52 | exposure_data.timestamp = data.timestamp; 53 | stitcher_->HandleExposureData(exposure_data); 54 | } 55 | 56 | private: 57 | std::shared_ptr stitcher_; 58 | }; 59 | 60 | int main(int argc, char* argv[]) { 61 | ins::InitEnv(); 62 | std::cout << "begin open camera" << std::endl; 63 | ins_camera::SetLogLevel(ins_camera::LogLevel::WARNING); 64 | ins::SetLogLevel(ins::InsLogLevel::WARNING); 65 | for (int i = 1; i < argc; i++) { 66 | const std::string arg = argv[i]; 67 | if (arg == std::string("--debug")) { 68 | ins_camera::SetLogLevel(ins_camera::LogLevel::VERBOSE); 69 | } 70 | else if (arg == std::string("--log_file")) { 71 | const std::string log_file = argv[++i]; 72 | ins_camera::SetLogPath(log_file); 73 | } 74 | } 75 | 76 | ins_camera::DeviceDiscovery discovery; 77 | auto list = discovery.GetAvailableDevices(); 78 | if (list.size() <= 0) { 79 | std::cerr << "no device found." << std::endl; 80 | discovery.FreeDeviceDescriptors(list); 81 | return -1; 82 | } 83 | 84 | for (const auto& camera : list) { 85 | std::cout << "serial:" << camera.serial_number << "\t" 86 | << ";camera type:" << camera.camera_name << "\t" 87 | << ";fw version:" << camera.fw_version << "\t" 88 | << std::endl; 89 | } 90 | 91 | auto cam = std::make_shared(list[0].info); 92 | if (!cam->Open()) { 93 | std::cerr << "failed to open camera" << std::endl; 94 | return -1; 95 | } 96 | 97 | const auto serial_number = list[0].serial_number; 98 | 99 | discovery.FreeDeviceDescriptors(list); 100 | 101 | cv::Mat show_image_; 102 | std::thread show_thread_; 103 | std::mutex show_image_mutex_; 104 | bool is_stop_ = true; 105 | std::condition_variable show_image_cond_; 106 | 107 | std::shared_ptr stitcher = std::make_shared(); 108 | ins::CameraInfo camera_info; 109 | auto preview_param = cam->GetPreviewParam(); 110 | camera_info.cameraName = preview_param.camera_name; 111 | camera_info.decode_type = static_cast(preview_param.encode_type); 112 | camera_info.offset = preview_param.offset; 113 | auto window_crop_info = preview_param.crop_info; 114 | camera_info.window_crop_info_.crop_offset_x = window_crop_info.crop_offset_x; 115 | camera_info.window_crop_info_.crop_offset_y = window_crop_info.crop_offset_y; 116 | camera_info.window_crop_info_.dst_width = window_crop_info.dst_width; 117 | camera_info.window_crop_info_.dst_height = window_crop_info.dst_height; 118 | camera_info.window_crop_info_.src_width = window_crop_info.src_width; 119 | camera_info.window_crop_info_.src_height = window_crop_info.src_height; 120 | camera_info.gyro_timestamp = preview_param.gyro_timestamp; 121 | 122 | stitcher->SetCameraInfo(camera_info); 123 | stitcher->SetStitchType(ins::STITCH_TYPE::DYNAMICSTITCH); 124 | stitcher->EnableFlowState(true); 125 | stitcher->SetOutputSize(960, 480); 126 | stitcher->SetStitchRealTimeDataCallback([&](uint8_t* data[4], int linesize[4], int width, int height, int format, int64_t timestamp) { 127 | std::unique_lock lck(show_image_mutex_); 128 | show_image_ = cv::Mat(height, width, CV_8UC4, data[0]).clone(); 129 | show_image_cond_.notify_one(); 130 | }); 131 | 132 | std::shared_ptr delegate = std::make_shared(stitcher); 133 | cam->SetStreamDelegate(delegate); 134 | 135 | std::cout << "Succeed to open camera..." << std::endl; 136 | 137 | std::cout << "Usage:" << std::endl; 138 | std::cout << "1: start preview live streaming:" << std::endl; 139 | std::cout << "2: stop preview live streaming:" << std::endl; 140 | 141 | int option = 0; 142 | while (true) { 143 | std::cout << "please enter index: "; 144 | std::cin >> option; 145 | if (option < 0 || option > 39) { 146 | std::cout << "Invalid index" << std::endl; 147 | continue; 148 | } 149 | 150 | if (option == 0) { 151 | break; 152 | } 153 | 154 | if (option == 1) { 155 | if (!is_stop_) { 156 | std::cout << "" << std::endl; 157 | continue; 158 | } 159 | ins_camera::LiveStreamParam param; 160 | param.video_resolution = ins_camera::VideoResolution::RES_1440_720P30; 161 | param.lrv_video_resulution = ins_camera::VideoResolution::RES_1440_720P30; 162 | param.video_bitrate = 1024 * 1024 / 2; 163 | param.enable_audio = false; 164 | param.using_lrv = false; 165 | if (cam->StartLiveStreaming(param)) { 166 | stitcher->StartStitch(); 167 | std::cout << "successfully started live stream" << std::endl; 168 | } 169 | 170 | show_thread_ = std::thread([&]() { 171 | cv::namedWindow(window_name, cv::WINDOW_NORMAL); 172 | is_stop_ = false; 173 | while (!is_stop_) 174 | { 175 | std::unique_lock lck(show_image_mutex_); 176 | show_image_cond_.wait(lck, [&]() { 177 | return is_stop_ || !show_image_.empty(); 178 | }); 179 | 180 | if (is_stop_) { 181 | break; 182 | } 183 | 184 | auto temp = show_image_.clone(); 185 | show_image_ = cv::Mat(); 186 | lck.unlock(); 187 | cv::cvtColor(temp, temp, cv::COLOR_RGBA2BGRA); 188 | cv::imshow(window_name, temp); 189 | cv::waitKey(5); 190 | } 191 | }); 192 | } 193 | 194 | if (option == 2) { 195 | std::unique_lock lck(show_image_mutex_); 196 | is_stop_ = true; 197 | show_image_cond_.notify_one(); 198 | lck.unlock(); 199 | if (show_thread_.joinable()) { 200 | show_thread_.join(); 201 | } 202 | cv::destroyWindow(window_name); 203 | if (cam->StopLiveStreaming()) { 204 | stitcher->CancelStitch(); 205 | std::cout << "success!" << std::endl; 206 | } 207 | else { 208 | std::cerr << "failed to stop live." << std::endl; 209 | } 210 | } 211 | } 212 | std::unique_lock lck(show_image_mutex_); 213 | is_stop_ = true; 214 | show_image_cond_.notify_one(); 215 | lck.unlock(); 216 | if (show_thread_.joinable()) { 217 | show_thread_.join(); 218 | } 219 | cv::destroyWindow(window_name); 220 | cam->Close(); 221 | return 0; 222 | } -------------------------------------------------------------------------------- /Demo/Windows/Media SDK/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #ifdef WIN32 14 | #include 15 | #include 16 | #endif // WIN32 17 | 18 | using namespace std::chrono; 19 | using namespace ins; 20 | 21 | const std::string helpstr = 22 | "{-help | default | print this message }\n" 23 | "{-inputs | None | input files }\n" 24 | "{-output | None | out path }\n" 25 | "{-stitch_type | template | template }\n" 26 | "{ | optflow }\n" 27 | "{ | dynamicstitch }\n" 28 | "{ | aistitch }\n" 29 | "{-ai_stitching_model | | ai stitching model path }\n" 30 | "{-bitrate | same as input video | the bitrate of ouput file }\n" 31 | "{-enable_flowstate | OFF | enable flowstate }\n" 32 | "{-enable_directionlock | OFF | enable directionlock }\n" 33 | "{-output_size | 1920x960 | the resolution of output }\n" 34 | "{-enable_h265_encoder | h264 | encode format }\n" 35 | "{-disable_cuda | true | disable cuda }\n" 36 | "{-enable_soft_encode | false | use soft encoder }\n" 37 | "{-enable_soft_decode | false | use soft decoder }\n" 38 | "{-enable_stitchfusion | OFF | stitch_fusion }\n" 39 | "{-enable_denoise | OFF | enable denoise }\n" 40 | "{-image_denoise_model | OFF | image denoise model path }\n" 41 | "{-enable_colorplus | OFF | enable colorplus }\n" 42 | "{-colorplus_model | | colorplus model path }\n" 43 | "{-enable_deflicker | OFF | enable deflicker }\n" 44 | "{-deflicker_model | | deflicker model path }\n" 45 | "{-image_sequence_dir | None | the output dir of image sequence }\n" 46 | "{-image_type | jpg | jpg }\n" 47 | "{ | png }\n" 48 | "{-camera_accessory_type | default 0 | refer to 'common.h' }\n" 49 | "{-export_frame_index | | Derived frame number sequence, example: 20-50-30 }\n"; 50 | 51 | static std::string stringToUtf8(const std::string& original_str) { 52 | #ifdef WIN32 53 | int nwLen = MultiByteToWideChar(CP_ACP, 0, original_str.c_str(), -1, NULL, 0); 54 | 55 | wchar_t* pwBuf = new wchar_t[nwLen + 1]; 56 | ZeroMemory(pwBuf, nwLen * 2 + 2); 57 | 58 | MultiByteToWideChar(CP_ACP, 0, original_str.c_str(), original_str.length(), pwBuf, nwLen); 59 | 60 | int nLen = WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL); 61 | 62 | char* pBuf = new char[nLen + 1]; 63 | ZeroMemory(pBuf, nLen + 1); 64 | 65 | WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL); 66 | 67 | std::string ret_str(pBuf); 68 | 69 | delete[] pwBuf; 70 | delete[] pBuf; 71 | 72 | pwBuf = NULL; 73 | pBuf = NULL; 74 | 75 | return ret_str; 76 | #else 77 | return original_str; 78 | #endif 79 | } 80 | 81 | std::vector split(const std::string& s, char delimiter) { 82 | std::vector tokens; 83 | std::string token; 84 | std::istringstream tokenStream(s); 85 | 86 | while (std::getline(tokenStream, token, delimiter)) { 87 | tokens.push_back(token); 88 | } 89 | 90 | return tokens; 91 | } 92 | 93 | int main(int argc, char* argv[]) { 94 | ins::SetLogLevel(ins::InsLogLevel::ERR); 95 | ins::InitEnv(); 96 | 97 | std::vector input_paths; 98 | std::string output_path; 99 | std::string image_sequence_dir; 100 | std::string ai_stitching_model; 101 | std::string colorpuls_model_path; 102 | std::string denoise_model_path; 103 | std::string exported_frame_number_sequence; 104 | std::string deflicker_model_path; 105 | 106 | STITCH_TYPE stitch_type = STITCH_TYPE::OPTFLOW; 107 | IMAGE_TYPE image_type = IMAGE_TYPE::JPEG; 108 | CameraAccessoryType accessory_type = CameraAccessoryType::kNormal; 109 | 110 | int output_width = 1920; 111 | int output_height = 960; 112 | int output_bitrate = 0; 113 | 114 | bool enable_flowstate = false; 115 | bool enable_cuda = true; 116 | bool enable_soft_encode = false; 117 | bool enable_soft_decode = false; 118 | bool enalbe_stitchfusion = true; 119 | bool enable_colorplus = false; 120 | bool enable_directionlock = false; 121 | bool enable_sequence_denoise = false; 122 | bool enable_H265_encoder = false; 123 | bool enable_deflicker = false; 124 | 125 | for (size_t i = 1; i < argc; i++) { 126 | if (std::string("-inputs") == std::string(argv[i])) { 127 | std::string input_path = argv[++i]; 128 | while (input_path[0] != '-') { 129 | input_paths.push_back(stringToUtf8(input_path)); 130 | input_path = argv[++i]; 131 | } 132 | } 133 | 134 | if (std::string("-output") == std::string(argv[i])) { 135 | output_path = stringToUtf8(argv[++i]); 136 | } 137 | if (std::string("-colorplus_model") == std::string(argv[i])) { 138 | colorpuls_model_path = stringToUtf8(argv[++i]); 139 | } 140 | else if (std::string("-stitch_type") == std::string(argv[i])) { 141 | std::string stitchType = argv[++i]; 142 | if (stitchType == std::string("optflow")) { 143 | stitch_type = STITCH_TYPE::OPTFLOW; 144 | } 145 | else if (stitchType == std::string("dynamicstitch")) { 146 | stitch_type = STITCH_TYPE::DYNAMICSTITCH; 147 | } 148 | else if (stitchType == std::string("aistitch")) { 149 | stitch_type = STITCH_TYPE::AIFLOW; 150 | } 151 | } 152 | else if (std::string("-enable_flowstate") == std::string(argv[i])) { 153 | enable_flowstate = true; 154 | } 155 | else if (std::string("-disable_cuda") == std::string(argv[i])) { 156 | enable_cuda = false; 157 | } 158 | else if (std::string("-enable_stitchfusion") == std::string(argv[i])) { 159 | enalbe_stitchfusion = true; 160 | } 161 | else if (std::string("-enable_denoise") == std::string(argv[i])) { 162 | enable_sequence_denoise = true; 163 | } 164 | else if (std::string("-enable_colorplus") == std::string(argv[i])) { 165 | enable_colorplus = true; 166 | } 167 | else if (std::string("-enable_directionlock") == std::string(argv[i])) { 168 | enable_directionlock = true; 169 | } 170 | else if (std::string("-enable_h265_encoder") == std::string(argv[i])) { 171 | enable_H265_encoder = true; 172 | } 173 | else if (std::string("-bitrate") == std::string(argv[i])) { 174 | output_bitrate = atoi(argv[++i]); 175 | } 176 | else if (std::string("-output_size") == std::string(argv[i])) { 177 | auto res = split(std::string(argv[++i]), 'x'); 178 | if (res.size() == 2) { 179 | output_width = std::atoi(res[0].c_str()); 180 | output_height = std::atoi(res[1].c_str()); 181 | } 182 | } 183 | else if (std::string("-image_sequence_dir") == std::string(argv[i])) { 184 | image_sequence_dir = std::string(argv[++i]); 185 | } 186 | else if (std::string("-image_type") == std::string(argv[i])) { 187 | std::string type = argv[++i]; 188 | if (type == std::string("jpg")) { 189 | image_type = IMAGE_TYPE::JPEG; 190 | } 191 | else if (type == std::string("png")) { 192 | image_type = IMAGE_TYPE::PNG; 193 | } 194 | } 195 | else if (std::string("-camera_accessory_type") == std::string(argv[i])) { 196 | accessory_type = static_cast(std::atoi(argv[++i])); 197 | } 198 | else if (std::string("-ai_stitching_model") == std::string(argv[i])) { 199 | ai_stitching_model = stringToUtf8(argv[++i]); 200 | } 201 | else if (std::string("-image_denoise_model") == std::string(argv[i])) { 202 | denoise_model_path = stringToUtf8(argv[++i]); 203 | } 204 | else if (std::string("-export_frame_index") == std::string(argv[i])) { 205 | exported_frame_number_sequence = argv[++i]; 206 | } 207 | else if (std::string("-deflicker_model") == std::string(argv[i])) { 208 | deflicker_model_path = stringToUtf8(argv[++i]); 209 | } 210 | else if (std::string("-enable_deflicker") == std::string(argv[i])) { 211 | enable_deflicker = true; 212 | } 213 | else if (std::string("-enable_soft_encode") == std::string(argv[i])) { 214 | enable_soft_encode = true; 215 | } 216 | else if (std::string("-enable_soft_decode") == std::string(argv[i])) { 217 | enable_soft_decode = true; 218 | } 219 | else if (std::string("-help") == std::string(argv[i])) { 220 | std::cout << helpstr << std::endl; 221 | } 222 | } 223 | 224 | if (input_paths.empty()) { 225 | std::cout << "can not find input_file" << std::endl; 226 | std::cout << helpstr << std::endl; 227 | return -1; 228 | } 229 | 230 | if (output_path.empty() && image_sequence_dir.empty()) { 231 | std::cout << "can not find output_file" << std::endl; 232 | std::cout << helpstr << std::endl; 233 | return -1; 234 | } 235 | 236 | std::vector export_frame_nums; 237 | if (!image_sequence_dir.empty()) { 238 | auto frame_index_vec = split(exported_frame_number_sequence, '-'); 239 | for (auto& frame_index : frame_index_vec) { 240 | int index = atoi(frame_index.c_str()); 241 | export_frame_nums.push_back(index); 242 | } 243 | } 244 | 245 | if (colorpuls_model_path.empty()) { 246 | enable_colorplus = false; 247 | } 248 | 249 | std::mutex mutex_; 250 | std::condition_variable cond_; 251 | bool is_finisned = false; 252 | bool has_error = false; 253 | bool is_cancel = false; 254 | int stitch_progress = 0; 255 | int count = 1; 256 | 257 | while (count--) { 258 | is_finisned = false; 259 | has_error = false; 260 | is_cancel = false; 261 | stitch_progress = 0; 262 | std::string suffix = input_paths[0].substr(input_paths[0].find_last_of(".") + 1); 263 | std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower); 264 | if (suffix == "insp" || suffix == "jpg") { 265 | auto image_stitcher = std::make_shared(); 266 | image_stitcher->SetInputPath(input_paths); 267 | image_stitcher->SetStitchType(stitch_type); 268 | image_stitcher->SetOutputPath(output_path); 269 | image_stitcher->SetOutputSize(output_width, output_height); 270 | image_stitcher->EnableFlowState(enable_flowstate); 271 | image_stitcher->EnableDenoise(enable_sequence_denoise, denoise_model_path); 272 | image_stitcher->EnableCuda(enable_cuda); 273 | image_stitcher->EnableStitchFusion(enalbe_stitchfusion); 274 | image_stitcher->SetCameraAccessoryType(accessory_type); 275 | image_stitcher->SetAiStitchModelFile(ai_stitching_model); 276 | image_stitcher->EnableColorPlus(enable_colorplus, colorpuls_model_path); 277 | image_stitcher->Stitch(); 278 | } 279 | else if (suffix == "mp4" || suffix == "insv" || suffix == "lrv") { 280 | auto start_time = steady_clock::now(); 281 | auto video_stitcher = std::make_shared(); 282 | video_stitcher->SetInputPath(input_paths); 283 | if (image_sequence_dir.empty()) { 284 | video_stitcher->SetOutputPath(output_path); 285 | } 286 | else { 287 | if (!export_frame_nums.empty()) { 288 | video_stitcher->SetExportFrameSequence(export_frame_nums); 289 | } 290 | 291 | video_stitcher->SetImageSequenceInfo(image_sequence_dir, image_type); 292 | } 293 | video_stitcher->SetStitchType(stitch_type); 294 | video_stitcher->EnableCuda(enable_cuda); 295 | video_stitcher->EnableStitchFusion(enalbe_stitchfusion); 296 | video_stitcher->EnableColorPlus(enable_colorplus, colorpuls_model_path); 297 | video_stitcher->SetOutputSize(output_width, output_height); 298 | video_stitcher->SetOutputBitRate(output_bitrate); 299 | video_stitcher->EnableFlowState(enable_flowstate); 300 | video_stitcher->SetAiStitchModelFile(ai_stitching_model); 301 | video_stitcher->EnableDenoise(enable_sequence_denoise); 302 | video_stitcher->EnableDirectionLock(enable_directionlock); 303 | video_stitcher->SetCameraAccessoryType(accessory_type); 304 | video_stitcher->SetSoftwareCodecUsage(enable_soft_encode, enable_soft_decode); 305 | if (enable_H265_encoder) { 306 | video_stitcher->EnableH265Encoder(); 307 | } 308 | video_stitcher->EnableDeflicker(enable_deflicker, deflicker_model_path); 309 | video_stitcher->SetStitchProgressCallback([&](int process, int error) { 310 | if (stitch_progress != process) { 311 | const std::string process_desc = "process = " + std::to_string(process) + std::string("%"); 312 | std::cout << "\r" << process_desc << std::flush; 313 | stitch_progress = process; 314 | } 315 | 316 | if (stitch_progress == 100) { 317 | std::cout << std::endl; 318 | std::unique_lock lck(mutex_); 319 | cond_.notify_one(); 320 | is_finisned = true; 321 | } 322 | }); 323 | 324 | video_stitcher->SetStitchStateCallback([&](int error, const char* errinfo) { 325 | std::cout << "error: " << errinfo << std::endl; 326 | has_error = true; 327 | cond_.notify_one(); 328 | }); 329 | 330 | std::cout << "start stitch " << std::endl; 331 | video_stitcher->StartStitch(); 332 | 333 | std::unique_lock lck(mutex_); 334 | cond_.wait(lck, [&] { 335 | std::cout << "progress: " << video_stitcher->GetStitchProgress() << "; finisned: " << is_finisned << std::endl; 336 | return is_finisned || has_error; 337 | }); 338 | 339 | std::cout << "end stitch " << std::endl; 340 | 341 | auto end_time = steady_clock::now(); 342 | std::cout << "cost = " << duration_cast>(end_time - start_time).count() << std::endl; 343 | } 344 | } 345 | return 0; 346 | } -------------------------------------------------------------------------------- /Demo/Windows/Media SDK/realtime_stitcher_demo.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | const std::string window_name = "realtime_stitcher"; 16 | 17 | std::vector split(const std::string& s, char delimiter) { 18 | std::vector tokens; 19 | std::string token; 20 | std::istringstream tokenStream(s); 21 | 22 | while (std::getline(tokenStream, token, delimiter)) { 23 | tokens.push_back(token); 24 | } 25 | 26 | return tokens; 27 | } 28 | 29 | class StitchDelegate : public ins_camera::StreamDelegate { 30 | public: 31 | StitchDelegate(const std::shared_ptr& stitcher) :stitcher_(stitcher) { 32 | } 33 | 34 | virtual ~StitchDelegate() { 35 | } 36 | 37 | void OnAudioData(const uint8_t* data, size_t size, int64_t timestamp) override {} 38 | 39 | void OnVideoData(const uint8_t* data, size_t size, int64_t timestamp, uint8_t streamType, int stream_index) override { 40 | stitcher_->HandleVideoData(data, size, timestamp, streamType, stream_index); 41 | } 42 | 43 | void OnGyroData(const std::vector& data) override { 44 | std::vector data_vec(data.size()); 45 | memcpy(data_vec.data(), data.data(), data.size() * sizeof(ins_camera::GyroData)); 46 | stitcher_->HandleGyroData(data_vec); 47 | } 48 | 49 | void OnExposureData(const ins_camera::ExposureData& data) override { 50 | ins::ExposureData exposure_data{}; 51 | exposure_data.exposure_time = data.exposure_time; 52 | exposure_data.timestamp = data.timestamp; 53 | stitcher_->HandleExposureData(exposure_data); 54 | } 55 | 56 | private: 57 | std::shared_ptr stitcher_; 58 | }; 59 | 60 | int main(int argc, char* argv[]) { 61 | ins::InitEnv(); 62 | std::cout << "begin open camera" << std::endl; 63 | ins_camera::SetLogLevel(ins_camera::LogLevel::WARNING); 64 | ins::SetLogLevel(ins::InsLogLevel::WARNING); 65 | for (int i = 1; i < argc; i++) { 66 | const std::string arg = argv[i]; 67 | if (arg == std::string("--debug")) { 68 | ins_camera::SetLogLevel(ins_camera::LogLevel::VERBOSE); 69 | } 70 | else if (arg == std::string("--log_file")) { 71 | const std::string log_file = argv[++i]; 72 | ins_camera::SetLogPath(log_file); 73 | } 74 | } 75 | 76 | ins_camera::DeviceDiscovery discovery; 77 | auto list = discovery.GetAvailableDevices(); 78 | if (list.empty()) { 79 | std::cerr << "no device found." << std::endl; 80 | discovery.FreeDeviceDescriptors(list); 81 | return -1; 82 | } 83 | 84 | for (const auto& camera : list) { 85 | std::cout << "serial:" << camera.serial_number << "\t" 86 | << ";camera type:" << camera.camera_name << "\t" 87 | << ";fw version:" << camera.fw_version << "\t" 88 | << std::endl; 89 | } 90 | 91 | auto cam = std::make_shared(list[0].info); 92 | if (!cam->Open()) { 93 | std::cerr << "failed to open camera" << std::endl; 94 | return -1; 95 | } 96 | 97 | const auto serial_number = list[0].serial_number; 98 | 99 | discovery.FreeDeviceDescriptors(list); 100 | 101 | cv::Mat show_image_; 102 | std::thread show_thread_; 103 | std::mutex show_image_mutex_; 104 | bool is_stop_ = true; 105 | std::condition_variable show_image_cond_; 106 | 107 | std::shared_ptr stitcher = std::make_shared(); 108 | ins::CameraInfo camera_info; 109 | auto preview_param = cam->GetPreviewParam(); 110 | camera_info.cameraName = preview_param.camera_name; 111 | camera_info.decode_type = static_cast(preview_param.encode_type); 112 | camera_info.offset = preview_param.offset; 113 | auto window_crop_info = preview_param.crop_info; 114 | camera_info.window_crop_info_.crop_offset_x = window_crop_info.crop_offset_x; 115 | camera_info.window_crop_info_.crop_offset_y = window_crop_info.crop_offset_y; 116 | camera_info.window_crop_info_.dst_width = window_crop_info.dst_width; 117 | camera_info.window_crop_info_.dst_height = window_crop_info.dst_height; 118 | camera_info.window_crop_info_.src_width = window_crop_info.src_width; 119 | camera_info.window_crop_info_.src_height = window_crop_info.src_height; 120 | camera_info.gyro_timestamp = preview_param.gyro_timestamp; 121 | 122 | stitcher->SetCameraInfo(camera_info); 123 | stitcher->SetStitchType(ins::STITCH_TYPE::DYNAMICSTITCH); 124 | stitcher->EnableFlowState(true); 125 | stitcher->SetOutputSize(960, 480); 126 | stitcher->SetStitchRealTimeDataCallback([&](uint8_t* data[4], int linesize[4], int width, int height, int format, int64_t timestamp) { 127 | std::unique_lock lck(show_image_mutex_); 128 | show_image_ = cv::Mat(height, width, CV_8UC4, data[0]).clone(); 129 | show_image_cond_.notify_one(); 130 | }); 131 | 132 | std::shared_ptr delegate = std::make_shared(stitcher); 133 | cam->SetStreamDelegate(delegate); 134 | 135 | std::cout << "Succeed to open camera..." << std::endl; 136 | 137 | std::cout << "Usage:" << std::endl; 138 | std::cout << "1: start preview live streaming:" << std::endl; 139 | std::cout << "2: stop preview live streaming:" << std::endl; 140 | 141 | int option = 0; 142 | while (true) { 143 | std::cout << "please enter index: "; 144 | std::cin >> option; 145 | if (option < 0 || option > 39) { 146 | std::cout << "Invalid index" << std::endl; 147 | continue; 148 | } 149 | 150 | if (option == 0) { 151 | break; 152 | } 153 | 154 | if (option == 1) { 155 | if (!is_stop_) { 156 | std::cout << "" << std::endl; 157 | continue; 158 | } 159 | ins_camera::LiveStreamParam param; 160 | param.video_resolution = ins_camera::VideoResolution::RES_1440_720P30; 161 | param.lrv_video_resulution = ins_camera::VideoResolution::RES_1440_720P30; 162 | param.video_bitrate = 1024 * 1024 / 2; 163 | param.enable_audio = false; 164 | param.using_lrv = false; 165 | if (cam->StartLiveStreaming(param)) { 166 | stitcher->StartStitch(); 167 | std::cout << "successfully started live stream" << std::endl; 168 | } 169 | 170 | show_thread_ = std::thread([&]() { 171 | cv::namedWindow(window_name, cv::WINDOW_NORMAL); 172 | is_stop_ = false; 173 | while (!is_stop_) 174 | { 175 | std::unique_lock lck(show_image_mutex_); 176 | show_image_cond_.wait(lck, [&]() { 177 | return is_stop_ || !show_image_.empty(); 178 | }); 179 | 180 | if (is_stop_) { 181 | break; 182 | } 183 | 184 | auto temp = show_image_.clone(); 185 | show_image_ = cv::Mat(); 186 | lck.unlock(); 187 | cv::cvtColor(temp, temp, cv::COLOR_RGBA2BGRA); 188 | cv::imshow(window_name, temp); 189 | cv::waitKey(5); 190 | } 191 | }); 192 | } 193 | 194 | if (option == 2) { 195 | std::unique_lock lck(show_image_mutex_); 196 | is_stop_ = true; 197 | show_image_cond_.notify_one(); 198 | lck.unlock(); 199 | if (show_thread_.joinable()) { 200 | show_thread_.join(); 201 | } 202 | cv::destroyWindow(window_name); 203 | if (cam->StopLiveStreaming()) { 204 | stitcher->CancelStitch(); 205 | std::cout << "success!" << std::endl; 206 | } 207 | else { 208 | std::cerr << "failed to stop live." << std::endl; 209 | } 210 | } 211 | } 212 | std::unique_lock lck(show_image_mutex_); 213 | is_stop_ = true; 214 | show_image_cond_.notify_one(); 215 | lck.unlock(); 216 | if (show_thread_.joinable()) { 217 | show_thread_.join(); 218 | } 219 | cv::destroyWindow(window_name); 220 | cam->Close(); 221 | return 0; 222 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # How to get? 2 | 3 | Please visit https://www.insta360.com/sdk/apply to apply for the latest SDK. 4 | 5 | # Support 6 | 7 | Developers' Page: https://www.insta360.com/developer/home 8 | 9 | Insta360 Enterprise: https://www.insta360.com/enterprise 10 | 11 | Issue Report: https://insta.jinshuju.com/f/hZ4aMW 12 | 13 | # [中文文档](README_zh.md) 14 | 15 | # **Overview** 16 | 17 | MediaSDK is mainly used for stitching panoramic materials. The currently supported device models include: **ONE X, ONE R/RS** (Standard fisheye and one-inch fisheye), **ONE X2, X3, X4, X5** cameras for panoramic materials. This SDK supports **video export** and **image export**. The main supported platforms are **Windows** and **Ubuntu 22.04**. For specific API usage, please refer to MediaSDK/example/main.cc. 18 | 19 | - **Supported cameras** 20 | 21 | | Model | Link | 22 | | :--------------------------------------- | :-------------------------------------------------------- | 23 | | ONE X (Discontinued) | http://insta360.com/product/insta360-onex/ | 24 | | ONE R Twin Edition (Discontinued) | http://insta360.com/product/insta360-oner_twin-edition | 25 | | ONE X2 | https://www.insta360.com/product/insta360-onex2 | 26 | | ONE RS 1-Inch 360 Edition (Discontinued) | https://www.insta360.com/product/insta360-oners/1inch-360 | 27 | | X3 | https://www.insta360.com/product/insta360-x3 | 28 | | X4 | https://www.insta360.com/product/insta360-x4 | 29 | | X5 | https://www.insta360.com/product/insta360-x5 | 30 | 31 | - **Supported platforms** 32 | 33 | | Platform | Version | 34 | | :------- | :----------------------------------------------------------- | 35 | | Windows | Windows 7 or later, only x64 supported | 36 | | Linux | Ubuntu 22.04 (x86_64), other distributions need to be tested | 37 | 38 | - **Supported file format** 39 | 40 | | filetype | import format | export format | 41 | | :------- | :------------ | :------------ | 42 | | Video | insv | mp4 | 43 | | Image | insp/jpeg | jpg | 44 | 45 | # **Table of contents** 46 | * [Initialize SDK Environment](#initialize-sdk-environment) 47 | * [Input and Output Parameter Settings](#input-and-output-parameter-settings) 48 | * [Stabilization Parameter Settings](#stabilization-parameter-settings) 49 | * [Stitching Parameter Settings](#stitching-parameter-settings) 50 | * [Image Setting Parameters](#image-setting-parameters) 51 | * [Stitching Process](#stitching-process) 52 | * [Logging Functionality](#logging-functionality) 53 | * [Hardware Codec Acceleration](#hardware-codec-acceleration) 54 | * [Live stream preview splicing](#live-stream-preview-splicing) 55 | * [Error Codes](#error-codes) 56 | 57 | # **Notes** 58 | 59 | The SDK requires that all file path strings must be encoded in UTF-8. 60 | 61 | # **API Description** 62 | 63 | ## **Initialize SDK Environment** 64 | void InitEnv() (GPU Version) 65 | 66 | This API must be called at the start of the main program to initialize the SDK environment. 67 | 68 | ## **Input and Output Parameter Settings** 69 | 70 | ### **Input Path: void SetInputPath(std::vector\& input\_paths)** 71 | 72 | This API is used to set the input paths of the materials. It is an array and is valid for both videos and photos. 73 | 74 | For videos, this array typically contains at most two material files. Materials with a resolution of **5.7K or higher** require two material files as input (except for materials captured with X4 cameras). For **X4 cameras**, dual video track storage is currently used. Regardless of resolution, there is **only one original video file**. 75 | 76 | **Example Usage** 77 | 78 | ```c++ 79 | // For dual-track 5.7K materials 80 | std::string _00_file = "/path/to/VID_XXX_..._00_XXX.insv"; 81 | std::string _10_file = "/path/to/VID_XXX_..._10_XXX.insv" 82 | std::vector input_path = {_00_file,_10_file}; 83 | videoStitcher->SetInputPath(input_path); 84 | 85 | // For single-track material files 86 | std::string insv_file = "/path/to/VID_XXX_..._00_XXX.insv"; 87 | std::vector input_path = {insv_file}; 88 | videoStitcher->SetInputPath(input_path); 89 | ``` 90 | 91 | For **photo files**, this array can accept multiple inputs **(but not exactly 2)**. If **3, 5, 7 or 9 materials** are input, they are assumed to be **HDR photos**, and **HDR fusion** will be applied automatically. For **X4 cameras**, the **default HDR materials** captured by the camera **have already undergone in-camera HDR fusion**. Therefore, only **one material file** is output from the camera. 92 | 93 | 94 | 95 | ### **Output Path: void SetOutputPath(const std::string& output\_path)** 96 | 97 | This API is used to set the output path. It is valid for both video and photo outputs. The parameter should be a full path. 98 | 99 | **Supported Output Formats:** 100 | 101 | > For videos, the path should end with .mp4 **Example:**/output/to/path/video.mp4 102 | 103 | > For images, the path should end with .jpg **Example:** /output/to/path/image.jpg 104 | 105 | 106 | 107 | ### **Output Resolution: void SetOutputSize(int width, int height)** 108 | 109 | This API is used to set the output resolution. The parameter width:height must have a **2:1 ratio**. 110 | 111 | For the **CPU version of the SDK**, if a resolution that is too small is set and **moiré patterns** appear, you can use the **EnableAreaSample** API to **eliminate moiré effects**. 112 | 113 | 114 | 115 | ### **Encoding Format: void EnableH265Encoder()** 116 | 117 | This API is used to set the encoding format to **H.265**. The default encoding format is **H.264**. 118 | 119 | When the output resolution is **greater than 4K**, it is **recommended to use H.265 encoding**, as **H.265 encoding supports hardware acceleration**, which can **speed up the export process**. 120 | 121 | 122 | 123 | ### **Output Bitrate: void SetOutputBitRate(int64\_t bitRate)** 124 | 125 | This API is used to set the bitrate for video output. The unit is **bps**. 126 | 127 | If not set, the original video bitrate will be used by default. 128 | 129 | > **Example:** 130 | > 131 | > To output at **60 Mbps**, set the value as follows: bitRate = 60 × 1000 × 1000 132 | 133 | 134 | 135 | ### **Export Video as Image Sequences: void SetImageSequenceInfo(const std::string output\_dir, IMAGE\_TYPE image\_type)** 136 | 137 | This function allows users to export video frames as an image sequence and configure the output path and image format. 138 | 139 | **Parameters: output\_dir** 140 | 141 | This parameter specifies the **directory-level** output path, **excluding file information**. 142 | 143 | Before using this function, make sure that the **target directory** **has already been created**. 144 | 145 | > **Example: **/path/to/image\_save\_dir 146 | 147 | The exported image files are **named based on the video frame timestamp (ms).** 148 | 149 | > **Example: **/path/to/image\_save\_dir/100.jpg *(This means the image was saved at the 100 ms video frame timestamp.)* 150 | 151 | **Note: **image\_type specifies the image format to be used. This can be either .png or .jpg. 152 | 153 | **Note: **If you have used SetOutputPath, this does not need to be set again. 154 | 155 | 156 | 157 | ### **Export Selected Frames from Video: void SetExportFrameSequence(const std::vector\& vec)** 158 | 159 | This API is used to export images from **specific video frame indices**. This function must be used together with **SetImageSequenceInfo**. The output image file names will be based on the **video frame index**.The **video frame index starts from 0**. 160 | 161 | > **Example: **/path/to/image\_save\_dir/10.jpg (this means the image is saved for video frame index **10**) 162 | 163 | **Demo Example:** 164 | 165 | ```c++ 166 | // This sample code demonstrates extracting frames 0, 10, 20, and 30 from a video file 167 | std::vector seq_nos = {0,10,20,30}; 168 | const std::string image_seq_export_dir = /path/to/image_seq_dir; 169 | const IMAGE_TYPE image_format = IMAGE_TYPE::JPEG; 170 | ... 171 | videoStitcher->SetExportFrameSequence(seq_nos); 172 | videoStitcher->SetImageSequenceInfo(image_seq_export_dir,image_format); 173 | ... 174 | videoStitcher->StartStitch() 175 | ``` 176 | 177 | 178 | 179 | ## **Stabilization Parameter Settings** 180 | 181 | ### **Enable Stabilization: void EnableFlowState(bool enable)** 182 | 183 | This API is used to configure the stabilization option, determining whether to enable stabilization. 184 | 185 | 186 | 187 | ### **Enable Direction Lock: void EnableDirectionLock(bool enable)** 188 | 189 | This API is used to enable **direction lock**. 190 | 191 | 192 | 193 | ## **Stitching Parameter Settings** 194 | 195 | ### **Stitching Type: void SetStitchType(STITCH\_TYPE type)** 196 | 197 | This API is used to set the stitching type. The available stitching types are as follows: 198 | 199 | ```plain text 200 | enum class STITCH_TYPE { 201 | TEMPLATE, // Template stitching 202 | OPTFLOW, // Optical flow stitching 203 | DYNAMICSTITCH, // Dynamic stitching 204 | AIFLOW // AI stitching 205 | }; 206 | ``` 207 | 208 | **Usage Scenarios** 209 | 210 | * **Template Stitching**: An older stitching algorithm that provides poor stitching results for near-field scenes, but is fast and has low computational cost. 211 | 212 | * **Dynamic Stitching**: Suitable for scenes containing motion or situations with rapid changes in movement. 213 | 214 | * **Optical Flow Stitching**: Similar in function to dynamic stitching but optimized for higher accuracy. 215 | 216 | * **AI Stitching**: Based on Insta360’s optimized optical flow stitching technology, offering superior stitching results. 217 | 218 | > **Computational Cost vs. Stitching Quality** 219 | > 220 | > **AI Stitching > Optical Flow Stitching > Dynamic Stitching > Template Stitching** 221 | 222 | > **Stitching Speed** 223 | > 224 | > **Template Stitching > Dynamic Stitching > Optical Flow Stitching > AI Stitching** 225 | 226 | **Note:** 227 | 228 | When using **AI Stitching**, you must call the **SetAiStitchModelFile** API to specify the model file. If this step is skipped, the stitching settings will be **invalid**. 229 | 230 | 231 | 232 | ### **AI Stitching Model: void SetAiStitchModelFile(const std::string& model\_file)** 233 | 234 | This API is used to set the AI stitching model, which is required for AI stitching. 235 | 236 | > **Model File Example: **MediaSDK/modelfile/ai\_stitch\_model.ins 237 | 238 | 239 | 240 | ### **Chromatic Calibration: void EnableStitchFusion(bool enable)** 241 | 242 | This API is used to enable Chromatic Calibration. 243 | 244 | 245 | 246 | **Causes of Chromatic Aberration: **Since the two lenses operate separately, the video exposure captured by each lens may be slightly different. When stitched together, **noticeable brightness differences** may appear. Additionally, due to different lighting conditions on each side of the lens, the camera exposure may vary. Sometimes, the front lens captures a significantly different brightness level compared to the rear lens. This effect is especially prominent in areas with **high contrast lighting conditions**. 247 | 248 | The chromatic calibration function is developed to address such issues. 249 | 250 | 251 | 252 | ### **Lens Guard: void SetCameraAccessoryType(CameraAccessoryType type)** 253 | 254 | This API is used to **set the lens guard type**. If a lens guard is used during shooting, it must also be specified when stitching. Otherwise, the stabilization effect may be incorrect. 255 | 256 | 257 | 258 | The following are the available **lens guard types**: 259 | 260 | ```c++ 261 | enum class CameraAccessoryType { 262 | kNormal = 0, 263 | kWaterproof, // Waterproof case (one/onex/onex2/oner/oners/onex3) 264 | kOnerLensGuard, // Adhesive lens guard (oner/oners) 265 | kOnerLensGuardPro, // Clip-on lens guard (oner/oners) 266 | kOnex2LensGuard, // Adhesive lens guard (oner/oners/onex2/onex3) 267 | kOnex2LensGuardPro, // Clip-on lens guard (onex2) 268 | k283PanoLensGuardPro, // Clip-on lens guard for 283 panoramic lens (oner/oners) 269 | kDiveCaseAir, // Dive case (above water) (onex/onex2/oner/oners/onex3) 270 | kDiveCaseWater, // Dive case (underwater) (onex/onex2/oner/oners/onex3) 271 | kInvisibleDiveCaseAir, // Invisible Dive Case (Above water) (X3/X4) 272 | kInvisibleDiveCaseWater,// Invisible Dive Case (underwater) (X3/X4) 273 | kOnex4LensGuardA, // X4 A-grade plastic lens guard 274 | kOnex4LensGuardS, // X4 S-grade glass lens guard 275 | kOnex3LensGuardA, // X3 A-grade plastic lens guard 276 | kOnex3LensGuardS // X3 S-grade glass lens guard 277 | }; 278 | ``` 279 | 280 | > Lens Guard Classification 281 | > 282 | > Standard lens guards in the store are classified as A-grade, while Premium guards are classified as S-grade. 283 | 284 | 285 | 286 | ## **Image Setting Parameters** 287 | 288 | ### **Color Plus: void EnableColorPlus(bool enable, const std::string& model\_path)** 289 | 290 | This API is used to enable or disable the **Color Plus** function. This is an **AI-based feature**, requiring the path to an **AI model** to be set. 291 | 292 | > **Model file:** SDK_ROOT_DIR/data/colorplus_model.ins 293 | 294 | ### **Denoise: void EnableSequenceDenoise(bool enable)** 295 | 296 | This API is used to **enable or disable** the denoising feature. 297 | 298 | **Video denoise **employs** image processing techniques** and is based on **multi-frame denoising** to reduce or eliminate noise in videos. Compared to **single-frame denoising**, multi-frame denoising **leverages redundant information from multiple frames**, but it also **requires more computing resources** and **slows down export speed**. 299 | 300 | For **image materials**, the **model file path** should be specified. 301 | 302 | > **Model file:** SDK_ROOT_DIR/data/jpg_denoise_9d006262.ins 303 | 304 | ### Remove purple edge: void EnableDefringe(bool enable, const std::string& defringe_model_path) 305 | 306 | This interface is used to eliminate the purple edge phenomenon caused by lighting during recording, such as outdoor strong light and indoor lighting scenes. 307 | 308 | > **Model file:** SDK_ROOT/modelfile/defringe_hr_dynamic_7b56e80f.ins 309 | 310 | ### Remove strobe: void EnableDeflicker(bool enable, const std::string& deflicker_model_path) 311 | 312 | This interface is used to eliminate screen flickering problems caused by lighting during recording. 313 | 314 | > **Model file:** SDK_ROOT/modelfile/deflicker_86ccba0d.ins 315 | 316 | ## **Stitching Process** 317 | 318 | ### **Stitching Progress Callback: void SetStitchStateCallback(stitch\_error\_callback callback)** 319 | 320 | This API is primarily used for **stitching status and progress notifications**. 321 | 322 | It is **recommended not to perform time-consuming operations** within this callback, as this may **affect stitching speed**. 323 | 324 | **Example Code:** 325 | 326 | ```c++ 327 | video_stitcher->SetStitchProgressCallback([&](int process, int error) { 328 | if (stitch_progress != process) { 329 | std::cout << "\r"; 330 | std::cout << "process = " << process << "%"; 331 | std::cout << std::flush; 332 | stitch_progress = process; 333 | } 334 | 335 | if (stitch_progress == 100) { 336 | std::cout << std::endl; 337 | std::unique_lock lck(mutex_); 338 | cond_.notify_one(); 339 | is_finisned = true; 340 | } 341 | }); 342 | ``` 343 | 344 | 345 | 346 | ### **Stitching Error Callback: void SetStitchProgressCallback(stitch\_process\_callback callback)** 347 | 348 | This API is used to receive error messages during the stitching process. 349 | 350 | **Example Code:** 351 | 352 | ```c++ 353 | video_stitcher->SetStitchStateCallback([&](int error, const char* errinfo) { 354 | std::cout << "error: " << errinfo << std::endl; 355 | has_error = true; 356 | cond_.notify_one(); 357 | }); 358 | ``` 359 | 360 | 361 | 362 | ### **Start Stitching: void StartStitch()** 363 | 364 | This API is used to **start the stitching process**. 365 | 366 | **Note:** 367 | 368 | Ensure that all **parameter settings are completed before calling this API**. 369 | 370 | If this API is executed **before setting the necessary parameters**, the parameters **will not take effect**. 371 | 372 | 373 | 374 | ### **Cancel Stitching: bool CancelStitch()** 375 | 376 | This API is used to **interrupt the stitching process**. 377 | 378 | 379 | 380 | ### **Get Stitching Progress: int GetStitchProgress() const** 381 | 382 | This API is used to **retrieve the stitching progress**. 383 | 384 | 385 | 386 | ## **Logging Functionality** 387 | 388 | ### **Set Log Path: void SetLogPath(const std::string log\_path)** 389 | 390 | This API is primarily used to set the **log file path** in the SDK, allowing SDK log information to be saved. 391 | 392 | ### **Set Log Print Level: void SetLogLevel(InsLogLevel level)** 393 | 394 | This API is used to **set the logging level** within the SDK. 395 | 396 | 397 | 398 | ## **Hardware Codec Acceleration** 399 | 400 | ## **Live stream preview stitching** 401 | 402 | ### Environmental preparation 403 | 404 | Camera stitch preview is based on CameraSDK and MediaSDK together. Header File is located in `MediaSDK_ROOT/include/ins_realtime_stitcher.` 405 | 406 | The main function of CameraSDK is to provide stitching parameters, video data, anti-shake data, and exposure data. 407 | 408 | The main function of MediaSDK is to use the parameters and data provided by cameraSDK to stitch together images and generate a 2:1 panoramic image. 409 | 410 | ### Preview parameter acquisition and setting 411 | 412 | ```c++ 413 | #include 414 | // This interface mainly obtains the parameters required by mediaSDK 415 | //... 416 | // Cam is the current camera instance object 417 | auto preview_param = cam->GetPreviewParam(); 418 | 419 | // Create a stitching instance object 420 | auto stitcher = std::make_shared(); 421 | 422 | // Set preview parameters for stitching instance objects 423 | ins::CameraInfo camera_info; 424 | camera_info.cameraName = preview_param.camera_name; 425 | camera_info.decode_type = static_cast(preview_param.encode_type); 426 | camera_info.offset = preview_param.offset; 427 | auto window_crop_info = preview_param.crop_info; 428 | camera_info.window_crop_info_.crop_offset_x = window_crop_info.crop_offset_x; 429 | camera_info.window_crop_info_.crop_offset_y = window_crop_info.crop_offset_y; 430 | camera_info.window_crop_info_.dst_width = window_crop_info.dst_width; 431 | camera_info.window_crop_info_.dst_height = window_crop_info.dst_height; 432 | camera_info.window_crop_info_.src_width = window_crop_info.src_width; 433 | camera_info.window_crop_info_.src_height = window_crop_info.src_height; 434 | camera_info.gyro_timestamp = preview_param.gyro_timestamp; 435 | 436 | stitcher->SetCameraInfo(camera_info); 437 | ``` 438 | 439 | ### Preview stream processing of original data source 440 | 441 | ```c++ 442 | // In the cameraSDK, you need to use the inheritance ins_camera :: StreamDelegate interface to achieve real-time data acquisition of the camera. 443 | // Real-time data from cameraSDK can be transmitted to MediaSDK through demo examples 444 | 445 | class StitchStreamDelegate : public ins_camera::StreamDelegate { 446 | public: 447 | StitchDelegate(const std::shared_ptr& stitcher) :stitcher_(stitcher) { 448 | } 449 | 450 | virtual ~StitchDelegate() { 451 | } 452 | 453 | void OnAudioData(const uint8_t* data, size_t size, int64_t timestamp) override {} 454 | 455 | // Video data 456 | void OnVideoData(const uint8_t* data, size_t size, int64_t timestamp, uint8_t streamType, int stream_index) override { 457 | stitcher_->HandleVideoData(data, size, timestamp, streamType, stream_index); 458 | } 459 | 460 | // Anti-shake data 461 | void OnGyroData(const std::vector& data) override { 462 | std::vector data_vec(data.size()); 463 | memcpy(data_vec.data(), data.data(), data.size() * sizeof(ins_camera::GyroData)); 464 | stitcher_->HandleGyroData(data_vec); 465 | } 466 | 467 | // Exposure data 468 | void OnExposureData(const ins_camera::ExposureData& data) override { 469 | ins::ExposureData exposure_data{}; 470 | exposure_data.exposure_time = data.exposure_time; 471 | exposure_data.timestamp = data.timestamp; 472 | stitcher_->HandleExposureData(exposure_data); 473 | } 474 | 475 | private: 476 | std::shared_ptr stitcher_; 477 | }; 478 | ``` 479 | 480 | ### Set preview parameters 481 | 482 | #### stitching type 483 | 484 | Reference 4.4.1 and 4.4.2. 485 | 486 | #### Stabilization parameter 487 | 488 | Parameter 3. 489 | 490 | #### Protective mirror 491 | 492 | Parameters 4.4.4. 493 | 494 | #### Output screen size 495 | 496 | For output size, if not set, the output size is the resolution of the current preview. 497 | 498 | If the performance output frame rate, the resolution size can be reduced. 499 | 500 | ### Get stitched data 501 | 502 | The currently supported format for stitched data is RGBA. 503 | 504 | You can get the stitched video picture by setting `SetStitchRealTimeDataCallback` this callback interface. It is recommended not to perform time-consuming operations in this callback. The reference code is as follows: 505 | 506 | ```c++ 507 | stitcher->SetStitchRealTimeDataCallback([&](uint8_t* data[4], int linesize[4], int width, int height, int format, int64_t timestamp) { 508 | show_image_ = cv::Mat(height, width, CV_8UC4, data[0]).clone(); 509 | }); 510 | ``` 511 | 512 | ### Enable preview 513 | 514 | ```c++ 515 | // Set up the delegation interface for camera real-time data 516 | std::shared_ptr delegate = std::make_shared(stitcher); 517 | cam->SetStreamDelegate(delegate); 518 | ins_camera::LiveStreamParam param; 519 | //... 520 | // Open the preview of the camera 521 | if (cam->StartLiveStreaming(param)) { 522 | // Start the stitching process 523 | stitcher->StartStitch(); 524 | std::cout << "successfully started live stream" << std::endl; 525 | } 526 | ``` 527 | 528 | ### Close preview 529 | 530 | ```c++ 531 | // Close camera preview stream 532 | if (cam->StopLiveStreaming()) { 533 | // Stop the stitching process 534 | stitcher->CancelStitch(); 535 | std::cout << "success!" << std::endl; 536 | } 537 | ``` 538 | 539 | ## **Error Codes** 540 | 541 | | Error Code | Error Message | 542 | | ------------------------- | ------------------------------------------------------------ | 543 | | E_OPEN_FILE(1) | Failed to open file | 544 | | E_PARSE_METADATA(2) | Failed to parse file metadata | 545 | | E_CREATE_OFFSCREEN(3) | Common offscreen rendering failure | 546 | | E_CREATE_RENDER_MODEL(4) | Failed to create render model | 547 | | E_FRAME_PARSE(5) | Failed to retrieve data frame | 548 | | E_CREATE_RENDER_SOURCE(6) | Failed to create rendering data source | 549 | | E_UPDATE_RENDER_SOURCE(7) | Failed to update rendering data frame | 550 | | E_RENDER_FRAME(7) | Failed to render frame | 551 | | E_SAVE_FRAME(8) | Failed to save image | 552 | | E_VIDEO_FRAME_EXPORTOR(9) | Failed to create video frame exporter | 553 | | E_UNKNOWN(999) | Unknown error, please provide detailed information for analysis | 554 | 555 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # 文档概述 2 | 3 | ​ MediaSDK主要用于对全景素材进行拼接,目前支持的机型有ONE X、ONE R/RS(普通鱼眼和一英寸鱼眼)、ONE X2、X3、X4以及X5相机的全景素材。支持视频导出和图片导出。支持平台主要有Windows和Ubuntu 22.04平台。具体接口的使用可以参考SDK中example/main.cc. 4 | 5 | - 支持机型 6 | 7 | | 型号 | 连接 | 8 | | :--------------------------------------- | :-------------------------------------------------------- | 9 | | ONE X (Discontinued) | http://insta360.com/product/insta360-onex/ | 10 | | ONE R Twin Edition (Discontinued) | http://insta360.com/product/insta360-oner_twin-edition | 11 | | ONE X2 | https://www.insta360.com/product/insta360-onex2 | 12 | | ONE RS 1-Inch 360 Edition (Discontinued) | https://www.insta360.com/product/insta360-oners/1inch-360 | 13 | | X3 | https://www.insta360.com/product/insta360-x3 | 14 | | X4 | https://www.insta360.com/product/insta360-x4 | 15 | | X5 | https://www.insta360.com/product/insta360-x5 | 16 | 17 | - **支持平台** 18 | 19 | | 平台 | 版本 | 20 | | :------ | :----------------------------------------- | 21 | | Windows | Windows 7 或更高版本,仅支持 x64 | 22 | | Linux | Ubuntu 22.04(x86_64),其他发行版需要测试 | 23 | 24 | - **支持的文件格式** 25 | 26 | | 文件类型 | 导入格式 | 导出格式 | 27 | | :------- | :-------- | :------- | 28 | | Video | insv | mp4 | 29 | | Image | insp/jpeg | jpg | 30 | 31 | # 目录 32 | * [初始化SDK环境](#初始化sdk环境) 33 | * [输入输出参数设置](#输入输出参数设置) 34 | * [防抖参数设置](#防抖参数设置) 35 | * [拼接参数设置](#拼接参数设置) 36 | * [图像设置参数](#图像设置参数) 37 | * [拼接流程](#拼接流程) 38 | * [日记功能](#日记功能) 39 | * [硬件编解码加速](#硬件编解码加速) 40 | * [实时预览流拼接](#实时预览流拼接) 41 | * [错误码](#错误码) 42 | 43 | # 注意事项: 44 | 45 | SDK中要求所有文件路径字符编码都是UTF-8编码 46 | 47 | # 接口说明 48 | 49 | ## 初始化SDK环境 50 | void InitEnv() (GPU版本); 51 | 52 | 这个接口必须在主程序main开始调用,用于初始化SDK环境 53 | 54 | ## 输入输出参数设置 55 | 56 | ### 输入路径: void SetInputPath(std::vector\& input\_paths) 57 | 58 | 这个接口用于设置素材的输入路径,是一个数组。对于视频和照片都是生效的. 59 | 60 | 对于视频,这个数组最多是有两个素材文件。大于等于5.7k分辨率的素材需要输入两个素材文件(除了X4相机的素材,X4相机的素材,目前使用双视频轨道保存,不管是什么分辨率,只有一个素材文件)。 61 | 62 | 示例如下: 63 | 64 | ```c++ 65 | //双路的5.7K素材如下 66 | std::string _00_file = "/path/to/VID_XXX_..._00_XXX.insv"; 67 | std::string _10_file = "/path/to/VID_XXX_..._10_XXX.insv" 68 | std::vector input_path = {_00_file,_10_file}; 69 | videoStitcher->SetInputPath(input_path); 70 | 71 | //单路文件素材如下 72 | std::string insv_file = "/path/to/VID_XXX_..._00_XXX.insv"; 73 | std::vector input_path = {insv_file}; 74 | videoStitcher->SetInputPath(input_path); 75 | ``` 76 | 77 | 对于图片,这个数组可以输入多个(不能输入2个). 如果输入3个、5个、7个或者9个素材,默认为是HDR照片会进行HDR融合。特别说明X4相机默认拍摄的HDR素材,已经是机内HDR融合好的素材。相机拍摄输出的素材文件只有一个。 78 | 79 | ### 输出路径: void SetOutputPath(const std::string& output\_path) 80 | 81 | 这个接口用于设置导出的路径。对于视频和照片都是生效的。这个参数是全路径的。 82 | 83 | 支持导出的格式: 84 | 85 | > 对于视频,以.mp4结尾。 示例:/ouput/to/path/video.mp4 86 | 87 | > 对于图片,以.jpg结尾。 示例: /output/to/path/image.jpg 88 | 89 | ### 输出分辨率: void SetOutputSize(int width, int height) 90 | 91 | 这个接口用于设置导出的分辨率。参数 width:height 必须是 2:1。 92 | 93 | *针对CPU版本的SDK,如果设置的分辨率过于小出现的摩尔纹现象,可以通过这个接口**EnableAreaSample**去消除摩尔纹现象* 94 | 95 | ### 编码格式: void EnableH265Encoder() 96 | 97 | 这个接口用于设置编码格式为h265. 默认编码格式h264. 输出分辨率大于4K时,建议使用h265编码可以使用硬件编码,可以加快导出进度。 98 | 99 | ### 输出码率: void SetOutputBitRate(int64\_t bitRate) 100 | 101 | 这个接口用于设置导出视频的码率,单位是bps。如果不设置,默认会采用原视频的码率导出。 102 | 103 | > 比如输出 60Mbps,输入的数值:bitRate = 60 X 1000 x 1000 104 | 105 | ### 图片序列导出信息: void SetImageSequenceInfo(const std::string output\_dir, IMAGE\_TYPE image\_type) 106 | 107 | 这个功能允许用户将视频原片导出为图像序列,并可以设置导出图像序列的路径和图片格式。 108 | 109 | 参数:output\_dir 这个参数设置路径是到目录级别的,不包含文件信息。使用这个功能之前需要确保目标目录已经创建好. 110 | 111 | > 示例:/path/to/image\_save\_dir 112 | 113 | 输出的图片文件的命名是以视频帧的时间戳(ms)的。 114 | 115 | > 示例:/path/to/image\_save\_dir/100.jpg(这个表示视频帧100ms时保存的图片名称). 116 | 117 | 参数: image\_type 这个参数设置图片的导出格式。目前支持png和jpg。 118 | 119 | 注意:如果设置了这个接口,** SetOutputPath **这个接口设置的参数是无效的。 120 | 121 | ### 指定图片序列导出: void SetExportFrameSequence(const std::vector\& vec) 122 | 123 | 这个接口用于将指定的视频帧序号序列导出成图片。这个功能是和**SetImageSequenceInfo**这个接口配合一起使用的。输出的图片文件的命名是以视频帧的序号的。视频帧序号以0开始。 124 | 125 | > 示例:/path/to/image\_save\_dir/10.jpg(这个表示视频帧序号为10时保存的图片名称) 126 | 127 | 演示demo: 128 | 129 | ```c++ 130 | // 这个伪代码演示了从视频文件中抽取第0,10,20,30的视频帧进行拼接导出成图片 131 | std::vector seq_nos = {0,10,20,30}; 132 | const std::string image_seq_export_dir = /path/to/image_seq_dir; 133 | const IMAGE_TYPE image_format = IMAGE_TYPE::JPEG; 134 | ... 135 | videoStitcher->SetExportFrameSequence(seq_nos); 136 | videoStitcher->SetImageSequenceInfo(image_seq_export_dir,image_format); 137 | ... 138 | videoStitcher->StartStitch() 139 | ``` 140 | 141 | ## 防抖参数设置 142 | 143 | ### 防抖开启: void EnableFlowState(bool enable) 144 | 145 | 这个接口用于设置防抖选项,是否开启防抖 146 | 147 | ### 方向锁定: void EnableDirectionLock(bool enable) 148 | 149 | 这个接口用于开启方向锁定 150 | 151 | 152 | 153 | ## 拼接参数设置 154 | 155 | ### 拼接类型: void SetStitchType(STITCH\_TYPE type) 156 | 157 | 这个接口用于设置拼接类型。拼接可分为以下几种类型: 158 | 159 | ```c++ 160 | enum class STITCH_TYPE { 161 | TEMPLATE, // 模板拼接 162 | OPTFLOW, // 光流拼接 163 | DYNAMICSTITCH, // 动态光流拼接 164 | AIFLOW // ai拼接 165 | }; 166 | ``` 167 | 168 | 使用场景 169 | 170 | - 模板拼接:比较老的拼接算法,对近景拼接效果不好,但是速度快,性能消耗低 171 | - 动态拼接:适合包含近景的场景,或者有运动和快速变化的情况 172 | - 光流拼接:使用场景和动态拼接相同 173 | - AI 拼接:基于影石 Insta360 现有的光流拼接技术的优化算法,提供更优的拼接效果 174 | 175 | > 性能消耗及拼接效果:AI 拼接>光流拼接>动态拼接>模板拼接 176 | 177 | > 拼接速度:模板拼接>动态拼接>光流拼接>AI 拼接 178 | 179 | 注意: 使用AI拼接时,必须使用接口 **SetAiStitchModelFile** 将模型文件设置进去,否则设置拼接效果失效 180 | 181 | ### AI拼接模型: void SetAiStitchModelFile(const std::string& model\_file) 182 | 183 | 这个接口用于设置AI拼接的模型,配合AI拼接使用 184 | 185 | > 模型文件:SDK\_ROOT\_DIR/data/ai\_stitch\_model.ins 186 | 187 | ### 消色差: void EnableStitchFusion(bool enable) 188 | 189 | 这个接口用于开启消色差的功能 190 | 191 | 产生色差的原因:两个镜头是分开的,得出的视频曝光可能不太一致,当把它们拼接在一起的时候,会有比较明显的亮度差;另外,因为镜头两边的光照不一样,相机曝光不同,有时候前后镜头拍出来的画面也会有明显的亮度差,这种现象在光差比大的地方尤其明显,消色差就是为了解决此类问题而开发 192 | 193 | ### 保护镜: void SetCameraAccessoryType(CameraAccessoryType type) 194 | 195 | 这个接口用于设置保护镜. 如果在拍摄过程中,相机佩戴了保护镜. 需要在拼接的时候也设置保护镜的类型,以防拼接效果不对. 下面保护镜的类型 196 | 197 | ```c++ 198 | enum class CameraAccessoryType { 199 | kNormal = 0, 200 | kWaterproof, // (one/onex/onex2/oner/oners/onex2/onex3) 潜水壳 201 | kOnerLensGuard, // (oner/oners) 黏贴式保护镜 202 | kOnerLensGuardPro, // (oner/oners) 卡扣式保护镜 203 | kOnex2LensGuard, // (oner/oners/onex2/onex3) 黏贴式保护镜 204 | kOnex2LensGuardPro, // (onex2)卡扣式保护镜 205 | k283PanoLensGuardPro, // (oner/oners) 283全景镜头的卡扣式保护镜 206 | kDiveCaseAir, // (onex/onex2/oner/oners/onex2/onex3) 潜水壳(水上) 207 | kDiveCaseWater, // (onex/onex2/oner/oners/onex2/onex3) 潜水壳(水下) 208 | kInvisibleDiveCaseAir, // X3/X4 全隐形潜水壳(水上) 209 | kInvisibleDiveCaseWater, // X3/X4 全隐形潜水壳(水下) 210 | kOnex4LensGuardA, // X4 A级塑胶保护镜 211 | kOnex4LensGuardS, // X4 S级玻璃保护镜 212 | kOnex3LensGuardA, // X3 A级塑胶保护镜 213 | kOnex3LensGuardS, // X3 A级玻璃保护镜 214 | }; 215 | ``` 216 | 217 | 商城中的标准保护镜为A级,高级保护镜为S级 218 | 219 | ## 图像设置参数 220 | 221 | ### 色彩增强: void EnableColorPlus(bool enable, const std::string& model\_path) 222 | 223 | 这个接口用于设置是否开启色彩增强功能.这个AI功能,需要设置一下AI模型的路径 224 | 225 | > 模型文件:SDK_ROOT_DIR/data/colorplus_model.ins 226 | 227 | ### 降噪: void EnableDenoise(bool enable, const std::string& model\_path) 228 | 229 | 这个接口用于设置是否开启降噪功能 230 | 231 | 视频中使用的是多帧降噪是通过图像处理技术减轻或去除视频中的噪点的过程。相比于单帧降噪,视频降噪常常利用前后多帧的冗余信息. 同时也比较消耗性能和减慢导出速度。 232 | 针对图片素材,需要输入模型文件的路径: 233 | 234 | > 模型路径:SDK_ROOT_DIR/data/colorplus_model.ins 235 | 236 | ### 去紫边: void EnableDefringe(bool enable, const std::string& defringe_model_path) 237 | 238 | 这个接口用于消除在录制过程中由于光照出现的紫边现象,如室外强光、室内灯光的场景。 239 | 240 | > 模型路径为:SDK_ROOT/modelfile/defringe_hr_dynamic_7b56e80f.ins 241 | 242 | ### 去频闪: void EnableDeflicker(bool enable, const std::string& deflicker_model_path) 243 | 244 | 这个接口用于消除在录制过程中由于光照出现的屏闪问题。 245 | 246 | >模型路径为:SDK_ROOT/modelfile/deflicker_86ccba0d.ins 247 | 248 | ## 拼接流程 249 | 250 | ### 拼接进度回调: void SetStitchStateCallback(stitch\_error\_callback callback) 251 | 252 | 这个接口主要用于拼接状态和进度信息的通知, 使用方法如下. 同时建议不能在这个回调中使用耗时的操作,这样会影响到拼接速度. 253 | 254 | ```C++ 255 | video_stitcher->SetStitchProgressCallback([&](int process, int error) { 256 | if (stitch_progress != process) { 257 | std::cout << "\r"; 258 | std::cout << "process = " << process << "%"; 259 | std::cout << std::flush; 260 | stitch_progress = process; 261 | } 262 | 263 | if (stitch_progress == 100) { 264 | std::cout << std::endl; 265 | std::unique_lock lck(mutex_); 266 | cond_.notify_one(); 267 | is_finisned = true; 268 | } 269 | }); 270 | ``` 271 | 272 | ### 拼接错误回调: void SetStitchProgressCallback(stitch\_process\_callback callback) 273 | 274 | 这个接口用于接收拼接过程中错误信息的返回. 275 | 276 | ```C++ 277 | video_stitcher->SetStitchStateCallback([&](int error, const char* errinfo) { 278 | std::cout << "error: " << errinfo << std::endl; 279 | has_error = true; 280 | cond_.notify_one(); 281 | }); 282 | ``` 283 | 284 | ### 开启拼接: void StartStitch() 285 | 286 | 这个接口开启拼接流程 287 | 288 | 注意在上面的参数设置完成后,才去执行这个接口。不允许在这个接口执行以后,设置上面的参数,参数不生效。 289 | 290 | ### 取消拼接: bool CancelStitch() 291 | 292 | 这个接口中断拼接流程 293 | 294 | ### 获取拼接进度: int GetStitchProgress() const 295 | 296 | 这个接口用于获取拼接进度 297 | 298 | ## 日记功能 299 | 300 | ### 设置日记路径: void SetLogPath(const std::string log\_path) 301 | 302 | 这个接口主要用于设置SDK中的日记路径,可以保存SDK中的日记信息 303 | 304 | ### 设置日记打印等级: void SetLogLevel(InsLogLevel level) 305 | 306 | 这个接口用于设置SDK中日记打印的等级 307 | 308 | ## 硬件编解码加速 309 | 310 | ## 实时流预览拼接 311 | 312 | ### 环境准备 313 | 314 | 相机拼接预览的功能是基于CameraSDK和MediaSDK一起实现的。头文件位于**MediaSDK_ROOT/include/ins_realtime_stitcher.h。** 315 | 316 | **CameraSDK**的主要功能是提供拼接参数、视频数据、防抖数据以及曝光数据。 317 | 318 | **MediaSDK**的主要功能使用cameraSDK提供的参数以及数据进行画面的拼接,生成一个2:1的全景画面。 319 | 320 | ### 预览参数获取和设置 321 | 322 | ```c++ 323 | #include 324 | // 这个接口主要获取mediaSDK需要的参数 325 | //... 326 | // cam为当前相机实例对象 327 | auto preview_param = cam->GetPreviewParam(); 328 | 329 | // 创建拼接实例对象 330 | auto stitcher = std::make_shared(); 331 | 332 | // 设置预览参数给拼接实例对象 333 | ins::CameraInfo camera_info; 334 | camera_info.cameraName = preview_param.camera_name; 335 | camera_info.decode_type = static_cast(preview_param.encode_type); 336 | camera_info.offset = preview_param.offset; 337 | auto window_crop_info = preview_param.crop_info; 338 | camera_info.window_crop_info_.crop_offset_x = window_crop_info.crop_offset_x; 339 | camera_info.window_crop_info_.crop_offset_y = window_crop_info.crop_offset_y; 340 | camera_info.window_crop_info_.dst_width = window_crop_info.dst_width; 341 | camera_info.window_crop_info_.dst_height = window_crop_info.dst_height; 342 | camera_info.window_crop_info_.src_width = window_crop_info.src_width; 343 | camera_info.window_crop_info_.src_height = window_crop_info.src_height; 344 | camera_info.gyro_timestamp = preview_param.gyro_timestamp; 345 | 346 | stitcher->SetCameraInfo(camera_info); 347 | ``` 348 | 349 | ### 预览流原始数据的处理 350 | 351 | ```c++ 352 | // 在cameraSDK中,要使用继承 ins_camera::StreamDelegate 接口才可以实现相机实时数据的获取。 353 | // 可以在通过demo的示例将cameraSDK的实时数据传输给MediaSDK 354 | 355 | class StitchStreamDelegate : public ins_camera::StreamDelegate { 356 | public: 357 | StitchDelegate(const std::shared_ptr& stitcher) :stitcher_(stitcher) { 358 | } 359 | 360 | virtual ~StitchDelegate() { 361 | } 362 | 363 | void OnAudioData(const uint8_t* data, size_t size, int64_t timestamp) override {} 364 | 365 | // 视频数据 366 | void OnVideoData(const uint8_t* data, size_t size, int64_t timestamp, uint8_t streamType, int stream_index) override { 367 | stitcher_->HandleVideoData(data, size, timestamp, streamType, stream_index); 368 | } 369 | 370 | // 防抖数据 371 | void OnGyroData(const std::vector& data) override { 372 | std::vector data_vec(data.size()); 373 | memcpy(data_vec.data(), data.data(), data.size() * sizeof(ins_camera::GyroData)); 374 | stitcher_->HandleGyroData(data_vec); 375 | } 376 | 377 | // 曝光数据 378 | void OnExposureData(const ins_camera::ExposureData& data) override { 379 | ins::ExposureData exposure_data{}; 380 | exposure_data.exposure_time = data.exposure_time; 381 | exposure_data.timestamp = data.timestamp; 382 | stitcher_->HandleExposureData(exposure_data); 383 | } 384 | 385 | private: 386 | std::shared_ptr stitcher_; 387 | }; 388 | ``` 389 | 390 | ### 设置预览参数 391 | 392 | #### 拼接类型 393 | 394 | 参考4.4.1以及4.4.2 395 | 396 | #### 防抖参数 397 | 398 | 参数3 399 | 400 | #### 保护镜 401 | 402 | 参数4.4.4 403 | 404 | #### 输出画面大小 405 | 406 | 对于输出大小,如果不进行设置,输出的大小为当前预览的分辨率 407 | 408 | 如果性能输出帧率,可以降低分辨率大小 409 | 410 | ### 获取拼接好的数据 411 | 412 | 拼接好的数据目前支持的格式是RGBA 413 | 414 | 可以通过设置**SetStitchRealTimeDataCallback** 这个回调接口获取到拼接好的视频画面,建议不要再这个回调里面执行耗时的操作。参考代码如下: 415 | 416 | ```c++ 417 | stitcher->SetStitchRealTimeDataCallback([&](uint8_t* data[4], int linesize[4], int width, int height, int format, int64_t timestamp) { 418 | show_image_ = cv::Mat(height, width, CV_8UC4, data[0]).clone(); 419 | }); 420 | ``` 421 | 422 | ### 开启预览 423 | 424 | ```c++ 425 | // 设置相机实时数据的委托接口 426 | std::shared_ptr delegate = std::make_shared(stitcher); 427 | cam->SetStreamDelegate(delegate); 428 | ins_camera::LiveStreamParam param; 429 | //... 430 | // 开启相机的预览 431 | if (cam->StartLiveStreaming(param)) { 432 | // 开启拼接流程 433 | stitcher->StartStitch(); 434 | std::cout << "successfully started live stream" << std::endl; 435 | } 436 | ``` 437 | 438 | ### 关闭预览 439 | 440 | ```c++ 441 | //关闭相机预览流 442 | if (cam->StopLiveStreaming()) { 443 | // 停止拼接流程 444 | stitcher->CancelStitch(); 445 | std::cout << "success!" << std::endl; 446 | } 447 | ``` 448 | 449 | ## 错误码 450 | 451 | | 错误码 | 错误信息 | 452 | | ---------------------------- | --------------- | 453 | | E\_OPEN\_FILE(1) | 打开文件失败 | 454 | | E\_PARSE\_METADATA(2) | 解析文件尾失败 | 455 | | E\_CREATE\_OFFSCREEN(3) | 常见离屏渲染失败 | 456 | | E\_CREATE\_RENDER\_MODEL(4) | 创建渲染模型失败 | 457 | | E\_FRAME\_PARSE(5) | 获取数据帧失败 | 458 | | E\_CREATE\_RENDER\_SOURCE(6) | 创建渲染数据源失败 | 459 | | E\_UPDATE\_RENDER\_SOURCE(7) | 更新数据帧到渲染源失败 | 460 | | E\_RENDER\_FRAME(7) | 渲染数据失败 | 461 | | E\_SAVE\_FRAME(8) | 保存图片失败 | 462 | | E\_VIDEO\_FRAME\_EXPORTOR(9) | 创建视频提取器失败 | 463 | | E\_UNKNOWN(999) | 未知信息,需要提供详细信息分析 | 464 | 465 | --------------------------------------------------------------------------------