luat_lib_multimedia_codec.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /*
  2. @module codec
  3. @summary 多媒体-编解码
  4. @version 1.0
  5. @date 2022.03.11
  6. @demo multimedia
  7. @tag LUAT_USE_MEDIA
  8. */
  9. #include "luat_base.h"
  10. #include "luat_multimedia.h"
  11. #include "luat_msgbus.h"
  12. #include "luat_zbuff.h"
  13. #include "luat_fs.h"
  14. #include "luat_mem.h"
  15. #define LUAT_LOG_TAG "codec"
  16. #include "luat_log.h"
  17. #ifdef LUAT_SUPPORT_AMR
  18. #include "interf_enc.h"
  19. #include "interf_dec.h"
  20. #endif
  21. #ifndef MINIMP3_MAX_SAMPLES_PER_FRAME
  22. #define MINIMP3_MAX_SAMPLES_PER_FRAME (2*1152)
  23. #endif
  24. /**
  25. 创建编解码用的codec
  26. @api codec.create(type, isDecoder)
  27. @int 多媒体类型,目前支持codec.MP3 codec.AMR
  28. @boolean 是否是解码器,true解码器,false编码器,默认true,是解码器
  29. @return userdata 成功返回一个数据结构,否则返回nil
  30. @usage
  31. -- 创建解码器
  32. local decoder = codec.create(codec.MP3)--创建一个mp3的decoder
  33. -- 创建编码器
  34. local encoder = codec.create(codec.AMR, false)--创建一个amr的encoder
  35. */
  36. static int l_codec_create(lua_State *L) {
  37. uint8_t type = luaL_optinteger(L, 1, MULTIMEDIA_DATA_TYPE_MP3);
  38. uint8_t is_decoder = 1;
  39. if (lua_isboolean(L, 2)) {
  40. is_decoder = lua_toboolean(L, 2);
  41. }
  42. luat_multimedia_codec_t *coder = (luat_multimedia_codec_t *)lua_newuserdata(L, sizeof(luat_multimedia_codec_t));
  43. if (coder == NULL) {
  44. lua_pushnil(L);
  45. } else {
  46. memset(coder, 0, sizeof(luat_multimedia_codec_t));
  47. coder->type = type;
  48. coder->is_decoder = is_decoder;
  49. if (is_decoder)
  50. {
  51. switch (type) {
  52. case MULTIMEDIA_DATA_TYPE_MP3:
  53. coder->mp3_decoder = mp3_decoder_create();
  54. if (!coder->mp3_decoder) {
  55. lua_pushnil(L);
  56. return 1;
  57. }
  58. break;
  59. }
  60. }
  61. else
  62. {
  63. switch (type) {
  64. #ifdef LUAT_SUPPORT_AMR
  65. case MULTIMEDIA_DATA_TYPE_AMR_NB:
  66. coder->amr_coder = Encoder_Interface_init(0);
  67. if (!coder->amr_coder) {
  68. lua_pushnil(L);
  69. return 1;
  70. }
  71. break;
  72. #endif
  73. default:
  74. break;
  75. }
  76. }
  77. luaL_setmetatable(L, LUAT_M_CODE_TYPE);
  78. }
  79. return 1;
  80. }
  81. /**
  82. decoder从文件中解析出音频信息
  83. @api codec.info(decoder, file_path)
  84. @userdata 解码用的decoder
  85. @string 文件路径
  86. @return boolean 是否成功解析
  87. @return int 音频格式
  88. @return int 声音通道数
  89. @return int 采样频率
  90. @return int 采样位数
  91. @return boolean 是否有符号
  92. @usage
  93. local result, audio_format, num_channels, sample_rate, bits_per_sample, is_signed= codec.info(coder, "xxx")
  94. */
  95. static int l_codec_get_audio_info(lua_State *L) {
  96. luat_multimedia_codec_t *coder = (luat_multimedia_codec_t *)luaL_checkudata(L, 1, LUAT_M_CODE_TYPE);
  97. uint32_t jump, i;
  98. uint8_t temp[16];
  99. int result = 0;
  100. int audio_format = MULTIMEDIA_DATA_TYPE_NONE;
  101. uint8_t num_channels;
  102. uint32_t sample_rate;
  103. int bits_per_sample = 16;
  104. uint32_t align;
  105. int is_signed = 1;
  106. size_t len;
  107. const char *file_path = luaL_checklstring(L, 2, &len);
  108. FILE *fd = luat_fs_fopen(file_path, "r");
  109. if (fd && coder)
  110. {
  111. switch(coder->type)
  112. {
  113. case MULTIMEDIA_DATA_TYPE_MP3:
  114. mp3_decoder_init(coder->mp3_decoder);
  115. coder->buff.addr = luat_heap_malloc(MP3_FRAME_LEN);
  116. coder->buff.len = MP3_FRAME_LEN;
  117. coder->buff.used = luat_fs_fread(temp, 10, 1, fd);
  118. if (coder->buff.used != 10)
  119. {
  120. break;
  121. }
  122. if (!memcmp(temp, "ID3", 3))
  123. {
  124. jump = 0;
  125. for(i = 0; i < 4; i++)
  126. {
  127. jump <<= 7;
  128. jump |= temp[6 + i] & 0x7f;
  129. }
  130. // LLOGD("jump head %d", jump);
  131. luat_fs_fseek(fd, jump, SEEK_SET);
  132. }
  133. coder->buff.used = luat_fs_fread(coder->buff.addr, MP3_FRAME_LEN, 1, fd);
  134. result = mp3_decoder_get_info(coder->mp3_decoder, coder->buff.addr, coder->buff.used, &sample_rate, &num_channels);
  135. mp3_decoder_init(coder->mp3_decoder);
  136. audio_format = MULTIMEDIA_DATA_TYPE_PCM;
  137. break;
  138. case MULTIMEDIA_DATA_TYPE_WAV:
  139. luat_fs_fread(temp, 12, 1, fd);
  140. if (!memcmp(temp, "RIFF", 4) || !memcmp(temp + 8, "WAVE", 4))
  141. {
  142. luat_fs_fread(temp, 8, 1, fd);
  143. if (!memcmp(temp, "fmt ", 4))
  144. {
  145. memcpy(&len, temp + 4, 4);
  146. coder->buff.addr = luat_heap_malloc(len);
  147. luat_fs_fread(coder->buff.addr, len, 1, fd);
  148. audio_format = coder->buff.addr[0];
  149. num_channels = coder->buff.addr[2];
  150. memcpy(&sample_rate, coder->buff.addr + 4, 4);
  151. align = coder->buff.addr[12];
  152. bits_per_sample = coder->buff.addr[14];
  153. coder->read_len = (align * sample_rate >> 3) & ~(3);
  154. // LLOGD("size %d", coder->read_len);
  155. luat_heap_free(coder->buff.addr);
  156. coder->buff.addr = NULL;
  157. luat_fs_fread(temp, 8, 1, fd);
  158. if (!memcmp(temp, "fact", 4))
  159. {
  160. memcpy(&len, temp + 4, 4);
  161. luat_fs_fseek(fd, len, SEEK_CUR);
  162. luat_fs_fread(temp, 8, 1, fd);
  163. }
  164. if (!memcmp(temp, "data", 4))
  165. {
  166. result = 1;
  167. }
  168. else
  169. {
  170. LLOGD("no data");
  171. result = 0;
  172. }
  173. }
  174. else
  175. {
  176. LLOGD("no fmt");
  177. }
  178. }
  179. else
  180. {
  181. LLOGD("head error");
  182. }
  183. break;
  184. default:
  185. break;
  186. }
  187. }
  188. if (!result)
  189. {
  190. luat_fs_fclose(fd);
  191. }
  192. else
  193. {
  194. coder->fd = fd;
  195. }
  196. lua_pushboolean(L, result);
  197. lua_pushinteger(L, audio_format);
  198. lua_pushinteger(L, num_channels);
  199. lua_pushinteger(L, sample_rate);
  200. lua_pushinteger(L, bits_per_sample);
  201. lua_pushboolean(L, is_signed);
  202. return 6;
  203. }
  204. /**
  205. decoder从文件中解析出原始音频数据,比如从MP3文件里解析出PCM数据,这里的文件路径已经在codec.info传入,不需要再次传入
  206. @api codec.data(decoder, out_buff)
  207. @userdata 解码用的decoder
  208. @zbuff 存放输出数据的zbuff,空间必须不少于16KB
  209. @int 最少解码出多少字节的音频数据,默认16384
  210. @return boolean 是否成功解析
  211. @usage
  212. -- 大内存设备
  213. local buff = zbuff.create(16*1024)
  214. local result = codec.data(coder, buff)
  215. -- 小内存设备
  216. local buff = zbuff.create(8*1024)
  217. local result = codec.data(coder, buff, 4096)
  218. */
  219. static int l_codec_get_audio_data(lua_State *L) {
  220. luat_multimedia_codec_t *coder = (luat_multimedia_codec_t *)luaL_checkudata(L, 1, LUAT_M_CODE_TYPE);
  221. uint32_t pos = 0;
  222. int read_len;
  223. int result = 0;
  224. luat_zbuff_t *out_buff = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
  225. uint32_t is_not_end = 1;
  226. uint32_t hz, out_len, used;
  227. size_t mini_output = luaL_optinteger(L, 3, 16384);
  228. if (mini_output > 16384)
  229. mini_output = 16384;
  230. else if (mini_output < 4 * 1024)
  231. mini_output = 4 * 1024;
  232. out_buff->used = 0;
  233. if (coder)
  234. {
  235. switch(coder->type)
  236. {
  237. case MULTIMEDIA_DATA_TYPE_MP3:
  238. GET_MP3_DATA:
  239. if (coder->buff.used < MINIMP3_MAX_SAMPLES_PER_FRAME)
  240. {
  241. read_len = luat_fs_fread((void*)(coder->buff.addr + coder->buff.used), MINIMP3_MAX_SAMPLES_PER_FRAME, 1, coder->fd);
  242. if (read_len > 0)
  243. {
  244. coder->buff.used += read_len;
  245. }
  246. else
  247. {
  248. is_not_end = 0;
  249. }
  250. }
  251. do
  252. {
  253. result = mp3_decoder_get_data(coder->mp3_decoder, coder->buff.addr + pos, coder->buff.used - pos, out_buff->addr + out_buff->used, &out_len, &hz, &used);
  254. if (result > 0)
  255. {
  256. out_buff->used += out_len;
  257. }
  258. if (result < 0) {
  259. return 0;
  260. }
  261. // if (!result) {
  262. // LLOGD("jump %dbyte", info.frame_bytes);
  263. // }
  264. pos += used;
  265. if ((out_buff->len - out_buff->used) < (MINIMP3_MAX_SAMPLES_PER_FRAME * 2))
  266. {
  267. break;
  268. }
  269. } while ((coder->buff.used - pos) >= (MINIMP3_MAX_SAMPLES_PER_FRAME * is_not_end + 1));
  270. // LLOGD("result %u,%u,%u,%u,%u", result, out_buff->used, coder->buff.used, pos, info.frame_bytes);
  271. if (pos >= coder->buff.used)
  272. {
  273. coder->buff.used = 0;
  274. }
  275. else
  276. {
  277. memmove(coder->buff.addr, coder->buff.addr + pos, coder->buff.used - pos);
  278. coder->buff.used -= pos;
  279. }
  280. pos = 0;
  281. if (!out_buff->used)
  282. {
  283. if (is_not_end)
  284. {
  285. goto GET_MP3_DATA;
  286. }
  287. else
  288. {
  289. result = 0;
  290. }
  291. }
  292. else
  293. {
  294. if ((out_buff->used < mini_output) && is_not_end)
  295. {
  296. goto GET_MP3_DATA;
  297. }
  298. result = 1;
  299. }
  300. break;
  301. case MULTIMEDIA_DATA_TYPE_WAV:
  302. read_len = luat_fs_fread(out_buff->addr + out_buff->used, coder->read_len, 1, coder->fd);
  303. if (read_len > 0)
  304. {
  305. out_buff->used += read_len;
  306. result = 1;
  307. }
  308. else
  309. {
  310. result = 0;
  311. }
  312. break;
  313. default:
  314. break;
  315. }
  316. }
  317. lua_pushboolean(L, result);
  318. return 1;
  319. }
  320. /**
  321. 编码音频数据,由于flash和ram空间一般比较有限,目前只支持amr-nb编码
  322. @api codec.encode(coder, in_buffer, out_buffer, mode)
  323. @userdata codec.create创建的编解码用的coder
  324. @zbuff 输入的数据,zbuff形式,从0到used
  325. @zbuff 输出的数据,zbuff形式,自动添加到buff的尾部,如果空间大小不足,会自动扩展,但是会额外消耗时间,甚至会失败,所以尽量一开始就给足空间
  326. @int amr_nb的编码等级 0~7(即 MR475~MR122)值越大消耗的空间越多,音质越高,默认0
  327. @return boolean 成功返回true,失败返回false
  328. @usage
  329. codec.encode(amr_coder, inbuf, outbuf, codec.AMR_)
  330. */
  331. static int l_codec_encode_audio_data(lua_State *L) {
  332. #ifdef LUAT_SUPPORT_AMR
  333. luat_multimedia_codec_t *coder = (luat_multimedia_codec_t *)luaL_checkudata(L, 1, LUAT_M_CODE_TYPE);
  334. luat_zbuff_t *in_buff = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
  335. luat_zbuff_t *out_buff = ((luat_zbuff_t *)luaL_checkudata(L, 3, LUAT_ZBUFF_TYPE));
  336. int mode = luaL_optinteger(L, 4, MR475);
  337. if (!coder || !in_buff || !out_buff || (coder->type != MULTIMEDIA_DATA_TYPE_AMR_NB) || coder->is_decoder)
  338. {
  339. lua_pushboolean(L, 0);
  340. return 1;
  341. }
  342. if (mode > MR122)
  343. {
  344. mode = MR475;
  345. }
  346. uint8_t outbuf[64];
  347. int16_t *pcm = (int16_t *)in_buff->addr;
  348. uint32_t total_len = in_buff->used >> 1;
  349. uint32_t done_len = 0;
  350. int out_len;
  351. while ((total_len - done_len) >= 160)
  352. {
  353. out_len = Encoder_Interface_Encode(coder->amr_coder, mode, &pcm[done_len], outbuf, 0);
  354. if (out_len <= 0)
  355. {
  356. LLOGE("encode error in %d,result %d", done_len, out_len);
  357. }
  358. else
  359. {
  360. if ((out_buff->len - out_buff->used) < out_len)
  361. {
  362. if (__zbuff_resize(out_buff, out_buff->len * 2 + out_len))
  363. {
  364. lua_pushboolean(L, 0);
  365. return 1;
  366. }
  367. }
  368. memcpy(out_buff->addr + out_buff->used, outbuf, out_len);
  369. out_buff->used += out_len;
  370. }
  371. done_len += 160;
  372. }
  373. lua_pushboolean(L, 1);
  374. return 1;
  375. #else
  376. lua_pushboolean(L, 0);
  377. return 1;
  378. #endif
  379. }
  380. static int l_codec_gc(lua_State *L)
  381. {
  382. luat_multimedia_codec_t *coder = ((luat_multimedia_codec_t *)luaL_checkudata(L, 1, LUAT_M_CODE_TYPE));
  383. if (coder->fd) {
  384. luat_fs_fclose(coder->fd);
  385. coder->fd = NULL;
  386. }
  387. if (coder->buff.addr)
  388. {
  389. luat_heap_free(coder->buff.addr);
  390. coder->buff.addr = NULL;
  391. memset(&coder->buff, 0, sizeof(luat_zbuff_t));
  392. }
  393. switch(coder->type) {
  394. case MULTIMEDIA_DATA_TYPE_MP3:
  395. if (coder->is_decoder && coder->mp3_decoder) {
  396. luat_heap_free(coder->mp3_decoder);
  397. coder->mp3_decoder = NULL;
  398. }
  399. break;
  400. #ifdef LUAT_SUPPORT_AMR
  401. case MULTIMEDIA_DATA_TYPE_AMR_NB:
  402. if (!coder->is_decoder && coder->amr_coder) {
  403. Encoder_Interface_exit(coder->amr_coder);
  404. coder->amr_coder = NULL;
  405. }
  406. break;
  407. #endif
  408. }
  409. return 0;
  410. }
  411. /**
  412. 释放编解码用的coder
  413. @api codec.release(coder)
  414. @coder codec.create创建的编解码用的coder
  415. @usage
  416. codec.release(coder)
  417. */
  418. static int l_codec_release(lua_State *L) {
  419. return l_codec_gc(L);
  420. }
  421. static const rotable_Reg_t reg_codec[] =
  422. {
  423. { "create" , ROREG_FUNC(l_codec_create)},
  424. { "info" , ROREG_FUNC(l_codec_get_audio_info)},
  425. { "data", ROREG_FUNC(l_codec_get_audio_data)},
  426. { "encode", ROREG_FUNC(l_codec_encode_audio_data)},
  427. { "release", ROREG_FUNC(l_codec_release)},
  428. //@const MP3 number MP3格式
  429. { "MP3", ROREG_INT(MULTIMEDIA_DATA_TYPE_MP3)},
  430. //@const WAV number WAV格式
  431. { "WAV", ROREG_INT(MULTIMEDIA_DATA_TYPE_WAV)},
  432. //@const AMR number AMR-NB格式,一般意义上的AMR
  433. { "AMR", ROREG_INT(MULTIMEDIA_DATA_TYPE_AMR_NB)},
  434. //@const AMR_WB number AMR-WB格式
  435. { "AMR_WB", ROREG_INT(MULTIMEDIA_DATA_TYPE_AMR_WB)},
  436. { NULL, {}}
  437. };
  438. LUAMOD_API int luaopen_multimedia_codec( lua_State *L ) {
  439. luat_newlib2(L, reg_codec);
  440. luaL_newmetatable(L, LUAT_M_CODE_TYPE); /* create metatable for file handles */
  441. lua_pushcfunction(L, l_codec_gc);
  442. lua_setfield(L, -2, "__gc");
  443. lua_pop(L, 1); /* pop new metatable */
  444. return 1;
  445. }