linuxOS_D21X/source/artinchip/aic-mpp/mpp_test/pic_animation.c
2024-11-29 16:33:21 +08:00

329 lines
7.2 KiB
C

/*
* Copyright (C) 2020-2022 Artinchip Technology Co. Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* author: <qi.xu@artinchip.com>
* Desc: jpeg/png decode demo
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <pthread.h>
#include <errno.h>
#include <dirent.h>
#include <linux/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <video/artinchip_fb.h>
#include <linux/dma-buf.h>
#include <linux/dma-heap.h>
#include "mpp_decoder.h"
#include "mpp_log.h"
#define MAX_TEST_FILE 200
struct dec_ctx {
struct mpp_decoder *decoder;
char file_input[MAX_TEST_FILE][1024]; // test file name
int file_num; // test file number
};
static void print_help(void)
{
printf("Usage: pic_animation [OPTIONS] [SLICES PATH]\n\n"
"Options:\n"
" -d directory of input png files\n"
" -h help\n\n"
"End:\n");
}
static int get_file_size(FILE* fp)
{
int len = 0;
fseek(fp, 0, SEEK_END);
len = ftell(fp);
fseek(fp, 0, SEEK_SET);
return len;
}
static int set_fb_layer_alpha(int fb0_fd, int val)
{
int ret = 0;
struct aicfb_alpha_config alpha = {0};
if (fb0_fd < 0)
return -1;
alpha.layer_id = 1;
alpha.enable = 1;
alpha.mode = 1;
alpha.value = val;
ret = ioctl(fb0_fd, AICFB_UPDATE_ALPHA_CONFIG, &alpha);
if (ret < 0)
loge("fb ioctl() AICFB_UPDATE_ALPHA_CONFIG failed!");
return ret;
}
static void video_layer_set(int fb0_fd, struct mpp_buf *picture_buf)
{
struct aicfb_layer_data layer = {0};
int dmabuf_num = 0;
struct dma_buf_info dmabuf_fd[3];
int i;
if (fb0_fd < 0)
return;
layer.layer_id = 0;
layer.enable = 1;
layer.scale_size.width = picture_buf->size.width;
layer.scale_size.height= picture_buf->size.height;
layer.pos.x = 0;
layer.pos.y = 0;
layer.buf = *picture_buf;
if (picture_buf->format == MPP_FMT_ARGB_8888) {
dmabuf_num = 1;
} else if (picture_buf->format == MPP_FMT_RGBA_8888) {
dmabuf_num = 1;
} else if (picture_buf->format == MPP_FMT_RGB_888) {
dmabuf_num = 1;
} else if (picture_buf->format == MPP_FMT_YUV420P) {
dmabuf_num = 3;
} else if (picture_buf->format == MPP_FMT_YUV444P) {
dmabuf_num = 3;
} else if (picture_buf->format == MPP_FMT_YUV422P) {
dmabuf_num = 3;
} else if (picture_buf->format == MPP_FMT_YUV400) {
dmabuf_num = 1;
} else {
loge("no support picture foramt %d, default argb8888", picture_buf->format);
}
//* add dmabuf to de driver
for(i=0; i<dmabuf_num; i++) {
dmabuf_fd[i].fd = picture_buf->fd[i];
if (ioctl(fb0_fd, AICFB_ADD_DMABUF, &dmabuf_fd[i]) < 0)
loge("fb ioctl() AICFB_UPDATE_LAYER_CONFIG failed!");
}
//* update layer config (it is async interface)
if (ioctl(fb0_fd, AICFB_UPDATE_LAYER_CONFIG, &layer) < 0)
loge("fb ioctl() AICFB_UPDATE_LAYER_CONFIG failed!");
//* wait vsync (wait layer config)
ioctl(fb0_fd, AICFB_WAIT_FOR_VSYNC, NULL);
//* remove dmabuf to de driver
for(i=0; i<dmabuf_num; i++) {
if (ioctl(fb0_fd, AICFB_RM_DMABUF, &dmabuf_fd[i]) < 0)
loge("fb ioctl() AICFB_UPDATE_LAYER_CONFIG failed!");
}
}
static int render_frame(struct mpp_frame* frame, int fb0_fd)
{
struct fb_fix_screeninfo finfo;
if (ioctl(fb0_fd, FBIOGET_FSCREENINFO, &finfo) == -1) {
loge("read fixed information failed!");
close(fb0_fd);
return -1;
}
set_fb_layer_alpha(fb0_fd, 0);
video_layer_set(fb0_fd, &frame->buf);
return 0;
}
static int read_dir(char* path, struct dec_ctx* dec_data)
{
char* ptr = NULL;
struct dirent* dir_file;
DIR* dir = opendir(path);
if(dir == NULL) {
loge("read dir failed");
return -1;
}
while((dir_file = readdir(dir))) {
if(strcmp(dir_file->d_name, ".") == 0 || strcmp(dir_file->d_name, "..") == 0)
continue;
ptr = strrchr(dir_file->d_name, '.');
if(ptr == NULL)
continue;
if (strcmp(ptr, ".png") && strcmp(ptr, ".jpg"))
continue;
logi("name: %s", dir_file->d_name);
logi("path: %s", path);
strcpy(dec_data->file_input[dec_data->file_num], path);
logi("strcpy");
usleep(20);
strcat(dec_data->file_input[dec_data->file_num], dir_file->d_name);
usleep(20);
logi("i: %d, filename: %s", dec_data->file_num, dec_data->file_input[dec_data->file_num]);
dec_data->file_num ++;
if(dec_data->file_num >= MAX_TEST_FILE)
break;
}
return 0;
}
static long long get_now_us(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (long long)tv.tv_sec * 1000000ll + tv.tv_usec;
}
int main(int argc, char **argv)
{
int ret = 0;
int i;
int opt;
int dec_type;
int file_len;
int fb0_fd;
FILE* fp = NULL;
struct dec_ctx *dec_data = NULL;
dec_data = malloc(sizeof(struct dec_ctx));
memset(dec_data, 0, sizeof(struct dec_ctx));
if (argc < 2) {
print_help();
goto out;
}
while (1) {
opt = getopt(argc, argv, "d:h");
if (opt == -1) {
break;
}
switch (opt) {
case 'd':
read_dir(optarg, dec_data);
break;
case 'h':
default:
print_help();
goto out;
}
}
fb0_fd = open("/dev/fb0", O_RDWR);
if (fb0_fd < 0) {
logw("open fb0 failed!");
goto out;
}
long long time_start = get_now_us();
for(i=0; i<dec_data->file_num; i++) {
char* ptr = strrchr(dec_data->file_input[i], '.');
if (!strcmp(ptr, ".jpg")) {
dec_type = MPP_CODEC_VIDEO_DECODER_MJPEG;
} else if (!strcmp(ptr, ".png")) {
dec_type = MPP_CODEC_VIDEO_DECODER_PNG;
}
fp = fopen(dec_data->file_input[i], "rb");
if (fp == NULL) {
loge("open file failed");
goto out;
}
file_len = get_file_size(fp);
//* 1. create mpp_decoder
struct mpp_decoder* dec = mpp_decoder_create(dec_type);
struct decode_config config;
config.bitstream_buffer_size = 512*1024;
config.extra_frame_num = 0;
config.packet_count = 1;
// JPEG not supprt YUV2RGB
if(dec_type == MPP_CODEC_VIDEO_DECODER_MJPEG)
config.pix_fmt = MPP_FMT_YUV420P;
else if(dec_type == MPP_CODEC_VIDEO_DECODER_PNG)
config.pix_fmt = MPP_FMT_ARGB_8888;
//* 2. init mpp_decoder
mpp_decoder_init(dec, &config);
//* 3. get an empty packet from mpp_decoder
struct mpp_packet packet;
memset(&packet, 0, sizeof(struct mpp_packet));
mpp_decoder_get_packet(dec, &packet, file_len);
//* 4. copy data to packet
fread(packet.data, 1, file_len, fp);
packet.size = file_len;
packet.flag = PACKET_FLAG_EOS;
//* 5. put the packet to mpp_decoder
mpp_decoder_put_packet(dec, &packet);
//* 6. decode
ret = mpp_decoder_decode(dec);
if(ret < 0) {
loge("decode error");
goto out;
}
//* 7. get a decoded frame
struct mpp_frame frame;
memset(&frame, 0, sizeof(struct mpp_frame));
mpp_decoder_get_frame(dec, &frame);
//* 8. render this frame
render_frame(&frame, fb0_fd);
//* 9. return this frame
mpp_decoder_put_frame(dec, &frame);
//* 10. destroy mpp_decoder
mpp_decoder_destory(dec);
}
long long time_end = get_now_us();
logw("time: %lld", time_end - time_start);
float fps = (long long)dec_data->file_num * 1000000LL/ (time_end - time_start);
logw("speed: fps %.2f", fps);
//* disable layer
struct aicfb_layer_data layer = {0};
layer.enable = 0;
if(ioctl(fb0_fd, AICFB_UPDATE_LAYER_CONFIG, &layer) < 0)
loge("fb ioctl() AICFB_UPDATE_LAYER_CONFIG failed!");
out:
if (dec_data)
free(dec_data);
if (fb0_fd)
close(fb0_fd);
if (fp)
fclose(fp);
return ret;
}