luat_lib_multimedia.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /*
  2. @module multimedia
  3. @summary 多媒体
  4. @version 1.0
  5. @date 2022.03.11
  6. */
  7. #include "luat_base.h"
  8. #include "luat_multimedia.h"
  9. #include "luat_msgbus.h"
  10. #include "luat_zbuff.h"
  11. #define LUAT_LOG_TAG "multimedia"
  12. #include "luat_log.h"
  13. #include <stddef.h>
  14. #include "mp3_decode/minimp3.h"
  15. typedef struct
  16. {
  17. union
  18. {
  19. mp3dec_t *mp3_decoder;
  20. };
  21. uint8_t type;
  22. uint8_t is_decoder;
  23. }luat_multimedia_codec_t;
  24. #define MAX_DEVICE_COUNT 2
  25. typedef struct luat_multimedia_cb {
  26. int function_ref;
  27. } luat_multimedia_cb_t;
  28. static luat_multimedia_cb_t multimedia_cbs[MAX_DEVICE_COUNT];
  29. int l_multimedia_raw_handler(lua_State *L, void* ptr) {
  30. rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
  31. lua_pop(L, 1);
  32. if (multimedia_cbs[msg->arg2].function_ref) {
  33. lua_geti(L, LUA_REGISTRYINDEX, multimedia_cbs[msg->arg2].function_ref);
  34. if (lua_isfunction(L, -1)) {
  35. lua_pushinteger(L, msg->arg2);
  36. lua_pushinteger(L, msg->arg1);
  37. lua_call(L, 2, 0);
  38. }
  39. }
  40. lua_pushinteger(L, 0);
  41. return 1;
  42. }
  43. /*
  44. 启动一个多媒体通道准备播放音频
  45. @api audio.start(id, audio_format, num_channels, sample_rate, bits_per_sample, is_signed)
  46. @int 多媒体播放通道号,0或者1
  47. @int 音频格式
  48. @int 声音通道数
  49. @int 采样频率
  50. @int 采样位数
  51. @boolean 是否有符号,默认true
  52. @return boolean 成功true, 失败false
  53. @usage
  54. audio.start(0, audio.PCM, 1, 16000, 16)
  55. */
  56. static int l_audio_start_raw(lua_State *L){
  57. int multimedia_id = luaL_checkinteger(L, 1);
  58. int audio_format = luaL_checkinteger(L, 2);
  59. int num_channels= luaL_checkinteger(L, 3);
  60. int sample_rate = luaL_checkinteger(L, 4);
  61. int bits_per_sample = luaL_checkinteger(L, 5);
  62. int is_signed = 1;
  63. if (lua_isboolean(L, 6))
  64. {
  65. is_signed = lua_toboolean(L, 6);
  66. }
  67. lua_pushboolean(L, !luat_audio_start_raw(multimedia_id, audio_format, num_channels, sample_rate, bits_per_sample, is_signed));
  68. return 1;
  69. }
  70. /**
  71. 往一个多媒体通道写入音频数据
  72. @api audio.write(id, data)
  73. @string or zbuff 音频数据
  74. @return boolean 成功返回true,否则返回false
  75. @usage
  76. audio.write(0, "xxxxxx")
  77. */
  78. static int l_audio_write_raw(lua_State *L) {
  79. int multimedia_id = luaL_checkinteger(L, 1);
  80. size_t len;
  81. uint8_t *buf;
  82. if(lua_isuserdata(L, 2))
  83. {
  84. luat_zbuff_t *buff = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
  85. len = buff->used;
  86. buf = (const char *)(buff->addr);
  87. }
  88. else
  89. {
  90. buf = lua_tolstring(L, 2, &len);//取出字符串数据
  91. }
  92. lua_pushboolean(L, !luat_audio_write_raw(multimedia_id, buf, len));
  93. return 1;
  94. }
  95. /**
  96. 停止指定的多媒体通道
  97. @api audio.stop(id)
  98. @int audio id,例如0
  99. @return boolean 成功返回true,否则返回false
  100. @usage
  101. audio.stop(0)
  102. */
  103. static int l_audio_stop_raw(lua_State *L) {
  104. lua_pushboolean(L, !luat_audio_stop_raw(luaL_checkinteger(L, 1)));
  105. return 1;
  106. }
  107. /**
  108. 暂停/恢复指定的多媒体通道
  109. @api audio.pause(id, pause)
  110. @int audio id,例如0
  111. @boolean onoff true 暂停,false 恢复
  112. @return boolean 成功返回true,否则返回false
  113. @usage
  114. audio.pause(0, true) --暂停通道0
  115. audio.pause(0, false) --恢复通道0
  116. */
  117. static int l_audio_pause_raw(lua_State *L) {
  118. lua_pushboolean(L, !luat_audio_pause_raw(luaL_checkinteger(L, 1), lua_toboolean(L, 2)));
  119. return 1;
  120. }
  121. /*
  122. 注册audio播放事件回调
  123. @api audio.on(id, event, func)
  124. @int audio id, audio 0写0, audio 1写1
  125. @function 回调方法
  126. @return nil 无返回值
  127. @usage
  128. camera.on(0, function(id, str)
  129. print(id, str)
  130. end)
  131. */
  132. static int l_audio_raw_on(lua_State *L) {
  133. int multimedia_id = luaL_checkinteger(L, 1);
  134. if (multimedia_cbs[multimedia_id].function_ref != 0) {
  135. luaL_unref(L, LUA_REGISTRYINDEX, multimedia_cbs[multimedia_id].function_ref);
  136. multimedia_cbs[multimedia_id].function_ref = 0;
  137. }
  138. if (lua_isfunction(L, 2)) {
  139. lua_pushvalue(L, 2);
  140. multimedia_cbs[multimedia_id].function_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  141. }
  142. return 0;
  143. }
  144. /**
  145. 创建编解码用的codec
  146. @api codec.create(codec.MP3)
  147. @int 多媒体类型,目前支持decode.MP3
  148. @boolean 是否是编码器,默认true,是解码器
  149. @return userdata 成功返回一个数据结构,否则返回nil
  150. @usage
  151. -- 创建decoder
  152. local decoder = codec.create(codec.MP3)--创建一个mp3的decoder
  153. */
  154. static int l_codec_create(lua_State *L) {
  155. uint8_t type = luaL_optinteger(L, 1, MULTIMEDIA_DATA_TYPE_MP3);
  156. uint8_t is_decoder = 1;
  157. if (lua_isboolean(L, 2)) {
  158. is_decoder = lua_toboolean(L, 2);
  159. }
  160. luat_multimedia_codec_t *coder = (luat_multimedia_codec_t *)lua_newuserdata(L, sizeof(luat_multimedia_codec_t));
  161. if (coder == NULL) {
  162. lua_pushnil(L);
  163. } else {
  164. coder->type = type;
  165. coder->is_decoder = is_decoder;
  166. if (is_decoder)
  167. {
  168. switch (type) {
  169. case MULTIMEDIA_DATA_TYPE_MP3:
  170. coder->mp3_decoder = luat_heap_malloc(sizeof(mp3dec_t));
  171. if (!coder->mp3_decoder) {
  172. lua_pushnil(L);
  173. }
  174. break;
  175. }
  176. }
  177. }
  178. return 1;
  179. }
  180. /**
  181. decoder从文件数据中解析出音频信息
  182. @api codec.get_audio_info(decoder, data)
  183. @coder 解码用的decoder
  184. @string 文件数据,必须是开头的数据
  185. @return
  186. @boolean 是否成功解析
  187. @int 音频格式
  188. @int 声音通道数
  189. @int 采样频率
  190. @int 采样位数
  191. @boolean 是否有符号
  192. @usage
  193. local result, audio_format, num_channels, sample_rate, bits_per_sample, is_signed= codec.get_audio_info(coder, "xxx")
  194. */
  195. static int l_codec_get_audio_info(lua_State *L) {
  196. luat_multimedia_codec_t *coder = (luat_multimedia_codec_t *)lua_touserdata(L, 1);
  197. int result = 0;
  198. int audio_format;
  199. int num_channels;
  200. int sample_rate;
  201. int bits_per_sample = 16;
  202. int is_signed = 1;
  203. size_t len;
  204. mp3dec_frame_info_t info;
  205. const char *data = luaL_checklstring(L, 2, &len);
  206. if (coder)
  207. {
  208. switch(coder->type)
  209. {
  210. case MULTIMEDIA_DATA_TYPE_MP3:
  211. mp3dec_init(coder->mp3_decoder);
  212. result = mp3dec_decode_frame(coder->mp3_decoder, data, len, NULL, &info);
  213. memset(coder->mp3_decoder, 0, sizeof(mp3dec_t));
  214. audio_format = MULTIMEDIA_DATA_TYPE_PCM;
  215. num_channels = info.channels;
  216. sample_rate = info.hz;
  217. break;
  218. default:
  219. break;
  220. }
  221. }
  222. lua_pushboolean(L, result);
  223. lua_pushinteger(L, audio_format);
  224. lua_pushinteger(L, num_channels);
  225. lua_pushinteger(L, sample_rate);
  226. lua_pushinteger(L, bits_per_sample);
  227. lua_pushboolean(L, is_signed);
  228. return 6;
  229. }
  230. /**
  231. decoder从文件数据中解析出音频数据
  232. @api codec.get_audio_data(decoder, in_buff, out_buff)
  233. @coder 解码用的decoder
  234. @zbuff 存放输入数据的zbuff
  235. @zbuff 存放输出数据的zbuff,空间必须不少于16KB
  236. @boolean后续有没有新数据,false表示没有了
  237. @return
  238. @boolean 是否成功解析
  239. @usage
  240. local result = codec.get_audio_data(coder, "xxx", zbuff)
  241. */
  242. static int l_codec_get_audio_data(lua_State *L) {
  243. luat_multimedia_codec_t *coder = (luat_multimedia_codec_t *)lua_touserdata(L, 1);
  244. uint32_t pos = 0;
  245. int result;
  246. luat_zbuff_t *in_buff = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
  247. luat_zbuff_t *out_buff = ((luat_zbuff_t *)luaL_checkudata(L, 3, LUAT_ZBUFF_TYPE));
  248. uint32_t is_not_end = 1;
  249. if (lua_isboolean(L, 4))
  250. {
  251. is_not_end = lua_toboolean(L, 4);
  252. }
  253. mp3dec_frame_info_t info;
  254. out_buff->used = 0;
  255. if (coder)
  256. {
  257. switch(coder->type)
  258. {
  259. case MULTIMEDIA_DATA_TYPE_MP3:
  260. do
  261. {
  262. memset(&info, 0, sizeof(info));
  263. result = mp3dec_decode_frame(coder->mp3_decoder, in_buff->addr + pos, in_buff->used - pos, out_buff->addr + out_buff->used, &info);
  264. // LLOGD("111 %u,%u,%u,%u,%u", result, info.frame_bytes, info.hz, info.layer, in_buff->used - pos);
  265. out_buff->used += (result * info.channels * 2);
  266. if (!result) {
  267. LLOGD("jump %dbyte", info.frame_bytes);
  268. }
  269. pos += info.frame_bytes;
  270. if ((out_buff->len - out_buff->used) < (MINIMP3_MAX_SAMPLES_PER_FRAME * 2))
  271. {
  272. __zbuff_resize(out_buff, out_buff->len * 2);
  273. }
  274. } while ((in_buff->used - pos) >= (MINIMP3_MAX_SAMPLES_PER_FRAME * is_not_end + 1));
  275. // LLOGD("result %u,%u,%u,%u", result, in_buff->used, pos, info.frame_bytes);
  276. if (pos >= in_buff->used)
  277. {
  278. in_buff->used = 0;
  279. }
  280. else
  281. {
  282. memmove(in_buff->addr, in_buff->addr + pos, in_buff->used - pos);
  283. in_buff->used -= pos;
  284. }
  285. break;
  286. default:
  287. break;
  288. }
  289. }
  290. lua_pushboolean(L, result);
  291. return 1;
  292. }
  293. /**
  294. 释放编解码用的coder
  295. @api codec.release(coder)
  296. @return
  297. codec.release(coder)
  298. */
  299. static int l_codec_release(lua_State *L) {
  300. luat_multimedia_codec_t *coder = (luat_multimedia_codec_t *)lua_touserdata(L, 1);
  301. if (coder) {
  302. switch(coder->type) {
  303. case MULTIMEDIA_DATA_TYPE_MP3:
  304. if (coder->is_decoder) {
  305. luat_heap_free(coder->mp3_decoder);
  306. }
  307. break;
  308. }
  309. } else {
  310. luaL_error(L, "no codec");
  311. }
  312. return 0;
  313. }
  314. #include "rotable2.h"
  315. static const rotable_Reg_t reg_audio[] =
  316. {
  317. { "start" , ROREG_FUNC(l_audio_start_raw)},
  318. { "write" , ROREG_FUNC(l_audio_write_raw)},
  319. { "pause", ROREG_FUNC(l_audio_pause_raw)},
  320. { "stop", ROREG_FUNC(l_audio_stop_raw)},
  321. { "on", ROREG_FUNC(l_audio_raw_on)},
  322. { "PCM", ROREG_INT(MULTIMEDIA_DATA_TYPE_PCM)},
  323. { "MORE_DATA", ROREG_INT(MULTIMEDIA_CB_AUDIO_NEED_DATA)},
  324. { "DONE", ROREG_INT(MULTIMEDIA_CB_AUDIO_DONE)},
  325. { NULL, {}}
  326. };
  327. static const rotable_Reg_t reg_codec[] =
  328. {
  329. { "create" , ROREG_FUNC(l_codec_create)},
  330. { "get_audio_info" , ROREG_FUNC(l_codec_get_audio_info)},
  331. { "get_audio_data", ROREG_FUNC(l_codec_get_audio_data)},
  332. { "release", ROREG_FUNC(l_codec_release)},
  333. { "MP3", ROREG_INT(MULTIMEDIA_DATA_TYPE_MP3)},
  334. { NULL, {}}
  335. };
  336. LUAMOD_API int luaopen_multimedia_audio( lua_State *L ) {
  337. luat_newlib2(L, reg_audio);
  338. return 1;
  339. }
  340. LUAMOD_API int luaopen_multimedia_codec( lua_State *L ) {
  341. luat_newlib2(L, reg_codec);
  342. return 1;
  343. }