export.cpp 14 KB

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