RTK_mmp_dec.c
10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "JZsdkLib.h"
#include "./RTK_mmp_dec.h"
#ifdef RTK_MPP_STATUS_ON
void dump_frame(MppFrame frame, FILE *out_fp)
{
printf("dump_frame_to_file\n");
RK_U32 width = 0;
RK_U32 height = 0;
RK_U32 h_stride = 0;
RK_U32 v_stride = 0;
MppFrameFormat fmt = MPP_FMT_YUV420SP;
MppBuffer buffer = NULL;
RK_U8 *base = NULL;
width = mpp_frame_get_width(frame);
height = mpp_frame_get_height(frame);
h_stride = mpp_frame_get_hor_stride(frame);
v_stride = mpp_frame_get_ver_stride(frame);
fmt = mpp_frame_get_fmt(frame);
buffer = mpp_frame_get_buffer(frame);
RK_U32 buf_size = mpp_frame_get_buf_size(frame);
printf("w x h: %dx%d hor_stride:%d ver_stride:%d buf_size:%d\n",
width, height, h_stride, v_stride, buf_size);
if (NULL == buffer) {
printf("buffer is null\n");
return ;
}
base = (RK_U8 *)mpp_buffer_get_ptr(buffer);
// MPP_FMT_YUV420SP
if (fmt != MPP_FMT_YUV420SP) {
printf("fmt %d not supported\n", fmt);
return;
}
RK_U32 i;
RK_U8 *base_y = base;
RK_U8 *base_c = base + h_stride * v_stride;
for (i = 0; i < height; i++, base_y += h_stride) {
fwrite(base_y, 1, width, out_fp);
}
for (i = 0; i < height / 2; i++, base_c += h_stride) {
fwrite(base_c, 1, width, out_fp);
}
}
// void dump_frame_to_file(MppCtx ctx, MppApi *mpi, MppFrame frame, FILE *out_fp)
// {
// printf("decode_and_dump_to_file\n");
// MPP_RET ret;
// if (mpp_frame_get_info_change(frame)) {
// printf("mpp_frame_get_info_change\n");
// /**
// * 第一次解码会到这个分支,需要为解码器设置缓冲区.
// * 解码器缓冲区支持3种模式。参考【图像内存分配以及交互模式】Rockchip_Developer_Guide_MPP_CN.pdf
// * 这里使用纯内部模式。
// */
// ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
// if (ret) {
// printf("mpp_frame_get_info_change mpi->control error"
// "MPP_DEC_SET_INFO_CHANGE_READY %d\n", ret);
// }
// return;
// }
// RK_U32 err_info = mpp_frame_get_errinfo(frame);
// RK_U32 discard = mpp_frame_get_discard(frame);
// printf("err_info: %u discard: %u\n", err_info, discard);
// if (err_info) {
// return;
// }
// // save
// dump_frame(frame, out_fp);
// return;
// }
//rtk解码器初始化
//输入内容,编码器参数的地址
T_JZsdkReturnCode RTK_mmp_dec_Init(T_rtk_mmp_dec_info *dec_info)
{
MPP_RET ret;
MppParam param = NULL;
//初始化编码器参数
// 资源分配参数
dec_info->packet_size = (3*dec_info->hor_stride*dec_info->ver_stride); //一般这个值够了
// 运行时配置
dec_info->need_split = 0;
//如果是其他类型,dec_tpye为1 mjpeg则为0
int VideoType = (dec_info->Dec_type != MPP_VIDEO_CodingMJPEG) ? (1) : (0);
// /*************************************
// //创建输入输出的数组
// ************************************/
if (VideoType == 1) //普通的视频类型
{
dec_info->dataBuf = (unsigned char*)malloc(dec_info->packet_size);
if(dec_info->dataBuf == NULL)
{
JZSDK_LOG_ERROR("摄像头的视频回复帧内存注册错误");
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
ret = mpp_packet_init(&dec_info->packet, dec_info->dataBuf, dec_info->packet_size);
if (ret) {
JZSDK_LOG_ERROR("mpp_packet_init failed");
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
}
else //mjpeg下的视频类型
{
ret = mpp_buffer_group_get_internal(&dec_info->frm_grp, MPP_BUFFER_TYPE_ION);
if (ret) {
JZSDK_LOG_ERROR("failed to get buffer group for input frame ret %d", ret);
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
ret = mpp_buffer_group_get_internal(&dec_info->pkt_grp, MPP_BUFFER_TYPE_ION);
if (ret) {
JZSDK_LOG_ERROR("failed to get buffer group for output packet ret %d", ret);
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
ret = mpp_frame_init(&dec_info->frame); /* output frame */
if (MPP_OK != ret)
{
JZSDK_LOG_ERROR("mpp_frame_init failed");
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
/*
* NOTE: For jpeg could have YUV420 and YUV422 the buffer should be
* larger for output. And the buffer dimension should align to 16.
* YUV420 buffer is 3/2 times of w*h.
* YUV422 buffer is 2 times of w*h.
* So create larger buffer with 2 times w*h.
*/
ret = mpp_buffer_get(dec_info->frm_grp, &dec_info->frmBuf, dec_info->hor_stride * dec_info->ver_stride * 4);
if (ret) {
JZSDK_LOG_ERROR("failed to get buffer for input frame ret %d", ret);
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
// NOTE: for mjpeg decoding send the whole file
ret = mpp_buffer_get(dec_info->pkt_grp, &dec_info->pktBuf, dec_info->packet_size);
if (ret) {
JZSDK_LOG_ERROR("failed to get buffer for input frame ret %d", ret);
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
mpp_packet_init_with_buffer(&dec_info->packet, dec_info->pktBuf);
dec_info->dataBuf = mpp_buffer_get_ptr(dec_info->pktBuf);
mpp_frame_set_buffer(dec_info->frame, dec_info->frmBuf);
}
printf("创建输入输出的数组初始化完毕\n");
// 创建解码器
ret = mpp_create(&dec_info->ctx, &dec_info->mpi);
if (ret != MPP_OK)
{
free(dec_info);
JZSDK_LOG_ERROR("解码器创建失败");
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
else
{
printf("解码器创建成功\n");
}
/**
* 配置解码器
* - 解码文件需要 split 模式
* - 设置非阻塞模式,0非阻塞(默认),-1阻塞,+val 超时(ms)
*/
param = &(dec_info->need_split);
ret = dec_info->mpi->control(dec_info->ctx, MPP_DEC_SET_PARSER_SPLIT_MODE, param);
if (ret != MPP_OK) {
mpp_destroy(dec_info->ctx); // 销毁创建的编码器
free(dec_info);
JZSDK_LOG_ERROR("mpi->control error MPP_DEC_SET_PARSER_SPLIT_MODE");
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
else
{
printf("解码器配置创建成功\n");
}
// //设置超时
// // NOTE: timeout value please refer to MppPollType definition
// // 0 - non-block call (default)
// // -1 - block call
// // +val - timeout value in ms
// if (timeout) {
// param = &timeout;
// ret = mpi->control(ctx, MPP_SET_OUTPUT_TIMEOUT, param);
// if (MPP_OK != ret) {
// mpp_err("Failed to set output timeout %d ret %d\n", timeout, ret);
// goto MPP_TEST_OUT;
// }
// }
//初始化mpp编解码器
//参数1 mmp初始上下文
//参数2 DEC解码 ENC编码
//参数3 编解码的格式
/*MPP_VIDEO_CodingAVC : H.264
MPP_VIDEO_CodingHEVC: H.265
MPP_VIDEO_CodingVP8 : VP8
MPP_VIDEO_CodingVP9 : VP9
MPP_VIDEO_CodingMJPEG : MJPEG */
ret = mpp_init(dec_info->ctx, MPP_CTX_DEC, dec_info->Dec_type);
if (ret != MPP_OK) {
mpp_destroy(dec_info->ctx);
free(dec_info);
JZSDK_LOG_ERROR("mpp解码初始化失败");
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
else
{
printf("mpp解码初始化成功\n");
}
//输出的码流格式
//param = &out_format;
//也不知道为什么只能设420sp没法设420p
MppFrameFormat format = dec_info->out_format;
ret = dec_info->mpi->control(dec_info->ctx, MPP_DEC_SET_OUTPUT_FORMAT, &format);
if (ret == MPP_OK)
{
printf("输出格式正确\n");
}
else
{
printf("输出格式错误\n");
}
return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
T_JZsdkReturnCode RTK_mmp_dec_input(T_rtk_mmp_dec_info *dec_info ,unsigned char *input_data, unsigned int input_data_len, MppFrame *out_put_frame)
{
int ret; //返回值
int pktEos = 0;
MppTask task = NULL;
//2、将解码的数据放入划好的地址
memset(dec_info->dataBuf,0,dec_info->packet_size);
memcpy(dec_info->dataBuf , input_data ,input_data_len );
mpp_packet_set_pos(dec_info->packet, dec_info->dataBuf); //设置packet的 有效数据 的开始位置
mpp_packet_set_length(dec_info->packet, input_data_len); //设置packet的 有效数据 的长度
if(pktEos) //结束标志,这边估计是不会用了
{
mpp_packet_set_eos(dec_info->packet);
}
ret = dec_info->mpi->poll(dec_info->ctx, MPP_PORT_INPUT, MPP_POLL_BLOCK);
if (ret)
{
JZSDK_LOG_ERROR("mpp input poll failed");
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
ret = dec_info->mpi->dequeue(dec_info->ctx, MPP_PORT_INPUT, &task); /* input queue */
if (ret)
{
JZSDK_LOG_ERROR("mpp task input dequeue failed");
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
//mpp_assert(task);
mpp_task_meta_set_packet(task, KEY_INPUT_PACKET, dec_info->packet);
mpp_task_meta_set_frame (task, KEY_OUTPUT_FRAME, dec_info->frame);
ret = dec_info->mpi->enqueue(dec_info->ctx, MPP_PORT_INPUT, task); /* input queue */
if (ret)
{
JZSDK_LOG_ERROR("mpp task input enqueue failed");
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
/* poll and wait here */
ret = dec_info->mpi->poll(dec_info->ctx, MPP_PORT_OUTPUT, MPP_POLL_BLOCK);
if (ret)
{
JZSDK_LOG_ERROR("mpp output poll failed");
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
ret = dec_info->mpi->dequeue(dec_info->ctx, MPP_PORT_OUTPUT, &task); /* output queue */
if (ret)
{
JZSDK_LOG_ERROR("mpp task output dequeue failed");
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
//mpp_assert(task);
if (task)
{
mpp_task_meta_get_frame(task, KEY_OUTPUT_FRAME, &dec_info->frame);
if (dec_info->frame)
{
//把解码出来的数据传递回去
*out_put_frame = dec_info->frame;
//printf("解码成功\n");
if (mpp_frame_get_eos(dec_info->frame))
{
printf("found eos frame\n");
}
}
ret = dec_info->mpi->enqueue(dec_info->ctx, MPP_PORT_OUTPUT, task);
if (ret)
{
JZSDK_LOG_ERROR("mpp task output enqueue failed\n");
}
}
return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
#endif