export.cpp 12 KB

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