1 /*
2 * Copyright 2020 Rockchip Electronics Co. LTD
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 #include <cstdio>
18 #include <cerrno>
19 #include <cstring>
20 #include <cstdlib>
21 #include <unistd.h>
22 #include <pthread.h>
23 #include "rk_debug.h"
24 #include "rk_mpi_adec.h"
25 #include "rk_mpi_mb.h"
26 #include "rk_mpi_sys.h"
27 #include "test_comm_argparse.h"
28
29 typedef struct _rkMpiADECCtx {
30 const char *srcFilePath;
31 const char *dstFilePath;
32 RK_S32 s32LoopCount;
33 RK_S32 s32ChnNum;
34 RK_S32 s32SampleRate;
35 RK_S32 s32Channel;
36 char *chCodecId;
37 RK_S32 s32DecMode;
38 RK_BOOL bBlock;
39 RK_S32 s32ChnIndex;
40 RK_S32 s32QueryStat;
41 RK_S32 s32ClrChnBuf;
42 } TEST_ADEC_CTX_S;
43
query_adec_flow_graph_stat(ADEC_CHN AdChn)44 void query_adec_flow_graph_stat(ADEC_CHN AdChn) {
45 RK_S32 ret = 0;
46 ADEC_CHN_STATE_S pstStat;
47 memset(&pstStat, 0, sizeof(ADEC_CHN_STATE_S));
48 ret = RK_MPI_ADEC_QueryChnStat(AdChn, &pstStat);
49 if (ret == RK_SUCCESS) {
50 RK_LOGI("query adec flow status:");
51 RK_LOGI("EOS flag : %d", pstStat.bEndOfStream);
52 RK_LOGI("total number of channel buffer : %d", pstStat.u32BufferFrmNum);
53 RK_LOGI("free number of channel buffer : %d", pstStat.u32BufferFreeNum);
54 RK_LOGI("busy number of channel buffer : %d", pstStat.u32BufferBusyNum);
55 }
56 }
57
adec_data_free(void * opaque)58 static RK_S32 adec_data_free(void *opaque) {
59 if (opaque) {
60 free(opaque);
61 opaque = RK_NULL;
62 }
63
64 return 0;
65 }
66
test_find_audio_codec_id(TEST_ADEC_CTX_S * params)67 static RK_U32 test_find_audio_codec_id(TEST_ADEC_CTX_S *params) {
68 if (params == RK_NULL)
69 return -1;
70
71 char *format = params->chCodecId;
72 if (strstr(format, "mp2")) {
73 return RK_AUDIO_ID_MP2;
74 } else if (strstr(format, "g726")) {
75 return RK_AUDIO_ID_ADPCM_G726;
76 } else if (strstr(format, "g711a")) {
77 return RK_AUDIO_ID_PCM_ALAW;
78 } else if (strstr(format, "g711u")) {
79 return RK_AUDIO_ID_PCM_MULAW;
80 }
81
82 if (params->s32DecMode == ADEC_MODE_STREAM) {
83 RK_LOGE("test not find codec id : %s", params->chCodecId);
84 return RK_AUDIO_ID_Unused;
85 } else {
86 // if set packet mode, try to get codecId, channels, samplerate
87 return RK_AUDIO_ID_AutoDetect;
88 }
89 }
90
test_init_mpi_adec(TEST_ADEC_CTX_S * params)91 RK_S32 test_init_mpi_adec(TEST_ADEC_CTX_S *params) {
92 RK_S32 i = 0;
93 RK_S32 s32ret = 0;
94 ADEC_CHN_ATTR_S stAdecAttr;
95 ADEC_CHN AdChn = (ADEC_CHN)(params->s32ChnIndex);
96 memset(&stAdecAttr, 0, sizeof(ADEC_CHN_ATTR_S));
97
98 if (stAdecAttr.stCodecAttr.u32Channels == 0) {
99 stAdecAttr.stCodecAttr.u32Channels = params->s32Channel;
100 stAdecAttr.stCodecAttr.u32SampleRate = params->s32SampleRate;
101 }
102
103 RK_U32 codecId = test_find_audio_codec_id(params);
104 if (codecId == RK_AUDIO_ID_Unused) {
105 return RK_FAILURE;
106 }
107
108 stAdecAttr.enType = (RK_CODEC_ID_E)codecId;
109 stAdecAttr.enMode = (ADEC_MODE_E)params->s32DecMode;
110 stAdecAttr.u32BufCount = 4;
111
112 s32ret = RK_MPI_ADEC_CreateChn(AdChn, &stAdecAttr);
113 if (s32ret) {
114 RK_LOGE("create adec chn %d err:0x%x\n", AdChn, s32ret);
115 return RK_FAILURE;
116 }
117
118 return RK_SUCCESS;
119 }
120
test_deinit_mpi_adec(TEST_ADEC_CTX_S * ctx)121 RK_S32 test_deinit_mpi_adec(TEST_ADEC_CTX_S *ctx) {
122 RK_MPI_ADEC_DestroyChn(ctx->s32ChnIndex);
123 return RK_SUCCESS;
124 }
125
send_stream_thread(void * arg)126 static void *send_stream_thread(void *arg) {
127 RK_S32 s32ret = 0;
128 TEST_ADEC_CTX_S *params = reinterpret_cast<TEST_ADEC_CTX_S *>(arg);
129 RK_U8 *srcData = RK_NULL;
130 RK_S32 srcSize = 0;
131 FILE *file = RK_NULL;
132 RK_S32 err = 0;
133 RK_S32 pktEos = 0;
134 AUDIO_STREAM_S stAudioStream;
135 RK_BOOL bBlock = params->bBlock;
136 ADEC_CHN AdChn = (ADEC_CHN)(params->s32ChnIndex);
137 RK_U64 timeStamp = 0;
138 RK_S32 count = 0;
139 RK_S64 dataOffset = 0;
140
141 file = fopen(params->srcFilePath, "rb");
142 if (file == RK_NULL) {
143 RK_LOGE("failed to open input file(%s), error: %s", params->srcFilePath, strerror(errno));
144 goto __FAILED;
145 }
146
147 while (1) {
148 srcData = reinterpret_cast<RK_U8 *>(calloc(1024, sizeof(RK_U8)));
149 memset(srcData, 0, 1024);
150
151 srcSize = fread(srcData, 1, 1024, file);
152
153 if (srcSize == 0 || srcData == RK_NULL) {
154 RK_LOGI("read eos packet, now send eos packet!");
155 pktEos = 1;
156 }
157
158 if (pktEos) {
159 RK_MPI_ADEC_SendEndOfStream(AdChn, RK_FALSE);
160 break;
161 } else {
162 stAudioStream.u32Len = srcSize;
163 stAudioStream.u64TimeStamp = timeStamp;
164 stAudioStream.u32Seq = ++count;
165 stAudioStream.bBypassMbBlk = RK_TRUE;
166 MB_EXT_CONFIG_S extConfig = {0};
167 extConfig.pFreeCB = adec_data_free;
168 extConfig.pOpaque = srcData;
169 extConfig.pu8VirAddr = srcData;
170 extConfig.u64Size = srcSize;
171 RK_MPI_SYS_CreateMB(&(stAudioStream.pMbBlk), &extConfig);
172 __RETRY:
173 s32ret = RK_MPI_ADEC_SendStream(AdChn, &stAudioStream, bBlock);
174 if (s32ret != RK_SUCCESS) {
175 RK_LOGE("fail to send adec stream.");
176 goto __RETRY;
177 }
178 RK_MPI_MB_ReleaseMB(stAudioStream.pMbBlk);
179 }
180 timeStamp++;
181 }
182
183 __FAILED:
184 if (file) {
185 fclose(file);
186 file = RK_NULL;
187 }
188
189 return RK_NULL;
190 }
191
receive_data_thread(void * arg)192 static void *receive_data_thread(void *arg) {
193 RK_S32 s32ret = 0;
194 FILE *file = RK_NULL;
195 TEST_ADEC_CTX_S *params = reinterpret_cast<TEST_ADEC_CTX_S *>(arg);
196 AUDIO_FRAME_INFO_S *pstFrmInfo = RK_NULL;
197
198 pstFrmInfo = reinterpret_cast<AUDIO_FRAME_INFO_S *>(malloc(sizeof(AUDIO_FRAME_INFO_S)));
199 memset(pstFrmInfo, 0, sizeof(AUDIO_FRAME_INFO_S));
200
201 RK_BOOL bBlock = params->bBlock;
202 ADEC_CHN AdChn = (ADEC_CHN)(params->s32ChnIndex);
203 RK_S32 eos = 0;
204 RK_S32 count = 0;
205
206 if (params->dstFilePath) {
207 file = fopen(params->dstFilePath, "wb+");
208 if (file == RK_NULL) {
209 RK_LOGE("failed to open output file %s, error: %s.", params->dstFilePath, strerror(errno));
210 goto __FAILED;
211 }
212 }
213
214 while (1) {
215 s32ret = RK_MPI_ADEC_GetFrame(AdChn, pstFrmInfo, bBlock);
216 if (s32ret == RK_SUCCESS) {
217 MB_BLK bBlk = pstFrmInfo->pstFrame->pMbBlk;
218 RK_VOID *pstFrame = RK_MPI_MB_Handle2VirAddr(bBlk);
219 RK_S32 frameSize = pstFrmInfo->pstFrame->u32Len;
220 eos = (frameSize <= 0) ? 1 : 0;
221 if (pstFrame) {
222 RK_LOGV("get frame data = %p, size = %d", pstFrame, frameSize);
223 if (file) {
224 fwrite(pstFrame, frameSize, 1, file);
225 fflush(file);
226 }
227 // release frame
228 RK_MPI_ADEC_ReleaseFrame(AdChn, pstFrmInfo);
229 count++;
230 }
231 } else {
232 RK_LOGE("fail to get adec frame.");
233 }
234
235 if (params->s32QueryStat) {
236 query_adec_flow_graph_stat(AdChn);
237 params->s32QueryStat = 0;
238 }
239
240 if (params->s32ClrChnBuf) {
241 RK_LOGI("test clear chn(%d) buf", AdChn);
242 RK_MPI_ADEC_ClearChnBuf(AdChn);
243 params->s32ClrChnBuf = 0;
244 }
245
246 if (eos) {
247 RK_LOGI("get eos packet.");
248 break;
249 }
250 }
251
252 __FAILED:
253 if (pstFrmInfo) {
254 free(pstFrmInfo);
255 pstFrmInfo = RK_NULL;
256 }
257
258 if (file) {
259 fclose(file);
260 file = RK_NULL;
261 }
262 return RK_NULL;
263 }
264
unit_test_mpi_adec(TEST_ADEC_CTX_S * params)265 RK_S32 unit_test_mpi_adec(TEST_ADEC_CTX_S *params) {
266 RK_S32 i = 0;
267 TEST_ADEC_CTX_S adecCtx[ADEC_MAX_CHN_NUM];
268 pthread_t tidSend[ADEC_MAX_CHN_NUM];
269 pthread_t tidReceive[ADEC_MAX_CHN_NUM];
270
271 if (params->s32ChnNum > ADEC_MAX_CHN_NUM) {
272 RK_LOGE("adec chn(%d) > max_chn(%d)", params->s32ChnNum, ADEC_MAX_CHN_NUM);
273 goto __FAILED;
274 }
275
276 params->bBlock = RK_TRUE;
277
278 for (i = 0; i < params->s32ChnNum; i++) {
279 memcpy(&(adecCtx[i]), params, sizeof(TEST_ADEC_CTX_S));
280 adecCtx[i].s32ChnIndex = i;
281
282 if (test_init_mpi_adec(&adecCtx[i]) == RK_FAILURE) {
283 goto __FAILED;
284 }
285
286 if (params->s32DecMode == ADEC_MODE_STREAM) {
287 pthread_create(&tidSend[i], RK_NULL, send_stream_thread, reinterpret_cast<void *>(&adecCtx[i]));
288 } else {
289
290 }
291 pthread_create(&tidReceive[i], RK_NULL, receive_data_thread, reinterpret_cast<void *>(&adecCtx[i]));
292 }
293
294 for (i = 0; i < params->s32ChnNum; i++) {
295 pthread_join(tidSend[i], RK_NULL);
296 pthread_join(tidReceive[i], RK_NULL);
297 test_deinit_mpi_adec(&adecCtx[i]);
298 }
299
300 return RK_SUCCESS;
301 __FAILED:
302
303 return RK_FAILURE;
304 }
305
306 static const char *const usages[] = {
307 "./rk_mpi_adec_test [-i src_path] [-C name] [--input_rate rate] [--input_ch ch]...",
308 NULL,
309 };
310
mpi_adec_test_show_options(const TEST_ADEC_CTX_S * ctx)311 static void mpi_adec_test_show_options(const TEST_ADEC_CTX_S *ctx) {
312 RK_PRINT("cmd parse result:\n");
313 RK_PRINT("input file name : %s\n", ctx->srcFilePath);
314 RK_PRINT("output file name : %s\n", ctx->dstFilePath);
315 RK_PRINT("loop count : %d\n", ctx->s32LoopCount);
316 RK_PRINT("channel number : %d\n", ctx->s32ChnNum);
317 RK_PRINT("input sample rate : %d\n", ctx->s32SampleRate);
318 RK_PRINT("input channel : %d\n", ctx->s32Channel);
319 RK_PRINT("input codec name : %s\n", ctx->chCodecId);
320 RK_PRINT("input decode mode : %d\n", ctx->s32DecMode);
321 RK_PRINT("query stat : %d\n", ctx->s32QueryStat);
322 RK_PRINT("clear buf : %d\n", ctx->s32ClrChnBuf);
323 }
324
main(int argc,const char ** argv)325 int main(int argc, const char **argv) {
326 RK_S32 i;
327 RK_S32 s32Ret;
328 TEST_ADEC_CTX_S *ctx;
329
330 ctx = reinterpret_cast<TEST_ADEC_CTX_S *>(malloc(sizeof(TEST_ADEC_CTX_S)));
331 memset(ctx, 0, sizeof(TEST_ADEC_CTX_S));
332
333 ctx->srcFilePath = RK_NULL;
334 ctx->dstFilePath = RK_NULL;
335 ctx->s32LoopCount = 1;
336 ctx->s32ChnNum = 1;
337 ctx->s32DecMode = 0;
338 ctx->chCodecId = RK_NULL;
339 ctx->s32DecMode = ADEC_MODE_STREAM;
340
341 struct argparse_option options[] = {
342 OPT_HELP(),
343 OPT_GROUP("basic options:"),
344 OPT_STRING('i', "input", &(ctx->srcFilePath),
345 "input file name , e.g.(./*.mp3). <required>", NULL, 0, 0),
346 OPT_STRING('C', "codec", &(ctx->chCodecId),
347 "codec, e.g.(mp2/g711a/g711u/g726). <required>", NULL, 0, 0),
348 OPT_INTEGER('\0', "input_ch", &(ctx->s32Channel),
349 "the number of input stream channels. <required>", NULL, 0, 0),
350 OPT_INTEGER('\0', "input_rate", &(ctx->s32SampleRate),
351 "the sample rate of input stream. <required>", NULL, 0, 0),
352 OPT_STRING('o', "output", &(ctx->dstFilePath),
353 "output file name, e.g.(./*.pcm). default(NULL).", NULL, 0, 0),
354 OPT_INTEGER('n', "loop_count", &(ctx->s32LoopCount),
355 "loop running count. default(1)", NULL, 0, 0),
356 OPT_INTEGER('c', "channel_count", &(ctx->s32ChnNum),
357 "the count of adec channel. default(1).", NULL, 0, 0),
358 OPT_INTEGER('\0', "dec_mode", &(ctx->s32DecMode),
359 "the audio stream decode mode, range(0: pack mode, 1: stream mode), default(0)", NULL, 0, 0),
360 OPT_INTEGER('\0', "query_stat", &(ctx->s32QueryStat),
361 "query adec statistics info, range(0: query, 1: not query), default(0)", NULL, 0, 0),
362 OPT_INTEGER('\0', "clr_buf", &(ctx->s32ClrChnBuf),
363 "clear buffer of channel, range(0, 1), default(0)", NULL, 0, 0),
364 OPT_END(),
365 };
366
367 struct argparse argparse;
368 argparse_init(&argparse, options, usages, 0);
369 argparse_describe(&argparse, "\nselect a test case to run.",
370 "\nuse --help for details.");
371
372 argc = argparse_parse(&argparse, argc, argv);
373 mpi_adec_test_show_options(ctx);
374
375 // must set params
376 if (ctx->srcFilePath == RK_NULL
377 || ctx->s32Channel <= 0
378 || ctx->s32SampleRate <= 0
379 || ctx->chCodecId == RK_NULL) {
380 argparse_usage(&argparse);
381 goto __FAILED;
382 }
383
384 RK_MPI_SYS_Init();
385
386 for (i = 0; i < ctx->s32LoopCount; i++) {
387 RK_LOGI("start running loop count = %d", i);
388 s32Ret = unit_test_mpi_adec(ctx);
389 if (s32Ret != RK_SUCCESS) {
390 goto __FAILED;
391 }
392 RK_LOGI("end running loop count = %d", i);
393 }
394
395 __FAILED:
396 if (ctx) {
397 free(ctx);
398 ctx = RK_NULL;
399 }
400
401 RK_MPI_SYS_Exit();
402 return 0;
403 }
404