export.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. #include "export.h"
  2. #include "device_audios.h"
  3. #include "encoder_video_define.h"
  4. #include "encoder_video.h"
  5. #include "encoder_aac.h"
  6. #include "record_audio_factory.h"
  7. #include "record_desktop_factory.h"
  8. #include "muxer_define.h"
  9. #include "muxer_ffmpeg.h"
  10. #include "remuxer_ffmpeg.h"
  11. #include "error_define.h"
  12. #include "log_helper.h"
  13. #include "utils_string.h"
  14. #include "performance_monitor.h"
  15. #ifdef _WIN32
  16. #include "system_version.h"
  17. #endif
  18. #include <atomic>
  19. #include <mutex>
  20. #include <string>
  21. #define USE_DSHOW 0
  22. namespace am {
  23. typedef std::lock_guard<std::mutex> lock_guard;
  24. static const double scaled_vals[]
  25. = {1.0, 1.25, (1.0 / 0.75), 1.5, (1.0 / 0.6), 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 0.0};
  26. class recorder
  27. {
  28. private:
  29. recorder();
  30. ~recorder();
  31. public:
  32. static recorder *instance();
  33. static void release();
  34. int init(const AMRECORDER_SETTING &setting, const AMRECORDER_CALLBACK &callbacks);
  35. int start();
  36. void stop();
  37. int pause();
  38. int resume();
  39. void set_preview_enabled(bool enable);
  40. // Expose underlying encoders for diagnostics
  41. encoder_video* get_video_encoder();
  42. encoder_aac* get_audio_encoder();
  43. // 性能监控接口
  44. std::string getPerformanceReport() const;
  45. void resetPerformanceStats();
  46. private:
  47. void on_preview_yuv(const uint8_t *data, int size, int width, int height, int type);
  48. void get_valid_out_resolution(int src_width, int src_height, int *out_width, int *out_height);
  49. private:
  50. AMRECORDER_SETTING _setting;
  51. AMRECORDER_CALLBACK _callbacks;
  52. record_audio *_recorder_speaker;
  53. record_audio *_recorder_mic;
  54. record_desktop *_recorder_desktop;
  55. muxer_file *_muxer;
  56. PerformanceMonitor *_perf_monitor; // 性能监控器
  57. std::atomic_bool _inited;
  58. std::mutex _mutex;
  59. };
  60. static recorder *_g_instance = nullptr;
  61. static std::mutex _g_mutex;
  62. recorder::recorder()
  63. {
  64. memset(&_setting, 0, sizeof(_setting));
  65. memset(&_callbacks, 0, sizeof(_callbacks));
  66. _recorder_speaker = nullptr;
  67. _recorder_mic = nullptr;
  68. _recorder_desktop = nullptr;
  69. _inited = false;
  70. _muxer = nullptr;
  71. _perf_monitor = new PerformanceMonitor(); // 初始化性能监控器
  72. }
  73. recorder::~recorder()
  74. {
  75. if (_muxer)
  76. delete _muxer;
  77. if (_recorder_desktop)
  78. delete _recorder_desktop;
  79. if (_recorder_mic)
  80. delete _recorder_mic;
  81. if (_recorder_speaker)
  82. delete _recorder_speaker;
  83. if (_perf_monitor)
  84. delete _perf_monitor; // 清理性能监控器
  85. }
  86. recorder *recorder::instance()
  87. {
  88. lock_guard lock(_g_mutex);
  89. if (_g_instance == nullptr)
  90. _g_instance = new recorder();
  91. return _g_instance;
  92. }
  93. void recorder::release()
  94. {
  95. lock_guard lock(_g_mutex);
  96. if (_g_instance)
  97. delete _g_instance;
  98. _g_instance = nullptr;
  99. }
  100. int recorder::init(const AMRECORDER_SETTING &setting, const AMRECORDER_CALLBACK &callbacks)
  101. {
  102. lock_guard lock(_mutex);
  103. if (_inited == true)
  104. return AE_NO;
  105. int error = AE_NO;
  106. int audio_num = 0;
  107. _setting = setting;
  108. _callbacks = callbacks;
  109. am::record_audio *audios[2] = {0};
  110. #if USE_DSHOW
  111. error = record_audio_new(RECORD_AUDIO_TYPES::AT_AUDIO_DSHOW, &_recorder_speaker);
  112. AMERROR_CHECK(error);
  113. error = _recorder_speaker->init("audio=virtual-audio-capturer",
  114. "audio=virtual-audio-capturer",
  115. false);
  116. AMERROR_CHECK(error);
  117. error = record_audio_new(RECORD_AUDIO_TYPES::AT_AUDIO_DSHOW, &_recorder_mic);
  118. AMERROR_CHECK(error);
  119. error = _recorder_mic->init(std::string("audio=") + std::string(setting.a_mic.name),
  120. std::string("audio=") + std::string(setting.a_mic.name),
  121. true);
  122. AMERROR_CHECK(error);
  123. audios = {_recorder_speaker, _recorder_mic};
  124. #else
  125. if (utils_string::utf8_ascii(setting.a_speaker.name).length()
  126. && utils_string::utf8_ascii(setting.a_speaker.id).length()) {
  127. error = record_audio_new(RECORD_AUDIO_TYPES::AT_AUDIO_WAS, &_recorder_speaker);
  128. AMERROR_CHECK(error);
  129. error = _recorder_speaker->init(setting.a_speaker.name, setting.a_speaker.id, false);
  130. AMERROR_CHECK(error);
  131. audios[audio_num] = _recorder_speaker;
  132. audio_num++;
  133. }
  134. if (utils_string::utf8_ascii(setting.a_mic.name).length()
  135. && utils_string::utf8_ascii(setting.a_mic.id).length()) {
  136. error = record_audio_new(RECORD_AUDIO_TYPES::AT_AUDIO_WAS, &_recorder_mic);
  137. AMERROR_CHECK(error);
  138. error = _recorder_mic->init(setting.a_mic.name, setting.a_mic.id, true);
  139. AMERROR_CHECK(error);
  140. audios[audio_num] = _recorder_mic;
  141. audio_num++;
  142. }
  143. #endif
  144. #ifdef _WIN32
  145. #if USE_MAG
  146. if (_recorder_desktop == nullptr) {
  147. error = record_desktop_new(RECORD_DESKTOP_TYPES::DT_DESKTOP_WIN_MAG, &_recorder_desktop);
  148. if (error == AE_NO) {
  149. error = _recorder_desktop->init({setting.v_left,
  150. setting.v_top,
  151. setting.v_width + setting.v_left,
  152. setting.v_height + setting.v_top},
  153. setting.v_frame_rate);
  154. if (error != AE_NO)
  155. record_desktop_destroy(&_recorder_desktop);
  156. }
  157. }
  158. #endif
  159. // windows support wgc since win10.1803
  160. if (_recorder_desktop == nullptr && system_version::is_win10_or_above(17134)) {
  161. error = record_desktop_new(RECORD_DESKTOP_TYPES::DT_DESKTOP_WIN_WGC, &_recorder_desktop);
  162. if (error == AE_NO) {
  163. error = _recorder_desktop->init({setting.v_left,
  164. setting.v_top,
  165. setting.v_width + setting.v_left,
  166. setting.v_height + setting.v_top},
  167. setting.v_frame_rate);
  168. if (error != AE_NO)
  169. record_desktop_destroy(&_recorder_desktop);
  170. }
  171. }
  172. if (_recorder_desktop == nullptr && system_version::is_win8_or_above()) {
  173. error = record_desktop_new(RECORD_DESKTOP_TYPES::DT_DESKTOP_WIN_DUPLICATION,
  174. &_recorder_desktop);
  175. if (error == AE_NO) {
  176. error = _recorder_desktop->init({setting.v_left,
  177. setting.v_top,
  178. setting.v_width + setting.v_left,
  179. setting.v_height + setting.v_top},
  180. setting.v_frame_rate);
  181. if (error != AE_NO)
  182. record_desktop_destroy(&_recorder_desktop);
  183. }
  184. }
  185. if (_recorder_desktop == nullptr) {
  186. error = record_desktop_new(RECORD_DESKTOP_TYPES::DT_DESKTOP_WIN_GDI, &_recorder_desktop);
  187. AMERROR_CHECK(error);
  188. error = _recorder_desktop->init({setting.v_left,
  189. setting.v_top,
  190. setting.v_width + setting.v_left,
  191. setting.v_height + setting.v_top},
  192. setting.v_frame_rate);
  193. AMERROR_CHECK(error);
  194. }
  195. #endif // _WIN32
  196. am::MUX_SETTING mux_setting;
  197. mux_setting.v_frame_rate = setting.v_frame_rate;
  198. mux_setting.v_bit_rate = setting.v_bit_rate;
  199. mux_setting.v_width = setting.v_width;
  200. mux_setting.v_height = setting.v_height;
  201. mux_setting.v_qb = setting.v_qb;
  202. mux_setting.v_encoder_id = (am::ENCODER_VIDEO_ID) setting.v_enc_id;
  203. get_valid_out_resolution(setting.v_width,
  204. setting.v_height,
  205. &mux_setting.v_out_width,
  206. &mux_setting.v_out_height);
  207. mux_setting.a_nb_channel = 2;
  208. mux_setting.a_sample_fmt = AV_SAMPLE_FMT_FLTP;
  209. mux_setting.a_sample_rate = 44100;
  210. mux_setting.a_bit_rate = 128000;
  211. _muxer = new muxer_ffmpeg();
  212. _muxer->registe_yuv_data(std::bind(&recorder::on_preview_yuv,
  213. this,
  214. std::placeholders::_1,
  215. std::placeholders::_2,
  216. std::placeholders::_3,
  217. std::placeholders::_4,
  218. std::placeholders::_5));
  219. error = _muxer->init(setting.output, _recorder_desktop, audios, audio_num, mux_setting);
  220. AMERROR_CHECK(error);
  221. _inited = true;
  222. return error;
  223. }
  224. int recorder::start()
  225. {
  226. lock_guard lock(_mutex);
  227. if (_inited == false)
  228. return AE_NEED_INIT;
  229. int error = _muxer->start();
  230. return error;
  231. }
  232. void recorder::stop()
  233. {
  234. lock_guard lock(_mutex);
  235. if (_inited == false)
  236. return;
  237. _muxer->stop();
  238. }
  239. int recorder::pause()
  240. {
  241. lock_guard lock(_mutex);
  242. if (_inited == false)
  243. return AE_NEED_INIT;
  244. return _muxer->pause();
  245. }
  246. int recorder::resume()
  247. {
  248. lock_guard lock(_mutex);
  249. if (_inited == false)
  250. return AE_NEED_INIT;
  251. return _muxer->resume();
  252. }
  253. void recorder::set_preview_enabled(bool enable)
  254. {
  255. lock_guard lock(_mutex);
  256. if (_inited == false)
  257. return;
  258. _muxer->set_preview_enabled(enable);
  259. }
  260. encoder_video* recorder::get_video_encoder()
  261. {
  262. lock_guard lock(_mutex);
  263. if (!_inited || _muxer == nullptr)
  264. return nullptr;
  265. auto mf = dynamic_cast<muxer_ffmpeg*>(_muxer);
  266. if (!mf) return nullptr;
  267. return mf->get_video_encoder();
  268. }
  269. encoder_aac* recorder::get_audio_encoder()
  270. {
  271. lock_guard lock(_mutex);
  272. if (!_inited || _muxer == nullptr)
  273. return nullptr;
  274. auto mf = dynamic_cast<muxer_ffmpeg*>(_muxer);
  275. if (!mf) return nullptr;
  276. return mf->get_audio_encoder();
  277. }
  278. void recorder::on_preview_yuv(const uint8_t *data, int size, int width, int height, int type)
  279. {
  280. if (_callbacks.func_preview_yuv != NULL)
  281. _callbacks.func_preview_yuv(data, size, width, height, type);
  282. }
  283. void recorder::get_valid_out_resolution(int src_width,
  284. int src_height,
  285. int *out_width,
  286. int *out_height)
  287. {
  288. int scale_cx = src_width;
  289. int scale_cy = src_height;
  290. int i = 0;
  291. while (((scale_cx * scale_cy) > (1920 * 1080)) && scaled_vals[i] > 0.0) {
  292. double scale = scaled_vals[i++];
  293. scale_cx = uint32_t(double(src_width) / scale);
  294. scale_cy = uint32_t(double(src_height) / scale);
  295. }
  296. if (scale_cx % 2 != 0) {
  297. scale_cx += 1;
  298. }
  299. if (scale_cy % 2 != 0) {
  300. scale_cy += 1;
  301. }
  302. *out_width = scale_cx;
  303. *out_height = scale_cy;
  304. al_info("get valid output resolution from %dx%d to %dx%d,with scale:%lf",
  305. src_width,
  306. src_height,
  307. scale_cx,
  308. scale_cy,
  309. scaled_vals[i]);
  310. }
  311. // 性能监控接口实现
  312. std::string recorder::getPerformanceReport() const
  313. {
  314. if (_perf_monitor) {
  315. return _perf_monitor->getPerformanceReport();
  316. }
  317. return "性能监控器未初始化";
  318. }
  319. void recorder::resetPerformanceStats()
  320. {
  321. if (_perf_monitor) {
  322. _perf_monitor->reset();
  323. }
  324. }
  325. } // namespace am
  326. AMRECORDER_API const char *recorder_err2str(int error)
  327. {
  328. return am::utils_string::ascii_utf8(err2str(error)).c_str();
  329. }
  330. AMRECORDER_API int recorder_init(const AMRECORDER_SETTING &setting,
  331. const AMRECORDER_CALLBACK &callbacks)
  332. {
  333. return am::recorder::instance()->init(setting, callbacks);
  334. }
  335. AMRECORDER_API void recorder_release()
  336. {
  337. return am::recorder::instance()->release();
  338. }
  339. AMRECORDER_API int recorder_start()
  340. {
  341. return am::recorder::instance()->start();
  342. }
  343. AMRECORDER_API void recorder_stop()
  344. {
  345. return am::recorder::instance()->stop();
  346. }
  347. AMRECORDER_API int recorder_pause()
  348. {
  349. return am::recorder::instance()->pause();
  350. }
  351. AMRECORDER_API int recorder_resume()
  352. {
  353. return am::recorder::instance()->resume();
  354. }
  355. AMRECORDER_API int recorder_get_speakers(AMRECORDER_DEVICE **devices)
  356. {
  357. std::list<am::DEVICE_AUDIOS> device_list;
  358. int error = am::device_audios::get_output_devices(device_list);
  359. if (error != AE_NO)
  360. return -error;
  361. int count = device_list.size();
  362. *devices = new AMRECORDER_DEVICE[count];
  363. int index = 0;
  364. for each (auto device in device_list) {
  365. al_info("audio input name:%s id:%s", device.name.c_str(), device.id.c_str());
  366. (*devices)[index].is_default = device.is_default;
  367. sprintf_s((*devices)[index].id, 260, "%s", device.id.c_str());
  368. sprintf_s((*devices)[index].name, 260, "%s", device.name.c_str());
  369. index++;
  370. }
  371. return count;
  372. }
  373. AMRECORDER_API int recorder_get_mics(AMRECORDER_DEVICE **devices)
  374. {
  375. std::list<am::DEVICE_AUDIOS> device_list;
  376. int error = am::device_audios::get_input_devices(device_list);
  377. if (error != AE_NO)
  378. return -error;
  379. int count = device_list.size();
  380. *devices = new AMRECORDER_DEVICE[count];
  381. int index = 0;
  382. for each (auto device in device_list) {
  383. al_info("audio output name:%s id:%s", device.name.c_str(), device.id.c_str());
  384. (*devices)[index].is_default = device.is_default;
  385. sprintf_s((*devices)[index].id, 260, "%s", device.id.c_str());
  386. sprintf_s((*devices)[index].name, 260, "%s", device.name.c_str());
  387. index++;
  388. }
  389. return count;
  390. }
  391. AMRECORDER_API int recorder_get_cameras(AMRECORDER_DEVICE **devices)
  392. {
  393. return -AE_UNSUPPORT;
  394. }
  395. AMRECORDER_API int recorder_get_vencoders(AMRECORDER_ENCODERS **encoders)
  396. {
  397. auto hw_encoders = am::hardware_acceleration::get_supported_video_encoders();
  398. int count = hw_encoders.size() + 1;
  399. *encoders = new AMRECORDER_ENCODERS[count];
  400. AMRECORDER_ENCODERS *ptr = *encoders;
  401. ptr->id = am::EID_VIDEO_X264;
  402. sprintf_s(ptr->name, 260, am::utils_string::ascii_utf8("Soft.X264").c_str());
  403. for each (auto hw_encoder in hw_encoders) {
  404. ptr++;
  405. ptr->id = hw_encoder.type;
  406. sprintf_s(ptr->name, 260, "%s", hw_encoder.name);
  407. }
  408. return count;
  409. }
  410. AMRECORDER_API void recorder_free_array(void *array_address)
  411. {
  412. if (array_address != nullptr)
  413. delete[] array_address;
  414. }
  415. AMRECORDER_API int recorder_remux(const char *src,
  416. const char *dst,
  417. AMRECORDER_FUNC_REMUX_PROGRESS func_progress,
  418. AMRECORDER_FUNC_REMUX_STATE func_state)
  419. {
  420. am::REMUXER_PARAM param = {0};
  421. sprintf_s(param.src, 260, "%s", am::utils_string::utf8_ascii(src).c_str());
  422. sprintf_s(param.dst, 260, "%s", am::utils_string::utf8_ascii(dst).c_str());
  423. param.cb_progress = func_progress;
  424. param.cb_state = func_state;
  425. return am::remuxer_ffmpeg::instance()->create_remux(param);
  426. }
  427. AMRECORDER_API void recorder_set_preview_enabled(int enable)
  428. {
  429. am::recorder::instance()->set_preview_enabled(enable == 1);
  430. }
  431. AMRECORDER_API void recorder_set_logpath(const char *path)
  432. {
  433. AMLog *log = AMLog::get(path);
  434. }
  435. // ================= Ring buffer diagnostics =================
  436. AMRECORDER_API uint64_t recorder_get_video_rb_dropped()
  437. {
  438. auto enc = am::recorder::instance()->get_video_encoder();
  439. if (!enc) return 0;
  440. return enc->rb_dropped_frames();
  441. }
  442. AMRECORDER_API int recorder_get_video_rb_pending()
  443. {
  444. auto enc = am::recorder::instance()->get_video_encoder();
  445. if (!enc) return 0;
  446. return enc->rb_pending_frames();
  447. }
  448. AMRECORDER_API int recorder_get_video_rb_max()
  449. {
  450. auto enc = am::recorder::instance()->get_video_encoder();
  451. if (!enc) return 0;
  452. return enc->rb_max_frames();
  453. }
  454. AMRECORDER_API void recorder_set_video_rb_max(int max_frames)
  455. {
  456. auto enc = am::recorder::instance()->get_video_encoder();
  457. if (!enc) return;
  458. enc->rb_set_max_frames(max_frames);
  459. }
  460. AMRECORDER_API void recorder_reset_video_rb_dropped()
  461. {
  462. auto enc = am::recorder::instance()->get_video_encoder();
  463. if (!enc) return;
  464. enc->rb_reset_dropped();
  465. }
  466. AMRECORDER_API uint64_t recorder_get_audio_rb_dropped()
  467. {
  468. auto enc = am::recorder::instance()->get_audio_encoder();
  469. if (!enc) return 0;
  470. return enc->rb_dropped_frames();
  471. }
  472. AMRECORDER_API int recorder_get_audio_rb_pending()
  473. {
  474. auto enc = am::recorder::instance()->get_audio_encoder();
  475. if (!enc) return 0;
  476. return enc->rb_pending_frames();
  477. }
  478. AMRECORDER_API int recorder_get_audio_rb_max()
  479. {
  480. auto enc = am::recorder::instance()->get_audio_encoder();
  481. if (!enc) return 0;
  482. return enc->rb_max_frames();
  483. }
  484. AMRECORDER_API void recorder_set_audio_rb_max(int max_frames)
  485. {
  486. auto enc = am::recorder::instance()->get_audio_encoder();
  487. if (!enc) return;
  488. enc->rb_set_max_frames(max_frames);
  489. }
  490. AMRECORDER_API void recorder_reset_audio_rb_dropped()
  491. {
  492. auto enc = am::recorder::instance()->get_audio_encoder();
  493. if (!enc) return;
  494. enc->rb_reset_dropped();
  495. } // namespace am 结束
  496. // 导出性能监控API
  497. AMRECORDER_API const char* recorder_get_performance_report()
  498. {
  499. static std::string report;
  500. report = am::recorder::instance()->getPerformanceReport();
  501. return report.c_str();
  502. }
  503. AMRECORDER_API void recorder_reset_performance_stats()
  504. {
  505. am::recorder::instance()->resetPerformanceStats();
  506. }