xref: /OK3568_Linux_fs/external/rockit/mpi/example/mod/test_mpi_aenc.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 <sys/poll.h>
24 #include "rk_debug.h"
25 #include "rk_mpi_aenc.h"
26 #include "rk_mpi_mb.h"
27 #include "rk_mpi_sys.h"
28 
29 #include "test_comm_argparse.h"
30 #define TEST_AENC_WITH_FD 0
31 
32 typedef struct _rkTEST_AENC_CTX_S {
33     const char *srcFilePath;
34     const char *dstFilePath;
35     RK_S32      s32LoopCount;
36     RK_S32      s32ChnNum;
37     RK_S32      s32SampleRate;
38     RK_S32      s32Channel;
39     RK_S32      s32Format;
40     char       *chCodecId;
41     RK_S32      s32MilliSec;
42     RK_S32      s32ChnIndex;
43     RK_S32      s32FrameSize;
44     RK_S32      s32DevFd;
45 } TEST_AENC_CTX_S;
46 
aenc_data_free(void * opaque)47 static RK_S32 aenc_data_free(void *opaque) {
48     if (opaque) {
49         free(opaque);
50         opaque = RK_NULL;
51     }
52 
53     return 0;
54 }
55 
test_find_audio_enc_codec_id(TEST_AENC_CTX_S * params)56 static RK_U32 test_find_audio_enc_codec_id(TEST_AENC_CTX_S *params) {
57     if (params == RK_NULL)
58         return -1;
59 
60     char *format = params->chCodecId;
61    if (strstr(format, "mp2")) {
62         return RK_AUDIO_ID_MP2;
63     } else if (strstr(format, "g722")) {
64         return RK_AUDIO_ID_ADPCM_G722;
65     } else if (strstr(format, "g726")) {
66         return RK_AUDIO_ID_ADPCM_G726;
67     } else if (strstr(format, "g711a")) {
68         return RK_AUDIO_ID_PCM_ALAW;
69     } else if (strstr(format, "g711u")) {
70         return RK_AUDIO_ID_PCM_MULAW;
71     }
72 
73     RK_LOGE("test not find codec id : %s", params->chCodecId);
74     return -1;
75 }
76 
test_find_audio_enc_format(TEST_AENC_CTX_S * params)77 static RK_U32 test_find_audio_enc_format(TEST_AENC_CTX_S *params) {
78     if (params == RK_NULL)
79         return -1;
80 
81     if (params->s32Format == 8) {
82         return AUDIO_BIT_WIDTH_8;
83     } else if (params->s32Format == 16) {
84         return AUDIO_BIT_WIDTH_16;
85     } else if (params->s32Format == 24) {
86         return AUDIO_BIT_WIDTH_24;
87     }
88 
89     RK_LOGE("test not find format : %s", params->s32Format);
90     return -1;
91 }
92 
test_aenc_poll_event(RK_S32 timeoutMsec,RK_S32 fd)93 RK_S32 test_aenc_poll_event(RK_S32 timeoutMsec, RK_S32 fd) {
94     RK_S32 num_fds = 1;
95     struct pollfd pollFds[num_fds];
96     RK_S32 ret = 0;
97 
98     RK_ASSERT(fd > 0);
99     memset(pollFds, 0, sizeof(pollFds));
100     pollFds[0].fd = fd;
101     pollFds[0].events = (POLLPRI | POLLIN | POLLERR | POLLNVAL | POLLHUP);
102 
103     ret = poll(pollFds, num_fds, timeoutMsec);
104 
105     if (ret > 0 && (pollFds[0].revents & (POLLERR | POLLNVAL | POLLHUP))) {
106         RK_LOGE("fd:%d polled error", fd);
107         return -1;
108     }
109 
110     return ret;
111 }
112 
test_init_mpi_aenc(TEST_AENC_CTX_S * params)113 RK_S32 test_init_mpi_aenc(TEST_AENC_CTX_S *params) {
114     RK_S32 s32ret = 0;
115     AENC_CHN_ATTR_S stAencAttr;
116     AENC_CHN AdChn = (AENC_CHN)(params->s32ChnIndex);
117 
118     RK_U32 codecId = test_find_audio_enc_codec_id(params);
119     if (codecId == -1) {
120         return RK_FAILURE;
121     }
122 
123     RK_U32 format = test_find_audio_enc_format(params);
124     if (codecId == -1) {
125         return RK_FAILURE;
126     }
127 
128     stAencAttr.enType = (RK_CODEC_ID_E)codecId;
129     stAencAttr.stCodecAttr.u32Channels = params->s32Channel;
130     stAencAttr.stCodecAttr.u32SampleRate = params->s32SampleRate;
131     stAencAttr.stCodecAttr.enBitwidth = (AUDIO_BIT_WIDTH_E)format;
132     stAencAttr.u32BufCount = 4;
133 
134     s32ret = RK_MPI_AENC_CreateChn(AdChn, &stAencAttr);
135     if (s32ret) {
136         RK_LOGE("create aenc chn %d err:0x%x\n", AdChn, s32ret);
137         return RK_FAILURE;
138     }
139 
140 #if TEST_AENC_WITH_FD
141     // open fd immediate after enable chn will be better.
142     params->s32DevFd = RK_MPI_AENC_GetFd(AdChn);
143     RK_LOGI("ai chnId: %d, selectFd:%d", (RK_S32)AdChn, params->s32DevFd);
144 #endif
145 
146     return RK_SUCCESS;
147 }
148 
send_frame_thread(void * arg)149 static void *send_frame_thread(void *arg) {
150     RK_S32 s32ret = 0;
151     TEST_AENC_CTX_S *params = reinterpret_cast<TEST_AENC_CTX_S *>(arg);
152     RK_U8 *srcData = RK_NULL;
153     RK_S32 srcSize = 0;
154     FILE  *file = RK_NULL;
155     RK_S32 frameEos = 0;
156     AUDIO_FRAME_S stAudioFrm;
157     ADEC_CHN AdChn = (AENC_CHN)(params->s32ChnIndex);
158     RK_U64 timeStamp = 0;
159     RK_S32 count = 0;
160     RK_S32 frmLen = params->s32FrameSize;
161 
162     file = fopen(params->srcFilePath, "rb");
163     if (file == RK_NULL) {
164         RK_LOGE("failed to open input file(%s), error: %s", params->srcFilePath, strerror(errno));
165         goto __FAILED;
166     }
167 
168     while (1) {
169         srcData = reinterpret_cast<RK_U8 *>(calloc(frmLen, sizeof(RK_U8)));
170         memset(srcData, 0, frmLen);
171 
172         srcSize = fread(srcData, 1, frmLen, file);
173 
174         if (srcSize == 0 || srcData == RK_NULL) {
175             RK_LOGI("read eos frame, now send eos frame!");
176             frameEos = 1;
177         }
178         RK_LOGV("send frame srcSize = %d, srcData = %p", srcSize, srcData);
179         stAudioFrm.u32Len = srcSize;
180         stAudioFrm.u64TimeStamp = timeStamp;
181         stAudioFrm.u32Seq = ++count;
182         stAudioFrm.bBypassMbBlk = RK_TRUE;
183 
184         MB_EXT_CONFIG_S extConfig = {0};
185         extConfig.pFreeCB = aenc_data_free;
186         extConfig.pOpaque = srcData;
187         extConfig.pu8VirAddr = srcData;
188         extConfig.u64Size    = srcSize;
189         RK_MPI_SYS_CreateMB(&(stAudioFrm.pMbBlk), &extConfig);
190 
191         s32ret = RK_MPI_AENC_SendFrame(AdChn, &stAudioFrm, RK_NULL, params->s32MilliSec);
192         if (s32ret != RK_SUCCESS) {
193             RK_LOGV("fail to send aenc stream.");
194         }
195         RK_MPI_MB_ReleaseMB(stAudioFrm.pMbBlk);
196 
197         if (frameEos)
198             break;
199         timeStamp++;
200     }
201 
202 __FAILED:
203     if (file) {
204         fclose(file);
205         file = RK_NULL;
206     }
207 
208     return RK_NULL;
209 }
210 
receive_stream_thread(void * arg)211 static void *receive_stream_thread(void *arg) {
212     RK_S32 s32ret = 0;
213     FILE *file = RK_NULL;
214     TEST_AENC_CTX_S *params = reinterpret_cast<TEST_AENC_CTX_S *>(arg);
215     AUDIO_STREAM_S pstStream;
216     AENC_CHN AdChn = (AENC_CHN)(params->s32ChnIndex);
217     RK_S32 eos = 0;
218     RK_S32 count = 0;
219 
220     if (params->dstFilePath) {
221         file = fopen(params->dstFilePath, "wb+");
222         if (file == RK_NULL) {
223             RK_LOGE("failed to open output file %s, error: %s.", params->dstFilePath, strerror(errno));
224             goto __FAILED;
225         }
226     }
227 
228     while (1) {
229 #if TEST_AENC_WITH_FD
230         test_aenc_poll_event(-1, params->s32DevFd);
231 #endif
232         s32ret = RK_MPI_AENC_GetStream(AdChn, &pstStream, params->s32MilliSec);
233         if (s32ret == RK_SUCCESS) {
234             MB_BLK bBlk = pstStream.pMbBlk;
235             RK_VOID *pstFrame = RK_MPI_MB_Handle2VirAddr(bBlk);
236             RK_S32 frameSize = pstStream.u32Len;
237             eos = (frameSize <= 0) ? 1 : 0;
238             if (pstFrame) {
239                 RK_LOGV("get frame data = %p, size = %d", pstFrame, frameSize);
240                 if (file) {
241                     fwrite(pstFrame, frameSize, 1, file);
242                     fflush(file);
243                 }
244                 RK_MPI_AENC_ReleaseStream(AdChn, &pstStream);
245                 count++;
246             }
247         } else {
248             RK_LOGE("fail to get aenc frame.");
249         }
250 
251         if (eos) {
252             RK_LOGI("get eos stream.");
253             break;
254         }
255     }
256 
257 __FAILED:
258     if (file) {
259         fclose(file);
260         file = RK_NULL;
261     }
262     return RK_NULL;
263 }
264 
unit_test_mpi_aenc(TEST_AENC_CTX_S * params)265 RK_S32 unit_test_mpi_aenc(TEST_AENC_CTX_S *params) {
266     RK_S32 i = 0;
267     TEST_AENC_CTX_S aencCtx[AENC_MAX_CHN_NUM];
268     pthread_t tidSend[AENC_MAX_CHN_NUM];
269     pthread_t tidReceive[AENC_MAX_CHN_NUM];
270 
271     if (params->s32ChnNum > AENC_MAX_CHN_NUM) {
272         RK_LOGE("aenc chn(%d) > max_chn(%d)", params->s32ChnNum, AENC_MAX_CHN_NUM);
273         goto __FAILED;
274     }
275 
276     for (i = 0; i < params->s32ChnNum; i++) {
277         memcpy(&(aencCtx[i]), params, sizeof(TEST_AENC_CTX_S));
278         aencCtx[i].s32ChnIndex = i;
279         aencCtx[i].s32MilliSec = -1;
280 
281         if (test_init_mpi_aenc(&aencCtx[i]) == RK_FAILURE) {
282             goto __FAILED;
283         }
284 
285         pthread_create(&tidSend[i], RK_NULL, send_frame_thread, reinterpret_cast<void *>(&aencCtx[i]));
286         pthread_create(&tidReceive[i], RK_NULL, receive_stream_thread, reinterpret_cast<void *>(&aencCtx[i]));
287     }
288 
289     for (i = 0; i < params->s32ChnNum; i++) {
290         pthread_join(tidSend[i], RK_NULL);
291         pthread_join(tidReceive[i], RK_NULL);
292         RK_MPI_AENC_DestroyChn((AENC_CHN)i);
293     }
294 
295     return RK_SUCCESS;
296 __FAILED:
297 
298     return RK_FAILURE;
299 }
300 
301 static const char *const usages[] = {
302     "./rk_mpi_aenc_test [-i src_path] [-C name] [--input_rate rate] [--input_ch ch] [--input_format format]...",
303     NULL,
304 };
305 
mpi_aenc_test_show_options(const TEST_AENC_CTX_S * ctx)306 static void mpi_aenc_test_show_options(const TEST_AENC_CTX_S *ctx) {
307     RK_PRINT("cmd parse result:\n");
308     RK_PRINT("input  file name       : %s\n", ctx->srcFilePath);
309     RK_PRINT("output file name       : %s\n", ctx->dstFilePath);
310     RK_PRINT("loop count             : %d\n", ctx->s32LoopCount);
311     RK_PRINT("channel number         : %d\n", ctx->s32ChnNum);
312     RK_PRINT("input sample rate      : %d\n", ctx->s32SampleRate);
313     RK_PRINT("input channel          : %d\n", ctx->s32Channel);
314     RK_PRINT("input format           : %d\n", ctx->s32Format);
315     RK_PRINT("input codec name       : %s\n", ctx->chCodecId);
316 }
317 
main(int argc,const char ** argv)318 int main(int argc, const char **argv) {
319     RK_S32           i;
320     RK_S32           s32Ret;
321     TEST_AENC_CTX_S *ctx;
322 
323     ctx = reinterpret_cast<TEST_AENC_CTX_S *>(malloc(sizeof(TEST_AENC_CTX_S)));
324     memset(ctx, 0, sizeof(TEST_AENC_CTX_S));
325 
326     ctx->srcFilePath     = RK_NULL;
327     ctx->dstFilePath     = RK_NULL;
328     ctx->s32LoopCount    = 1;
329     ctx->s32ChnNum       = 1;
330     ctx->chCodecId       = RK_NULL;
331     ctx->s32Format       = 16;
332     ctx->s32FrameSize    = 1024;
333 
334     struct argparse_option options[] = {
335         OPT_HELP(),
336         OPT_GROUP("basic options:"),
337         OPT_STRING('i', "input",  &(ctx->srcFilePath),
338                    "input file name , e.g.(./*.mp3). <required>", NULL, 0, 0),
339         OPT_STRING('C', "codec", &(ctx->chCodecId),
340                     "codec, e.g.(mp3/aac/flac/mp2/g722/g726). <required>", NULL, 0, 0),
341         OPT_INTEGER('\0', "input_ch", &(ctx->s32Channel),
342                     "the number of input stream channels. <required>", NULL, 0, 0),
343         OPT_INTEGER('\0', "input_rate", &(ctx->s32SampleRate),
344                     "the sample rate of input stream. <required>", NULL, 0, 0),
345         OPT_INTEGER('\0', "input_format", &(ctx->s32Format),
346                     "the input format of input stream. <required>", NULL, 0, 0),
347         OPT_STRING('o', "output", &(ctx->dstFilePath),
348                     "output file name, e.g.(./*.pcm). default(NULL).", NULL, 0, 0),
349         OPT_INTEGER('n', "loop_count", &(ctx->s32LoopCount),
350                     "loop running count. default(1)", NULL, 0, 0),
351         OPT_INTEGER('c', "channel_count", &(ctx->s32ChnNum),
352                     "the count of adec channel. default(1).", NULL, 0, 0),
353         OPT_INTEGER('\0', "frame_size", &(ctx->s32FrameSize),
354                     "the size of send frame. default(1024).", NULL, 0, 0),
355         OPT_END(),
356     };
357 
358     struct argparse argparse;
359     argparse_init(&argparse, options, usages, 0);
360     argparse_describe(&argparse, "\nselect a test case to run.",
361                                  "\nuse --help for details.");
362 
363     argc = argparse_parse(&argparse, argc, argv);
364     mpi_aenc_test_show_options(ctx);
365 
366     // must set params
367     if (ctx->srcFilePath == RK_NULL
368         || ctx->s32Channel <= 0
369         || ctx->s32SampleRate <= 0
370         || ctx->chCodecId == RK_NULL) {
371         argparse_usage(&argparse);
372         goto __FAILED;
373     }
374     RK_MPI_SYS_Init();
375     for (i = 0; i < ctx->s32LoopCount; i++) {
376         RK_LOGI("start running loop count  = %d", i);
377         s32Ret = unit_test_mpi_aenc(ctx);
378         if (s32Ret != RK_SUCCESS) {
379             goto __FAILED;
380         }
381         RK_LOGI("end running loop count  = %d", i);
382     }
383 
384 __FAILED:
385     if (ctx) {
386         free(ctx);
387         ctx = RK_NULL;
388     }
389     RK_MPI_SYS_Exit();
390     return 0;
391 }
392