/* SPDX-License-Identifier: Apache-2.0 OR MIT */ /* * Copyright (c) 2015 Rockchip Electronics Co., Ltd. */ #define MODULE_TAG "mpp_impl" #include #include #include #include #include "rk_mpi_cmd.h" #include "mpp_env.h" #include "mpp_mem.h" #include "mpp_time.h" #include "mpp_debug.h" #include "mpp_thread.h" #include "mpp_common.h" #include "mpp_impl.h" #define MAX_FILE_NAME_LEN 512 #define MAX_DUMP_WIDTH 960 #define MAX_DUMP_HEIGHT 540 #define ops_log(fp, fmt, ...) _ops_log(fp, fmt, ## __VA_ARGS__) typedef enum MppOpsType_e { MPP_DEC_OPS_BASE = 0, MPP_DEC_INIT = MPP_DEC_OPS_BASE, MPP_DEC_SE } MppOpsType; /* dump data */ typedef struct MppDumpImpl_t { MppMutex lock; RK_U32 log_version; RK_U32 debug; pid_t tid; RK_S64 time_base; MppCtxType type; MppCodingType coding; FILE *fp_in; // file for MppPacket FILE *fp_out; // file for MppFrame FILE *fp_ops; // file for decoder / encoder extra info RK_U8 *fp_buf; // for resample frame RK_U32 pkt_offset; RK_U32 dump_width; RK_U32 dump_height; RK_U32 dump_size; RK_U32 idx; } MppDumpImpl; typedef union OpsArgs_u { struct MppOpsInitArg_t { MppCtxType type; MppCodingType coding; } init_arg; struct MppOpsPktArg_t { RK_U32 offset; // offset in packet file RK_U32 length; // pakcet length RK_S64 pts; } pkt_arg; struct MppOpsFrmArg_t { RK_U32 fd; RK_U32 info_change; RK_U32 error; RK_U32 discard; RK_S64 pts; } frm_arg; struct MppOpCtrlArg_t { MpiCmd cmd; } ctrl_arg; } OpsArgs; typedef struct MppOpsInfo_t { RK_U32 idx; RK_U32 id; RK_S64 time; OpsArgs args; } MppOpsInfo; /* * decoder file dump: * dec_pkt - decoder input byte raw stream file * dec_cfg - decoder input stream offset and size info in format [u32 offset|u32 size] * dec_frm - decoder output frame file with snapshot method */ static const char dec_pkt_path[] = "/data/mpp_dec_in.bin"; static const char dec_ops_path[] = "/data/mpp_dec_ops.bin"; static const char dec_frm_path[] = "/data/mpp_dec_out.bin"; static const char enc_frm_path[] = "/data/mpp_enc_in.bin"; static const char enc_ops_path[] = "/data/mpp_enc_ops.bin"; static const char enc_pkt_path[] = "/data/mpp_enc_out.bin"; static FILE *try_env_file(const char *env, const char *path, pid_t tid) { const char *fname = NULL; FILE *fp = NULL; char name[MAX_FILE_NAME_LEN]; mpp_env_get_str(env, &fname, path); if (fname == path) { snprintf(name, sizeof(name) - 1, "%s-%d", path, tid); fname = name; } fp = fopen(fname, "w+b"); mpp_log("open %s %p for dump\n", fname, fp); return fp; } static RK_U8 fetch_data(RK_U32 fmt, RK_U8 *line, RK_U32 num) { RK_U32 offset = 0; RK_U32 value = 0; if (fmt == MPP_FMT_YUV420SP_10BIT) { offset = (num * 2) & 7; value = (line[num * 10 / 8] >> offset) | (line[num * 10 / 8 + 1] << (8 - offset)); value = (value & 0x3ff) >> 2; } else if (fmt == MPP_FMT_YUV420SP) { value = line[num]; } return (RK_U8)value; } static void rearrange_pix(RK_U8 *tmp_line, RK_U8 *base, RK_U32 n) { RK_U16 * pix = (RK_U16 *)(tmp_line + n * 16); RK_U16 * base_u16 = (RK_U16 *)(base + n * 10); pix[0] = base_u16[0] & 0x03FF; pix[1] = (base_u16[0] & 0xFC00) >> 10 | (base_u16[1] & 0x000F) << 6; pix[2] = (base_u16[1] & 0x3FF0) >> 4; pix[3] = (base_u16[1] & 0xC000) >> 14 | (base_u16[2] & 0x00FF) << 2; pix[4] = (base_u16[2] & 0xFF00) >> 8 | (base_u16[3] & 0x0003) << 8; pix[5] = (base_u16[3] & 0x0FFC) >> 2; pix[6] = (base_u16[3] & 0xF000) >> 12 | (base_u16[4] & 0x003F) << 4; pix[7] = (base_u16[4] & 0xFFC0) >> 6; } static void dump_frame(FILE *fp, MppFrame frame, RK_U8 *tmp, RK_U32 w, RK_U32 h) { RK_U32 i = 0, j = 0; RK_U32 fmt = (mpp_frame_get_fmt(frame) & MPP_FRAME_FMT_MASK); RK_U32 width = mpp_frame_get_width(frame); RK_U32 height = mpp_frame_get_height(frame); RK_U32 hor_stride = mpp_frame_get_hor_stride(frame); RK_U32 ver_stride = mpp_frame_get_ver_stride(frame); RK_U8 *p_buf = (RK_U8 *) mpp_buffer_get_ptr(mpp_frame_get_buffer(frame)); RK_U8 *psrc = p_buf; RK_U8 *pdes = tmp; RK_U32 size = 0; if (pdes) { if (hor_stride > w || ver_stride > h) { RK_U32 step = MPP_MAX((hor_stride + w - 1) / w, (ver_stride + h - 1) / h); RK_U32 img_w = width / step; RK_U32 img_h = height / step; img_w -= img_w & 0x1; img_h -= img_h & 0x1; for (i = 0; i < img_h; i++) { for (j = 0; j < img_w; j++) pdes[j] = fetch_data(fmt, psrc, j * step); pdes += img_w; psrc += step * hor_stride; } psrc = p_buf + hor_stride * ver_stride; pdes = tmp + img_w * img_h; for (i = 0; i < (img_h / 2); i++) { for (j = 0; j < (img_w / 2); j++) { pdes[2 * j + 0] = fetch_data(fmt, psrc, 2 * j * step + 0); pdes[2 * j + 1] = fetch_data(fmt, psrc, 2 * j * step + 1); } pdes += img_w; psrc += step * hor_stride; } width = img_w; height = img_h; } else if (fmt == MPP_FMT_YUV420SP_10BIT) { for (i = 0; i < height; i++) { for (j = 0; j < width; j++) pdes[j] = fetch_data(fmt, psrc, j); pdes += width; psrc += hor_stride; } psrc = p_buf + hor_stride * ver_stride; pdes = tmp + width * height; for (i = 0; i < height / 2; i++) { for (j = 0; j < width; j++) pdes[j] = fetch_data(fmt, psrc, j); pdes += width; psrc += hor_stride; } } size = width * height * 1.5; } else { tmp = p_buf; switch (fmt) { case MPP_FMT_YUV420SP : case MPP_FMT_YUV420P : { size = hor_stride * ver_stride * 3 / 2; } break; case MPP_FMT_YUV422SP : { size = hor_stride * ver_stride * 2; } break; case MPP_FMT_YUV444SP : { size = hor_stride * ver_stride * 3; } break; case MPP_FMT_YUV420SP_10BIT : { RK_U8 *base_y = p_buf; RK_U8 *base_c = p_buf + hor_stride * ver_stride; RK_U8 *tmp_line = (RK_U8 *)mpp_malloc(RK_U16, width); if (!tmp_line) { mpp_log("tmp_line malloc fail"); return; } for (i = 0; i < height; i++, base_y += hor_stride) { for (j = 0; j < MPP_ALIGN(width, 8) / 8; j++) rearrange_pix(tmp_line, base_y, j); fwrite(tmp_line, width * sizeof(RK_U16), 1, fp); } for (i = 0; i < height / 2; i++, base_c += hor_stride) { for (j = 0; j < MPP_ALIGN(width, 8) / 8; j++) rearrange_pix(tmp_line, base_c, j); fwrite(tmp_line, width * sizeof(RK_U16), 1, fp); } MPP_FREE(tmp_line); } default : break; } } mpp_log("dump_yuv: w:h [%d:%d] stride [%d:%d] pts %lld\n", width, height, hor_stride, ver_stride, mpp_frame_get_pts(frame)); if (size) fwrite(tmp, 1, size, fp); fflush(fp); } void _ops_log(FILE *fp, const char *fmt, ...) { struct tm tm_buf; struct tm* ptm; struct timespec tp; char logs[64]; size_t len = 0; va_list args; va_start(args, fmt); clock_gettime(CLOCK_REALTIME_COARSE, &tp); ptm = localtime_r(&tp.tv_sec, &tm_buf); len = strftime(logs, sizeof(logs), "%m-%d %H:%M:%S", ptm); mpp_assert(len < sizeof(logs)); fprintf(fp, "%s.%03ld,", logs, tp.tv_nsec / 1000000); vfprintf(fp, fmt, args); fflush(fp); va_end(args); } MPP_RET mpp_dump_init(MppDump *info) { if (!(mpp_debug & (MPP_DBG_DUMP_IN | MPP_DBG_DUMP_OUT | MPP_DBG_DUMP_CFG))) { *info = NULL; return MPP_OK; } MppDumpImpl *p = mpp_calloc(MppDumpImpl, 1); mpp_env_get_u32("mpp_dump_width", &p->dump_width, 0); mpp_env_get_u32("mpp_dump_height", &p->dump_height, 0); p->dump_size = p->dump_width * p->dump_height * 3 / 2; mpp_mutex_init(&p->lock); p->debug = mpp_debug; p->tid = syscall(SYS_gettid); p->log_version = 0; p->time_base = mpp_time(); *info = p; return MPP_OK; } MPP_RET mpp_dump_deinit(MppDump *info) { if (info && *info) { MppDumpImpl *p = (MppDumpImpl *)*info; MPP_FCLOSE(p->fp_in); MPP_FCLOSE(p->fp_out); MPP_FCLOSE(p->fp_ops); MPP_FREE(p->fp_buf); mpp_mutex_destroy(&p->lock); } return MPP_OK; } MPP_RET mpp_ops_init(MppDump info, MppCtxType type, MppCodingType coding) { MppDumpImpl *p = (MppDumpImpl *)info; if (NULL == info) return MPP_OK; mpp_mutex_lock(&p->lock); p->type = type; p->coding = coding; if (type == MPP_CTX_DEC) { if (p->debug & MPP_DBG_DUMP_IN) p->fp_in = try_env_file("mpp_dump_in", dec_pkt_path, p->tid); if (p->debug & MPP_DBG_DUMP_OUT) { p->fp_out = try_env_file("mpp_dump_out", dec_frm_path, p->tid); if (p->dump_size) p->fp_buf = mpp_malloc(RK_U8, p->dump_size); } if (p->debug & MPP_DBG_DUMP_CFG) p->fp_ops = try_env_file("mpp_dump_ops", dec_ops_path, p->tid); } else { if (p->debug & MPP_DBG_DUMP_IN) { p->fp_in = try_env_file("mpp_dump_in", enc_frm_path, p->tid); if (p->dump_size) p->fp_buf = mpp_malloc(RK_U8, p->dump_size); } if (p->debug & MPP_DBG_DUMP_OUT) p->fp_out = try_env_file("mpp_dump_out", enc_pkt_path, p->tid); if (p->debug & MPP_DBG_DUMP_CFG) p->fp_ops = try_env_file("mpp_dump_ops", enc_ops_path, p->tid); } if (p->fp_ops) ops_log(p->fp_ops, "%d,%s,%d,%d\n", p->idx++, "init", type, coding); mpp_mutex_unlock(&p->lock); return MPP_OK; } MPP_RET mpp_ops_dec_put_pkt(MppDump info, MppPacket pkt) { MppDumpImpl *p = (MppDumpImpl *)info; if (NULL == p || NULL == pkt || NULL == p->fp_in) return MPP_OK; RK_U32 length = mpp_packet_get_length(pkt); mpp_mutex_lock(&p->lock); if (p->fp_in) { fwrite(mpp_packet_get_data(pkt), 1, length, p->fp_in); fflush(p->fp_in); } if (p->fp_ops) { ops_log(p->fp_ops, "%d,%s,%d,%d\n", p->idx++, "pkt", p->pkt_offset, length); p->pkt_offset += length; } mpp_mutex_unlock(&p->lock); return MPP_OK; } MPP_RET mpp_ops_dec_get_frm(MppDump info, MppFrame frame) { MppDumpImpl *p = (MppDumpImpl *)info; if (NULL == p || NULL == frame || NULL == p->fp_out) return MPP_OK; mpp_mutex_lock(&p->lock); MppBuffer buf = mpp_frame_get_buffer(frame); RK_S32 fd = (buf) ? mpp_buffer_get_fd(buf) : (-1); RK_U32 info_change = mpp_frame_get_info_change(frame); RK_U32 error = mpp_frame_get_errinfo(frame); RK_U32 discard = mpp_frame_get_discard(frame); if (p->fp_ops) { ops_log(p->fp_ops, "%d,%s,%d,%d,%d,%d,%lld\n", p->idx, "frm", fd, info_change, error, discard, mpp_frame_get_pts(frame)); } if (NULL == buf || fd < 0) { mpp_err("failed to dump frame\n"); mpp_mutex_unlock(&p->lock); return MPP_NOK; } dump_frame(p->fp_out, frame, p->fp_buf, p->dump_width, p->dump_height); if (p->debug & MPP_DBG_DUMP_LOG) { RK_S64 pts = mpp_frame_get_pts(frame); RK_U32 width = mpp_frame_get_hor_stride(frame); RK_U32 height = mpp_frame_get_ver_stride(frame); mpp_log("yuv_info: [%d:%d] pts %lld", width, height, pts); } mpp_mutex_unlock(&p->lock); return MPP_OK; } MPP_RET mpp_ops_enc_put_frm(MppDump info, MppFrame frame) { MppDumpImpl *p = (MppDumpImpl *)info; if (NULL == p || NULL == frame || NULL == p->fp_in) return MPP_OK; mpp_mutex_lock(&p->lock); dump_frame(p->fp_in, frame, p->fp_buf, p->dump_width, p->dump_height); if (p->debug & MPP_DBG_DUMP_LOG) { RK_S64 pts = mpp_frame_get_pts(frame); RK_U32 width = mpp_frame_get_hor_stride(frame); RK_U32 height = mpp_frame_get_ver_stride(frame); mpp_log("yuv_info: [%d:%d] pts %lld", width, height, pts); } mpp_mutex_unlock(&p->lock); return MPP_OK; } MPP_RET mpp_ops_enc_get_pkt(MppDump info, MppPacket pkt) { MppDumpImpl *p = (MppDumpImpl *)info; if (NULL == p || NULL == pkt) return MPP_OK; RK_U32 length = mpp_packet_get_length(pkt); mpp_mutex_lock(&p->lock); if (p->fp_out) { fwrite(mpp_packet_get_data(pkt), 1, length, p->fp_out); fflush(p->fp_out); } mpp_mutex_unlock(&p->lock); return MPP_OK; } MPP_RET mpp_ops_ctrl(MppDump info, MpiCmd cmd) { MppDumpImpl *p = (MppDumpImpl *)info; if (NULL == p) return MPP_OK; mpp_mutex_lock(&p->lock); if (p->fp_ops) ops_log(p->fp_ops, "%d,%s,%d\n", p->idx, "ctrl", cmd); mpp_mutex_unlock(&p->lock); return MPP_OK; } MPP_RET mpp_ops_reset(MppDump info) { MppDumpImpl *p = (MppDumpImpl *)info; if (NULL == p) return MPP_OK; mpp_mutex_lock(&p->lock); if (p->fp_ops) ops_log(p->fp_ops, "%d,%s\n", p->idx, "rst"); mpp_mutex_unlock(&p->lock); return MPP_OK; }