1 /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2 /*
3 * Copyright (c) 2015 Rockchip Electronics Co., Ltd.
4 */
5
6 #define MODULE_TAG "mpp_impl"
7
8 #include <time.h>
9 #include <stdarg.h>
10 #include <sys/types.h>
11 #include <sys/syscall.h>
12
13 #include "rk_mpi_cmd.h"
14
15 #include "mpp_env.h"
16 #include "mpp_mem.h"
17 #include "mpp_time.h"
18 #include "mpp_debug.h"
19 #include "mpp_thread.h"
20 #include "mpp_common.h"
21
22 #include "mpp_impl.h"
23
24 #define MAX_FILE_NAME_LEN 512
25 #define MAX_DUMP_WIDTH 960
26 #define MAX_DUMP_HEIGHT 540
27
28 #define ops_log(fp, fmt, ...) _ops_log(fp, fmt, ## __VA_ARGS__)
29
30 typedef enum MppOpsType_e {
31 MPP_DEC_OPS_BASE = 0,
32 MPP_DEC_INIT = MPP_DEC_OPS_BASE,
33 MPP_DEC_SE
34 } MppOpsType;
35
36 /* dump data */
37 typedef struct MppDumpImpl_t {
38 MppMutex lock;
39 RK_U32 log_version;
40 RK_U32 debug;
41 pid_t tid;
42 RK_S64 time_base;
43
44 MppCtxType type;
45 MppCodingType coding;
46
47 FILE *fp_in; // file for MppPacket
48 FILE *fp_out; // file for MppFrame
49 FILE *fp_ops; // file for decoder / encoder extra info
50
51 RK_U8 *fp_buf; // for resample frame
52 RK_U32 pkt_offset;
53 RK_U32 dump_width;
54 RK_U32 dump_height;
55 RK_U32 dump_size;
56
57 RK_U32 idx;
58 } MppDumpImpl;
59
60 typedef union OpsArgs_u {
61 struct MppOpsInitArg_t {
62 MppCtxType type;
63 MppCodingType coding;
64 } init_arg;
65
66 struct MppOpsPktArg_t {
67 RK_U32 offset; // offset in packet file
68 RK_U32 length; // pakcet length
69 RK_S64 pts;
70 } pkt_arg;
71
72 struct MppOpsFrmArg_t {
73 RK_U32 fd;
74 RK_U32 info_change;
75 RK_U32 error;
76 RK_U32 discard;
77 RK_S64 pts;
78 } frm_arg;
79
80 struct MppOpCtrlArg_t {
81 MpiCmd cmd;
82 } ctrl_arg;
83 } OpsArgs;
84
85 typedef struct MppOpsInfo_t {
86 RK_U32 idx;
87 RK_U32 id;
88 RK_S64 time;
89 OpsArgs args;
90 } MppOpsInfo;
91
92 /*
93 * decoder file dump:
94 * dec_pkt - decoder input byte raw stream file
95 * dec_cfg - decoder input stream offset and size info in format [u32 offset|u32 size]
96 * dec_frm - decoder output frame file with snapshot method
97 */
98 static const char dec_pkt_path[] = "/data/mpp_dec_in.bin";
99 static const char dec_ops_path[] = "/data/mpp_dec_ops.bin";
100 static const char dec_frm_path[] = "/data/mpp_dec_out.bin";
101
102 static const char enc_frm_path[] = "/data/mpp_enc_in.bin";
103 static const char enc_ops_path[] = "/data/mpp_enc_ops.bin";
104 static const char enc_pkt_path[] = "/data/mpp_enc_out.bin";
105
try_env_file(const char * env,const char * path,pid_t tid)106 static FILE *try_env_file(const char *env, const char *path, pid_t tid)
107 {
108 const char *fname = NULL;
109 FILE *fp = NULL;
110 char name[MAX_FILE_NAME_LEN];
111
112 mpp_env_get_str(env, &fname, path);
113 if (fname == path) {
114 snprintf(name, sizeof(name) - 1, "%s-%d", path, tid);
115 fname = name;
116 }
117
118 fp = fopen(fname, "w+b");
119 mpp_log("open %s %p for dump\n", fname, fp);
120
121 return fp;
122 }
123
fetch_data(RK_U32 fmt,RK_U8 * line,RK_U32 num)124 static RK_U8 fetch_data(RK_U32 fmt, RK_U8 *line, RK_U32 num)
125 {
126 RK_U32 offset = 0;
127 RK_U32 value = 0;
128
129 if (fmt == MPP_FMT_YUV420SP_10BIT) {
130 offset = (num * 2) & 7;
131 value = (line[num * 10 / 8] >> offset) |
132 (line[num * 10 / 8 + 1] << (8 - offset));
133
134 value = (value & 0x3ff) >> 2;
135 } else if (fmt == MPP_FMT_YUV420SP) {
136 value = line[num];
137 }
138
139 return (RK_U8)value;
140 }
141
rearrange_pix(RK_U8 * tmp_line,RK_U8 * base,RK_U32 n)142 static void rearrange_pix(RK_U8 *tmp_line, RK_U8 *base, RK_U32 n)
143 {
144 RK_U16 * pix = (RK_U16 *)(tmp_line + n * 16);
145 RK_U16 * base_u16 = (RK_U16 *)(base + n * 10);
146
147 pix[0] = base_u16[0] & 0x03FF;
148 pix[1] = (base_u16[0] & 0xFC00) >> 10 | (base_u16[1] & 0x000F) << 6;
149 pix[2] = (base_u16[1] & 0x3FF0) >> 4;
150 pix[3] = (base_u16[1] & 0xC000) >> 14 | (base_u16[2] & 0x00FF) << 2;
151 pix[4] = (base_u16[2] & 0xFF00) >> 8 | (base_u16[3] & 0x0003) << 8;
152 pix[5] = (base_u16[3] & 0x0FFC) >> 2;
153 pix[6] = (base_u16[3] & 0xF000) >> 12 | (base_u16[4] & 0x003F) << 4;
154 pix[7] = (base_u16[4] & 0xFFC0) >> 6;
155 }
156
dump_frame(FILE * fp,MppFrame frame,RK_U8 * tmp,RK_U32 w,RK_U32 h)157 static void dump_frame(FILE *fp, MppFrame frame, RK_U8 *tmp, RK_U32 w, RK_U32 h)
158 {
159 RK_U32 i = 0, j = 0;
160 RK_U32 fmt = (mpp_frame_get_fmt(frame) & MPP_FRAME_FMT_MASK);
161 RK_U32 width = mpp_frame_get_width(frame);
162 RK_U32 height = mpp_frame_get_height(frame);
163 RK_U32 hor_stride = mpp_frame_get_hor_stride(frame);
164 RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
165 RK_U8 *p_buf = (RK_U8 *) mpp_buffer_get_ptr(mpp_frame_get_buffer(frame));
166
167 RK_U8 *psrc = p_buf;
168 RK_U8 *pdes = tmp;
169 RK_U32 size = 0;
170
171 if (pdes) {
172 if (hor_stride > w || ver_stride > h) {
173 RK_U32 step = MPP_MAX((hor_stride + w - 1) / w,
174 (ver_stride + h - 1) / h);
175 RK_U32 img_w = width / step;
176 RK_U32 img_h = height / step;
177
178 img_w -= img_w & 0x1;
179 img_h -= img_h & 0x1;
180 for (i = 0; i < img_h; i++) {
181 for (j = 0; j < img_w; j++)
182 pdes[j] = fetch_data(fmt, psrc, j * step);
183 pdes += img_w;
184 psrc += step * hor_stride;
185 }
186 psrc = p_buf + hor_stride * ver_stride;
187 pdes = tmp + img_w * img_h;
188 for (i = 0; i < (img_h / 2); i++) {
189 for (j = 0; j < (img_w / 2); j++) {
190 pdes[2 * j + 0] = fetch_data(fmt, psrc, 2 * j * step + 0);
191 pdes[2 * j + 1] = fetch_data(fmt, psrc, 2 * j * step + 1);
192 }
193 pdes += img_w;
194 psrc += step * hor_stride;
195 }
196 width = img_w;
197 height = img_h;
198 } else if (fmt == MPP_FMT_YUV420SP_10BIT) {
199 for (i = 0; i < height; i++) {
200 for (j = 0; j < width; j++)
201 pdes[j] = fetch_data(fmt, psrc, j);
202 pdes += width;
203 psrc += hor_stride;
204 }
205 psrc = p_buf + hor_stride * ver_stride;
206 pdes = tmp + width * height;
207 for (i = 0; i < height / 2; i++) {
208 for (j = 0; j < width; j++)
209 pdes[j] = fetch_data(fmt, psrc, j);
210 pdes += width;
211 psrc += hor_stride;
212 }
213 }
214 size = width * height * 1.5;
215 } else {
216 tmp = p_buf;
217 switch (fmt) {
218 case MPP_FMT_YUV420SP :
219 case MPP_FMT_YUV420P : {
220 size = hor_stride * ver_stride * 3 / 2;
221 } break;
222 case MPP_FMT_YUV422SP : {
223 size = hor_stride * ver_stride * 2;
224 } break;
225 case MPP_FMT_YUV444SP : {
226 size = hor_stride * ver_stride * 3;
227 } break;
228 case MPP_FMT_YUV420SP_10BIT : {
229 RK_U8 *base_y = p_buf;
230 RK_U8 *base_c = p_buf + hor_stride * ver_stride;
231 RK_U8 *tmp_line = (RK_U8 *)mpp_malloc(RK_U16, width);
232
233 if (!tmp_line) {
234 mpp_log("tmp_line malloc fail");
235 return;
236 }
237
238 for (i = 0; i < height; i++, base_y += hor_stride) {
239 for (j = 0; j < MPP_ALIGN(width, 8) / 8; j++)
240 rearrange_pix(tmp_line, base_y, j);
241 fwrite(tmp_line, width * sizeof(RK_U16), 1, fp);
242 }
243
244 for (i = 0; i < height / 2; i++, base_c += hor_stride) {
245 for (j = 0; j < MPP_ALIGN(width, 8) / 8; j++)
246 rearrange_pix(tmp_line, base_c, j);
247 fwrite(tmp_line, width * sizeof(RK_U16), 1, fp);
248 }
249 MPP_FREE(tmp_line);
250 }
251 default : break;
252 }
253 }
254 mpp_log("dump_yuv: w:h [%d:%d] stride [%d:%d] pts %lld\n",
255 width, height, hor_stride, ver_stride, mpp_frame_get_pts(frame));
256 if (size)
257 fwrite(tmp, 1, size, fp);
258 fflush(fp);
259 }
260
_ops_log(FILE * fp,const char * fmt,...)261 void _ops_log(FILE *fp, const char *fmt, ...)
262 {
263 struct tm tm_buf;
264 struct tm* ptm;
265 struct timespec tp;
266 char logs[64];
267 size_t len = 0;
268 va_list args;
269 va_start(args, fmt);
270
271 clock_gettime(CLOCK_REALTIME_COARSE, &tp);
272 ptm = localtime_r(&tp.tv_sec, &tm_buf);
273 len = strftime(logs, sizeof(logs), "%m-%d %H:%M:%S", ptm);
274 mpp_assert(len < sizeof(logs));
275 fprintf(fp, "%s.%03ld,", logs, tp.tv_nsec / 1000000);
276 vfprintf(fp, fmt, args);
277 fflush(fp);
278
279 va_end(args);
280 }
281
mpp_dump_init(MppDump * info)282 MPP_RET mpp_dump_init(MppDump *info)
283 {
284 if (!(mpp_debug & (MPP_DBG_DUMP_IN | MPP_DBG_DUMP_OUT | MPP_DBG_DUMP_CFG))) {
285 *info = NULL;
286 return MPP_OK;
287 }
288
289 MppDumpImpl *p = mpp_calloc(MppDumpImpl, 1);
290
291 mpp_env_get_u32("mpp_dump_width", &p->dump_width, 0);
292 mpp_env_get_u32("mpp_dump_height", &p->dump_height, 0);
293 p->dump_size = p->dump_width * p->dump_height * 3 / 2;
294
295 mpp_mutex_init(&p->lock);
296 p->debug = mpp_debug;
297 p->tid = syscall(SYS_gettid);
298 p->log_version = 0;
299 p->time_base = mpp_time();
300
301 *info = p;
302
303 return MPP_OK;
304 }
305
mpp_dump_deinit(MppDump * info)306 MPP_RET mpp_dump_deinit(MppDump *info)
307 {
308 if (info && *info) {
309 MppDumpImpl *p = (MppDumpImpl *)*info;
310
311 MPP_FCLOSE(p->fp_in);
312 MPP_FCLOSE(p->fp_out);
313 MPP_FCLOSE(p->fp_ops);
314 MPP_FREE(p->fp_buf);
315
316 mpp_mutex_destroy(&p->lock);
317 }
318
319 return MPP_OK;
320 }
321
mpp_ops_init(MppDump info,MppCtxType type,MppCodingType coding)322 MPP_RET mpp_ops_init(MppDump info, MppCtxType type, MppCodingType coding)
323 {
324 MppDumpImpl *p = (MppDumpImpl *)info;
325
326 if (NULL == info)
327 return MPP_OK;
328
329 mpp_mutex_lock(&p->lock);
330
331 p->type = type;
332 p->coding = coding;
333
334 if (type == MPP_CTX_DEC) {
335 if (p->debug & MPP_DBG_DUMP_IN)
336 p->fp_in = try_env_file("mpp_dump_in", dec_pkt_path, p->tid);
337
338 if (p->debug & MPP_DBG_DUMP_OUT) {
339 p->fp_out = try_env_file("mpp_dump_out", dec_frm_path, p->tid);
340 if (p->dump_size)
341 p->fp_buf = mpp_malloc(RK_U8, p->dump_size);
342 }
343
344 if (p->debug & MPP_DBG_DUMP_CFG)
345 p->fp_ops = try_env_file("mpp_dump_ops", dec_ops_path, p->tid);
346 } else {
347 if (p->debug & MPP_DBG_DUMP_IN) {
348 p->fp_in = try_env_file("mpp_dump_in", enc_frm_path, p->tid);
349 if (p->dump_size)
350 p->fp_buf = mpp_malloc(RK_U8, p->dump_size);
351 }
352
353 if (p->debug & MPP_DBG_DUMP_OUT)
354 p->fp_out = try_env_file("mpp_dump_out", enc_pkt_path, p->tid);
355
356 if (p->debug & MPP_DBG_DUMP_CFG)
357 p->fp_ops = try_env_file("mpp_dump_ops", enc_ops_path, p->tid);
358 }
359
360 if (p->fp_ops)
361 ops_log(p->fp_ops, "%d,%s,%d,%d\n", p->idx++, "init", type, coding);
362
363 mpp_mutex_unlock(&p->lock);
364
365 return MPP_OK;
366 }
367
mpp_ops_dec_put_pkt(MppDump info,MppPacket pkt)368 MPP_RET mpp_ops_dec_put_pkt(MppDump info, MppPacket pkt)
369 {
370 MppDumpImpl *p = (MppDumpImpl *)info;
371 if (NULL == p || NULL == pkt || NULL == p->fp_in)
372 return MPP_OK;
373
374 RK_U32 length = mpp_packet_get_length(pkt);
375
376 mpp_mutex_lock(&p->lock);
377
378 if (p->fp_in) {
379 fwrite(mpp_packet_get_data(pkt), 1, length, p->fp_in);
380 fflush(p->fp_in);
381 }
382
383 if (p->fp_ops) {
384 ops_log(p->fp_ops, "%d,%s,%d,%d\n", p->idx++, "pkt", p->pkt_offset, length);
385
386 p->pkt_offset += length;
387 }
388
389 mpp_mutex_unlock(&p->lock);
390
391 return MPP_OK;
392 }
393
mpp_ops_dec_get_frm(MppDump info,MppFrame frame)394 MPP_RET mpp_ops_dec_get_frm(MppDump info, MppFrame frame)
395 {
396 MppDumpImpl *p = (MppDumpImpl *)info;
397
398 if (NULL == p || NULL == frame || NULL == p->fp_out)
399 return MPP_OK;
400
401 mpp_mutex_lock(&p->lock);
402
403 MppBuffer buf = mpp_frame_get_buffer(frame);
404 RK_S32 fd = (buf) ? mpp_buffer_get_fd(buf) : (-1);
405 RK_U32 info_change = mpp_frame_get_info_change(frame);
406 RK_U32 error = mpp_frame_get_errinfo(frame);
407 RK_U32 discard = mpp_frame_get_discard(frame);
408
409 if (p->fp_ops) {
410 ops_log(p->fp_ops, "%d,%s,%d,%d,%d,%d,%lld\n", p->idx, "frm", fd,
411 info_change, error, discard, mpp_frame_get_pts(frame));
412 }
413
414 if (NULL == buf || fd < 0) {
415 mpp_err("failed to dump frame\n");
416 mpp_mutex_unlock(&p->lock);
417 return MPP_NOK;
418 }
419
420 dump_frame(p->fp_out, frame, p->fp_buf, p->dump_width, p->dump_height);
421
422 if (p->debug & MPP_DBG_DUMP_LOG) {
423 RK_S64 pts = mpp_frame_get_pts(frame);
424 RK_U32 width = mpp_frame_get_hor_stride(frame);
425 RK_U32 height = mpp_frame_get_ver_stride(frame);
426
427 mpp_log("yuv_info: [%d:%d] pts %lld", width, height, pts);
428 }
429 mpp_mutex_unlock(&p->lock);
430
431 return MPP_OK;
432 }
433
mpp_ops_enc_put_frm(MppDump info,MppFrame frame)434 MPP_RET mpp_ops_enc_put_frm(MppDump info, MppFrame frame)
435 {
436 MppDumpImpl *p = (MppDumpImpl *)info;
437
438 if (NULL == p || NULL == frame || NULL == p->fp_in)
439 return MPP_OK;
440
441 mpp_mutex_lock(&p->lock);
442
443 dump_frame(p->fp_in, frame, p->fp_buf, p->dump_width, p->dump_height);
444
445 if (p->debug & MPP_DBG_DUMP_LOG) {
446 RK_S64 pts = mpp_frame_get_pts(frame);
447 RK_U32 width = mpp_frame_get_hor_stride(frame);
448 RK_U32 height = mpp_frame_get_ver_stride(frame);
449
450 mpp_log("yuv_info: [%d:%d] pts %lld", width, height, pts);
451 }
452
453 mpp_mutex_unlock(&p->lock);
454
455 return MPP_OK;
456 }
457
mpp_ops_enc_get_pkt(MppDump info,MppPacket pkt)458 MPP_RET mpp_ops_enc_get_pkt(MppDump info, MppPacket pkt)
459 {
460 MppDumpImpl *p = (MppDumpImpl *)info;
461
462 if (NULL == p || NULL == pkt)
463 return MPP_OK;
464
465 RK_U32 length = mpp_packet_get_length(pkt);
466 mpp_mutex_lock(&p->lock);
467
468 if (p->fp_out) {
469 fwrite(mpp_packet_get_data(pkt), 1, length, p->fp_out);
470 fflush(p->fp_out);
471 }
472
473 mpp_mutex_unlock(&p->lock);
474
475 return MPP_OK;
476 }
477
mpp_ops_ctrl(MppDump info,MpiCmd cmd)478 MPP_RET mpp_ops_ctrl(MppDump info, MpiCmd cmd)
479 {
480 MppDumpImpl *p = (MppDumpImpl *)info;
481
482 if (NULL == p)
483 return MPP_OK;
484
485 mpp_mutex_lock(&p->lock);
486
487 if (p->fp_ops)
488 ops_log(p->fp_ops, "%d,%s,%d\n", p->idx, "ctrl", cmd);
489 mpp_mutex_unlock(&p->lock);
490
491 return MPP_OK;
492 }
493
mpp_ops_reset(MppDump info)494 MPP_RET mpp_ops_reset(MppDump info)
495 {
496 MppDumpImpl *p = (MppDumpImpl *)info;
497
498 if (NULL == p)
499 return MPP_OK;
500
501 mpp_mutex_lock(&p->lock);
502
503 if (p->fp_ops)
504 ops_log(p->fp_ops, "%d,%s\n", p->idx, "rst");
505 mpp_mutex_unlock(&p->lock);
506
507 return MPP_OK;
508 }
509