/*
|
*
|
* Copyright 2015 Rockchip Electronics Co. LTD
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
|
#define MODULE_TAG "mpp_impl"
|
|
#include <time.h>
|
#include <stdarg.h>
|
#include <sys/types.h>
|
#include <sys/syscall.h>
|
|
#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 {
|
Mutex *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 struct MppOpsInfo_t {
|
RK_U32 idx;
|
RK_U32 id;
|
RK_S64 time;
|
|
union OpsArgs_u {
|
struct MppOpsInitArg_t {
|
MppCtxType type;
|
MppCodingType coding;
|
};
|
|
struct MppOpsPktArg_t {
|
RK_U32 offset; // offset in packet file
|
RK_U32 length; // pakcet length
|
RK_S64 pts;
|
};
|
|
struct MppOpsFrmArg_t {
|
RK_U32 fd;
|
RK_U32 info_change;
|
RK_U32 error;
|
RK_U32 discard;
|
RK_S64 pts;
|
};
|
|
struct MppOpCtrlArg_t {
|
MpiCmd cmd;
|
};
|
};
|
} 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 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);
|
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;
|
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));
|
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;
|
|
p->lock = new Mutex();
|
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);
|
|
if (p->lock) {
|
delete p->lock;
|
p->lock = NULL;
|
}
|
}
|
|
return MPP_OK;
|
}
|
|
MPP_RET mpp_ops_init(MppDump info, MppCtxType type, MppCodingType coding)
|
{
|
if (NULL == info)
|
return MPP_OK;
|
|
MppDumpImpl *p = (MppDumpImpl *)info;
|
AutoMutex auto_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);
|
|
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);
|
AutoMutex auto_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;
|
}
|
|
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;
|
|
AutoMutex auto_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");
|
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);
|
}
|
|
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;
|
|
AutoMutex auto_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);
|
}
|
|
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);
|
AutoMutex auto_lock(p->lock);
|
|
if (p->fp_out) {
|
fwrite(mpp_packet_get_data(pkt), 1, length, p->fp_out);
|
fflush(p->fp_out);
|
}
|
|
return MPP_OK;
|
}
|
|
MPP_RET mpp_ops_ctrl(MppDump info, MpiCmd cmd)
|
{
|
MppDumpImpl *p = (MppDumpImpl *)info;
|
if (NULL == p)
|
return MPP_OK;
|
|
AutoMutex auto_lock(p->lock);
|
|
if (p->fp_ops)
|
ops_log(p->fp_ops, "%d,%s,%d\n", p->idx, "ctrl", cmd);
|
|
return MPP_OK;
|
}
|
|
MPP_RET mpp_ops_reset(MppDump info)
|
{
|
MppDumpImpl *p = (MppDumpImpl *)info;
|
if (NULL == p)
|
return MPP_OK;
|
|
AutoMutex auto_lock(p->lock);
|
|
if (p->fp_ops)
|
ops_log(p->fp_ops, "%d,%s\n", p->idx, "rst");
|
|
return MPP_OK;
|
}
|