export.cpp 16 KB

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