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