xref: /rockchip-linux_mpp/mpp/mpp_impl.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
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