Files
BPI-CM9-Linux/aml-comp/vendor/amlogic/meson_videoserver/vscfuse/vsctest.cpp
T

1113 lines
33 KiB
C++

/*
* Copyright (C) 2024 Amlogic Corporation.
*
* 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.
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <linux/videodev2.h>
#include "vsc_fuse.h"
#include <linux/v4l2-ext-vsc.h>
#include <linux/v4l2-ext-hdmitx.h>
#include <video_tunnel.h>
#include <meson_drm.h>
#include "xf86drmMode.h"
#include "xf86drm.h"
#include "drm_fourcc.h"
#define NAME_LEN 32
#define FUNC_NAME_LEN 100
#define BUFFER_MAX_NUMBER 3
#define VT_TIME_STAMP 37510560
#define STR_HELPER(x) #x
#define SET_PARAMETER(name, v4l2id) void set_##name(int video_fd, char *par) \
{ \
struct v4l2_control ctl = { 0 }; \
\
ctl.id = v4l2id; \
get_int_for_flag(par, STR_HELPER(name), (int *)&ctl.value); \
int rc = ioctl(video_fd, VIDIOC_S_CTRL, &ctl); \
if (rc < 0) { \
fprintf(stderr, "set %s fail: %s\n", STR_HELPER(name), strerror(errno)); \
return; \
} \
}
#define GET_PARAMETER(name, v4l2id) void get_##name(int video_fd) \
{ \
struct v4l2_control ctl = { 0 }; \
\
ctl.id = v4l2id; \
\
int rc = ioctl(video_fd, VIDIOC_G_CTRL, &ctl); \
if (rc < 0) { \
fprintf(stderr, "get %s fail: %s\n", STR_HELPER(name), strerror(errno)); \
return; \
} \
fprintf(stderr, "%s: %d\n", STR_HELPER(name), ctl.value); \
}
int subscribe_array[] = {
V4L2_CID_EXT_VSC_SUBSCRIBE_ACTIVE_WIN,
V4L2_CID_EXT_VSC_SUBSCRIBE_APPLYING_DONE_WINDOW_REGION,
V4L2_CID_EXT_VSC_SUBSCRIBE_BSP_ERROR,
V4L2_CID_EXT_VSC_SUBSCRIBE_MUTE_OFF,
V4L2_CID_EXT_VSC_SUBSCRIBE_VIDEO_DELAY,
};
struct support_func {
const char *name;
void (*get_func)(int);
void (*set_func)(int, char *);
};
int get_num(char a)
{
if (a < '0') return 0;
return a - '0';
}
int get_big_num(char *start, int len)
{
char *p = start;
int res = 0;
for (int i = 0; i < len; i++) {
if (*p == 0) break;
res *= 10;
res += get_num(*p);
p++;
}
fprintf(stderr, "get big num is: %d\n", res);
return res;
}
static int parse_rect(char *src, struct v4l2_ext_video_rect *out) // crop={12,34,56,78}
{
char *s = NULL, *e = NULL;
char *p = NULL;
s = strstr(src, "{");
e = strstr(src, "}");
p = s + 1;
if (s == NULL || e == NULL)
return -1;
out->x = atoi(p);
p = strstr(p, ",");
p++;
out->y = atoi(p);
p = strstr(p, ",");
p++;
out->w = atoi(p);
p = strstr(p, ",");
p++;
out->h = atoi(p);
return 0;
}
static int get_rect_for_flag(char *src, const char *flag, struct v4l2_ext_video_rect *out)
{
char *p = NULL;
if (out == NULL)
return -1;
p = strstr(src, flag);
if (p == NULL)
return -1;
return parse_rect(p, out);
}
static int get_int_for_flag(char *src, const char *flag, int *value)
{
char *p = NULL;
if (value == NULL)
return -1;
p = strstr(src, flag);
if (p == NULL)
return -1;
p = strstr(p, "=");
if (p == NULL)
return -1;
p++;
*value = atoi(p);
return 0;
}
static int get_char_for_flag(char *src, const char *flag, unsigned char *value)
{
int val = 0;
int ret = get_int_for_flag(src, flag, &val);
if (ret == 0) {
if (val >= 0 && val <= 255)
*value = (unsigned char)val;
}
return ret;
}
void set_win_region(int video_fd, char *par)
{
struct v4l2_ext_controls ext_controls = {0};
struct v4l2_ext_control ext_control = {0};
struct v4l2_ext_vsc_win_region win;
int ret = 0;
memset(&win, 0, sizeof(win));
ret |= get_rect_for_flag(par, "crop", &win.in.crop);
ret |= get_rect_for_flag(par, "res", &win.in.res);
ret |= get_rect_for_flag(par, "out", &win.out);
ret |= get_rect_for_flag(par, "punch", &win.punch);
ret |= get_int_for_flag(par, "rot", (int *)&win.rotation);
if (ret) {
fprintf(stderr, "par error\n");
return;
}
ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
ext_controls.count = 1;
ext_controls.controls = &ext_control;
ext_controls.controls->id = V4L2_CID_EXT_VSC_WIN_REGION;
ext_controls.controls->ptr = (void *)&win;
int rc;
rc = ioctl(video_fd, VIDIOC_S_EXT_CTRLS, &ext_controls);
if (rc < 0) {
fprintf(stderr, "set win region fail: %s\n", strerror(errno));
return;
}
}
void get_win_region(int video_fd)
{
struct v4l2_ext_controls ext_controls = {0};
struct v4l2_ext_control ext_control = {0};
struct v4l2_ext_vsc_win_region win;
memset(&win, 0, sizeof(win));
ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
ext_controls.count = 1;
ext_controls.controls = &ext_control;
ext_controls.controls->id = V4L2_CID_EXT_VSC_WIN_REGION;
ext_controls.controls->ptr = (void *)&win;
int rc;
rc = ioctl(video_fd, VIDIOC_G_EXT_CTRLS, &ext_controls);
if (rc < 0) {
fprintf(stderr, "get win region fail: %s\n", strerror(errno));
return;
}
fprintf(stderr, "win data: res {%d, %d, %d, %d}"
" crop {%d, %d, %d, %d}"
" out {%d, %d, %d, %d}"
" punch {%d, %d, %d, %d}"
" rot %d\n",
win.in.res.x, win.in.res.y, win.in.res.w, win.in.res.h,
win.in.crop.x, win.in.crop.y, win.in.crop.w, win.in.crop.h,
win.out.x, win.out.y, win.out.w, win.out.h,
win.punch.x, win.punch.y, win.punch.w, win.punch.h, win.rotation);
}
void set_connect_info(int video_fd, char *par)
{
struct v4l2_ext_controls ext_controls = {0};
struct v4l2_ext_control ext_control = {0};
struct v4l2_ext_vsc_connect_info con;
int ret = 0;
memset(&con, 0, sizeof(con));
ret |= get_int_for_flag(par, "attr", (int *)&con.in.attr);
ret |= get_int_for_flag(par, "index", (int *)&con.in.index);
ret |= get_int_for_flag(par, "src", (int *)&con.in.src);
ret |= get_int_for_flag(par, "out", (int *)&con.out);
if (ret) {
fprintf(stderr, "par error\n");
return;
}
ext_control.id = V4L2_CID_EXT_VSC_CONNECT_INFO;
ext_control.ptr = (void *)&con;
ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
ext_controls.count = 1;
ext_controls.controls = &ext_control;
int rc;
rc = ioctl(video_fd, VIDIOC_S_EXT_CTRLS, &ext_controls);
if (rc < 0) {
fprintf(stderr, "set connect info fail: %s\n", strerror(errno));
return;
}
}
void get_connect_info(int video_fd)
{
struct v4l2_ext_controls ext_controls = {0};
struct v4l2_ext_control ext_control = {0};
struct v4l2_ext_vsc_connect_info con;
memset(&con, 0, sizeof(con));
ext_control.id = V4L2_CID_EXT_VSC_CONNECT_INFO;
ext_control.ptr = (void *)&con;
ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
ext_controls.count = 1;
ext_controls.controls = &ext_control;
int rc;
rc = ioctl(video_fd, VIDIOC_G_EXT_CTRLS, &ext_controls);
if (rc < 0) {
fprintf(stderr, "get connect info fail: %s\n", strerror(errno));
return;
}
fprintf(stderr, "connectinfo: attr %d index %d src %d out %d\n",
con.in.attr, con.in.index, con.in.src, con.out);
}
void set_win_prop(int video_fd, char *par)
{
struct v4l2_ext_controls ext_controls = {0};
struct v4l2_ext_control ext_control = {0};
struct v4l2_ext_vsc_win_prop prop;
memset(&prop, 0, sizeof(prop));
int ret = 0;
ret |= get_int_for_flag(par, "win", (int *)&prop.win_mode);
ret |= get_int_for_flag(par, "mirror", (int *)&prop.mirror_mode);
ret |= get_int_for_flag(par, "mem", (int *)&prop.mem_type);
if (ret != 0) {
fprintf(stderr, "set win prop fail, par error\n");
return;
}
ext_control.id = V4L2_CID_EXT_VSC_WIN_PROP;
ext_control.ptr = (void *)&prop;
ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
ext_controls.count = 1;
ext_controls.controls = &ext_control;
int rc;
rc = ioctl(video_fd, VIDIOC_S_EXT_CTRLS, &ext_controls);
if (rc < 0) {
fprintf(stderr, "set win prop fail: %s\n", strerror(errno));
return;
}
}
void get_win_prop(int video_fd)
{
struct v4l2_ext_controls ext_controls = {0};
struct v4l2_ext_control ext_control = {0};
struct v4l2_ext_vsc_win_prop prop;
memset(&prop, 0, sizeof(prop));
ext_control.id = V4L2_CID_EXT_VSC_WIN_PROP;
ext_control.ptr = (void *)&prop;
ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
ext_controls.count = 1;
ext_controls.controls = &ext_control;
int rc;
rc = ioctl(video_fd, VIDIOC_G_EXT_CTRLS, &ext_controls);
if (rc < 0) {
fprintf(stderr, "get win prop fail: %s\n", strerror(errno));
return;
}
fprintf(stderr, "winprop: win mode %d mirror mode %d mem type %d\n",
prop.win_mode, prop.mirror_mode, prop.mem_type);
}
void set_zorder(int video_fd, char *par)
{
struct v4l2_ext_controls ext_controls = { 0 };
struct v4l2_ext_control ext_control = { 0 };
struct v4l2_ext_vsc_zorder z = { 0 };
int ret = 0;
ret |= get_char_for_flag(par, "alpha", &z.alpha);
ret |= get_char_for_flag(par, "zorder", &z.zorder);
if (ret != 0) {
fprintf(stderr, "set zorder fail, par error\n");
return;
}
ext_control.id = V4L2_CID_EXT_VSC_ZORDER;
ext_control.ptr = (void *)&z;
ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
ext_controls.count = 1;
ext_controls.controls = &ext_control;
int rc = ioctl(video_fd, VIDIOC_S_EXT_CTRLS, &ext_controls);
if (rc < 0) {
fprintf(stderr, "set zorder fail: %s\n", strerror(errno));
return;
}
}
void get_zorder(int video_fd)
{
struct v4l2_ext_controls ext_controls = { 0 };
struct v4l2_ext_control ext_control = { 0 };
struct v4l2_ext_vsc_zorder z = { 0 };
ext_control.id = V4L2_CID_EXT_VSC_ZORDER;
ext_control.ptr = (void *)&z;
ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
ext_controls.count = 1;
ext_controls.controls = &ext_control;
int rc = ioctl(video_fd, VIDIOC_G_EXT_CTRLS, &ext_controls);
if (rc < 0) {
fprintf(stderr, "get zorder fail: %s\n", strerror(errno));
return;
}
fprintf(stderr, "zorder: alpha %d, zorder %d\n",
z.alpha, z.zorder);
}
SET_PARAMETER(hdr, V4L2_CID_EXT_VSC_HDR_TYPE)
GET_PARAMETER(hdr, V4L2_CID_EXT_VSC_HDR_TYPE)
SET_PARAMETER(freeze, V4L2_CID_EXT_VSC_FREEZE)
GET_PARAMETER(freeze, V4L2_CID_EXT_VSC_FREEZE)
SET_PARAMETER(freeze_frame, V4L2_CID_EXT_VSC_FREEZE_FRAME_BUFFER)
GET_PARAMETER(freeze_frame, V4L2_CID_EXT_VSC_FREEZE_FRAME_BUFFER)
SET_PARAMETER(frame_delay, V4L2_CID_EXT_VSC_FRAME_DELAY)
GET_PARAMETER(frame_delay, V4L2_CID_EXT_VSC_FRAME_DELAY)
SET_PARAMETER(rgb444, V4L2_CID_EXT_VSC_RGB444)
GET_PARAMETER(rgb444, V4L2_CID_EXT_VSC_RGB444)
SET_PARAMETER(occupation_sub_scaler, V4L2_CID_EXT_VSC_OCCUPATION_SUB_SCALER)
GET_PARAMETER(occupation_sub_scaler, V4L2_CID_EXT_VSC_OCCUPATION_SUB_SCALER)
SET_PARAMETER(adaptive_stream, V4L2_CID_EXT_VSC_ADAPTIVE_STREAM)
GET_PARAMETER(adaptive_stream, V4L2_CID_EXT_VSC_ADAPTIVE_STREAM)
SET_PARAMETER(bg_color, V4L2_CID_BG_COLOR)
GET_PARAMETER(bg_color, V4L2_CID_BG_COLOR)
GET_PARAMETER(hdmitx_connection, V4L2_CID_EXT_HDMITX_CONNECTION_STATE)
GET_PARAMETER(hdmitx_hdr_mode, V4L2_CID_EXT_HDMITX_HDR_MODE)
GET_PARAMETER(hdmitx_hdcp_version, V4L2_CID_EXT_HDMITX_HDCP_VERSION)
SET_PARAMETER(hdmitx_hdr_policy, V4L2_CID_EXT_HDMITX_HDR_POLICY)
GET_PARAMETER(hdmitx_hdr_policy, V4L2_CID_EXT_HDMITX_HDR_POLICY)
SET_PARAMETER(hdmitx_av_mute, V4L2_CID_EXT_HDMITX_AVMUTE)
SET_PARAMETER(hdmitx_hdcp_auth, V4L2_CID_EXT_HDMITX_HDCP_AUTH)
GET_PARAMETER(hdmitx_hdcp_status, V4L2_CID_EXT_HDMITX_HDCP_STATUS)
SET_PARAMETER(scan_mode, V4L2_CID_EXT_VSC_SCAN_MODE)
GET_PARAMETER(scan_mode, V4L2_CID_EXT_VSC_SCAN_MODE)
SET_PARAMETER(pixed_to_pixed, V4L2_CID_EXT_VSC_PIXEL_TO_PIXEL)
GET_PARAMETER(pixed_to_pixed, V4L2_CID_EXT_VSC_PIXEL_TO_PIXEL)
void set_orbit_policy(int video_fd, char *par)
{
struct v4l2_ext_controls ext_controls = {0};
struct v4l2_ext_control ext_control = {0};
struct v4l2_ext_vsc_orbit_policy policy;
int ret = 0;
unsigned char on_off = 0;
struct v4l2_ext_video_rect t;
struct v4l2_ext_video_rect x;
memset(&policy, 0, sizeof(policy));
ret |= get_char_for_flag(par, "on", &on_off);
ret |= get_rect_for_flag(par, "osdr", &policy.osd_resolution);
ret |= get_rect_for_flag(par, "panelr", &policy.panel_resolution);
ret |= get_rect_for_flag(par, "step", &t);
ret |= get_rect_for_flag(par, "size", &x);
ret |= get_int_for_flag(par, "vscan", (int *)&policy.region.video_scan);
ret |= get_int_for_flag(par, "oscan", (int *)&policy.region.osd_scan);
if (ret) {
fprintf(stderr, "par error\n");
return;
}
policy.orbit_on_off = (enum v4l2_ext_vsc_orbit_on_off)on_off;
policy.region.video_size.x = x.x;
policy.region.video_size.y = x.y;
policy.region.osd_size.x = x.w;
policy.region.osd_size.y = x.h;
policy.video_step.x = t.x;
policy.video_step.y = t.y;
policy.osd_step.x = t.w;
policy.osd_step.y = t.h;
ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
ext_controls.count = 1;
ext_controls.controls = &ext_control;
ext_controls.controls->id = V4L2_CID_EXT_VSC_ORBIT_POLICY;
ext_controls.controls->ptr = (void *)&policy;
int rc;
rc = ioctl(video_fd, VIDIOC_S_EXT_CTRLS, &ext_controls);
if (rc < 0) {
fprintf(stderr, "set orbit policy fail: %s\n", strerror(errno));
return;
}
}
void get_orbit_policy(int video_fd)
{
struct v4l2_ext_controls ext_controls = {0};
struct v4l2_ext_control ext_control = {0};
struct v4l2_ext_vsc_orbit_policy policy;
memset(&policy, 0, sizeof(policy));
ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
ext_controls.count = 1;
ext_controls.controls = &ext_control;
ext_controls.controls->id = V4L2_CID_EXT_VSC_ORBIT_POLICY;
ext_controls.controls->ptr = (void *)&policy;
int rc;
rc = ioctl(video_fd, VIDIOC_G_EXT_CTRLS, &ext_controls);
if (rc < 0) {
fprintf(stderr, "get orbit policy fail: %s\n", strerror(errno));
return;
}
fprintf(stderr, "on_off: %d, osd res: {%d, %d, %d, %d}"
" panel res: {%d, %d, %d, %d}"
" regin: {vs: {%d, %d}, vsan: %d, os: {%d, %d}, oscan: %d}"
" vstep: {%d, %d}, ostep: {%d, %d}\n",
policy.orbit_on_off, policy.osd_resolution.x, policy.osd_resolution.y, policy.osd_resolution.w, policy.osd_resolution.h,
policy.panel_resolution.x, policy.panel_resolution.y, policy.panel_resolution.w, policy.panel_resolution.h,
policy.region.video_size.x, policy.region.video_size.y, policy.region.video_scan,
policy.region.osd_size.x, policy.region.osd_size.y, policy.region.osd_scan,
policy.video_step.x, policy.video_step.y, policy.osd_step.x, policy.osd_step.y);
}
void set_seamless_info(int video_fd, char *par)
{
struct v4l2_ext_controls ext_controls = {0};
struct v4l2_ext_control ext_control = {0};
struct v4l2_ext_vsc_seamless_info info;
int ret = 0;
memset(&info, 0, sizeof(info));
ret |= get_char_for_flag(par, "cp", &info.cp_seamless);
ret |= get_char_for_flag(par, "dtv", &info.dtv_seamless);
ret |= get_char_for_flag(par, "ma", &info.magnification);
if (ret) {
fprintf(stderr, "par error\n");
return;
}
ext_control.id = V4L2_CID_EXT_VSC_SEAMLESS_MODE;
ext_control.ptr = (void *)&info;
ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
ext_controls.count = 1;
ext_controls.controls = &ext_control;
int rc;
rc = ioctl(video_fd, VIDIOC_S_EXT_CTRLS, &ext_controls);
if (rc < 0) {
fprintf(stderr, "set seamless info fail: %s\n", strerror(errno));
return;
}
}
void get_seamless_info(int video_fd)
{
struct v4l2_ext_controls ext_controls = {0};
struct v4l2_ext_control ext_control = {0};
struct v4l2_ext_vsc_seamless_info info;
memset(&info, 0, sizeof(info));
ext_control.id = V4L2_CID_EXT_VSC_SEAMLESS_MODE;
ext_control.ptr = (void *)&info;
ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
ext_controls.count = 1;
ext_controls.controls = &ext_control;
int rc;
rc = ioctl(video_fd, VIDIOC_G_EXT_CTRLS, &ext_controls);
if (rc < 0) {
fprintf(stderr, "get seamless info fail: %s\n", strerror(errno));
return;
}
fprintf(stderr, "seamless info: cp: %d, dtv: %d, magnification: %d\n",
info.cp_seamless, info.dtv_seamless, info.magnification);
}
void get_event(int video_fd)
{
struct v4l2_event event;
int rc;
rc = ioctl(video_fd, VIDIOC_DQEVENT, &event);
if (rc < 0) {
fprintf(stderr, "get event fail: %s\n", strerror(errno));
return;
}
fprintf(stderr, "event is ok\n");
}
void set_subscribe_event(int video_fd, char *par)
{
struct v4l2_event_subscription event = { 0 };
int id = 0;
get_int_for_flag(par, "id", &id);
event.type = V4L2_EVENT_CTRL;
event.id = subscribe_array[id];
int rc = ioctl(video_fd, VIDIOC_SUBSCRIBE_EVENT, &event);
if (rc < 0) {
fprintf(stderr, "set event fail: %s\n", strerror(errno));
return;
}
}
void get_alpha_zorder(int video_fd)
{
struct v4l2_ext_controls ext_controls = { 0 };
struct v4l2_ext_control ext_control = { 0 };
struct v4l2_ext_vsc_zorder_info z = { 0 };
ext_control.id = V4L2_CID_EXT_VSC_ALPHA_ZORDER;
ext_control.ptr = (void *)&z;
ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
ext_controls.count = 1;
ext_controls.controls = &ext_control;
int rc = ioctl(video_fd, VIDIOC_G_EXT_CTRLS, &ext_controls);
if (rc < 0) {
fprintf(stderr, "get zorder fail: %s\n", strerror(errno));
return;
}
fprintf(stderr, "zorder data length: %d\n", z.length);
for (int i = 0; i < z.length; i++)
fprintf(stderr, "zorder[%d]: alpha %d, zorder %d\n",
i, z.z[i].alpha, z.z[i].zorder);
}
void set_alpha_zorder(int video_fd, char *par)
{
struct v4l2_ext_controls ext_controls = { 0 };
struct v4l2_ext_control ext_control = { 0 };
struct v4l2_ext_vsc_zorder_info z = { 0 };
int ret;
ret = get_int_for_flag(par, "len", &z.length);
for (int i = 0; i < z.length; i++) {
ret |= get_char_for_flag(par, "alpha", &z.z[i].alpha);
ret |= get_char_for_flag(par, "zorder", &z.z[i].zorder);
}
if (ret) {
fprintf(stderr, "par error\n");
return;
}
ext_control.id = V4L2_CID_EXT_VSC_ALPHA_ZORDER;
ext_control.ptr = (void *)&z;
ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
ext_controls.count = 1;
ext_controls.controls = &ext_control;
int rc = ioctl(video_fd, VIDIOC_S_EXT_CTRLS, &ext_controls);
if (rc < 0) {
fprintf(stderr, "set zorder fail: %s\n", strerror(errno));
return;
}
}
void test_video_play(int video_fd, int flag, int w, int h)
{
const char *video_info;
char buffer[200] = { 0 };
if (flag == 0) { // local video/dtv
video_info = "attr=0,index=0,src=4,out=1";
} else if (flag == 1) { // hdmi
video_info = "attr=0,index=0,src=3,out=1";
} else if (flag == 2) { // VO
video_info = "attr=0,index=0,src=5,out=1";
} else if (flag == 3) { // atv
video_info = "attr=0,index=0,src=1,out=1";
}
strcpy(buffer, video_info);
set_connect_info(video_fd, buffer);
snprintf(buffer, sizeof(buffer), "crop={0,0,%d,%d},res={0,0,%d,%d},"
"out={0,0,3840,2160},punch={0,0,%d,%d},rot=0",
w, h, w, h, w, h);
set_win_region(video_fd, buffer);
}
struct ctx_info {
int fd;
bool exitThread;
};
void* PollThreadMain(void *data) {
struct ctx_info *ctx = (struct ctx_info *)data;
int fd = ctx->fd;
struct pollfd pfd;
pfd.fd = fd;
pfd.events = POLLIN;
pfd.revents = 0;
int pollrtn;
fprintf(stderr, "PollThreadMain enter\n");
while (true) {
if (ctx->exitThread) {
pthread_exit(0);
return NULL;
}
pollrtn = poll(&pfd, 1, 32);
if (pollrtn > 0) {
if (pfd.revents & POLLIN) {
struct v4l2_event event;
int rc = ioctl(fd, VIDIOC_DQEVENT, &event);
if (rc < 0) {
fprintf(stderr, "get event fail: %s\n", strerror(errno));
return NULL;
}
fprintf(stderr, "event id: %d\n", event.id);
if (event.id == V4L2_CID_EXT_VSC_SUBSCRIBE_APPLYING_DONE_WINDOW_REGION) {
fprintf(stderr, "scaler:%d, x:%d, y:%d, w:%d, h:%d, time:%d,"
" px:%d, py:%d, pw:%d, ph:%d\n",
event.u.data[0],
event.u.data[2] * 256 + event.u.data[1],
event.u.data[4] * 256 + event.u.data[3],
event.u.data[6] * 256 + event.u.data[5],
event.u.data[8] * 256 + event.u.data[7],
event.u.data[10] * 256 + event.u.data[9],
event.u.data[12] * 256 + event.u.data[11],
event.u.data[14] * 256 + event.u.data[13],
event.u.data[16] * 256 + event.u.data[15],
event.u.data[18] * 256 + event.u.data[17]);
}
if (event.id == V4L2_CID_EXT_VSC_SUBSCRIBE_BSP_ERROR) {
fprintf(stderr, "bsp error: %s\n", event.u.data);
}
if (event.id == V4L2_CID_EXT_VSC_SUBSCRIBE_MUTE_OFF) {
fprintf(stderr, "mute off\n");
}
}
}
}
}
/* tunnel producer */
struct pro_buffer {
int fd;
void * img;
int handle;
int width;
int height;
int size;
};
struct pro_data {
int tunnel_fd;
int tunnel_id;
bool is_exit;
pthread_t thread_id;
int drmFd;
struct pro_buffer buffer[BUFFER_MAX_NUMBER];
};
static int producer_alloc_buffer(struct pro_data *ctx,
uint32_t width, uint32_t height)
{
if (!ctx)
return -1;
int drmfd = -1;
struct drm_meson_gem_create arg;
struct drm_mode_map_dumb map;
struct pro_buffer *buffer = ctx->buffer;
uint32_t stride;
int ret;
if (drmfd < 0) {
drmfd = drmOpen("meson", NULL);
if (drmfd < 0) {
printf("failed to open drm: %s\n", strerror(errno));
return -1;
}
drmDropMaster(drmfd);
}
ctx->drmFd = drmfd;
memset(&arg, 0, sizeof(arg));
memset(&map, 0, sizeof(map));
stride = width;
arg.flags = MESON_USE_VIDEO_PLANE;
arg.size = stride * height * 3 / 2;
for (int i = 0 ;i < BUFFER_MAX_NUMBER; i++) {
if (buffer[i].img)
continue;
memset(&buffer[i], 0, sizeof(buffer[i]));
ret = ioctl(drmfd, DRM_IOCTL_MESON_GEM_CREATE, &arg);
if (ret) {
printf("alloc buffer fail: %s\n", strerror(errno));
return -1;
}
drmPrimeHandleToFD(drmfd, arg.handle, 0, &buffer[i].fd);
printf("buffer info: handle: %d, patich: %d, size: %lld, fd: %d\n",
arg.handle, width, arg.size, buffer[i].fd);
printf("buffer info: width = %u, height = %u\n", width, height);
map.handle = arg.handle;
ret = drmIoctl(drmfd, DRM_IOCTL_MODE_MAP_DUMB, &map);
if (ret) {
printf("failed to map dumb buffer: %s\n",strerror(errno));
return -1;
}
printf("map offset: %lld, fd: %d, size: %lld\n",
map.offset, drmfd, arg.size);
buffer[i].img = mmap64(NULL, arg.size, PROT_READ | PROT_WRITE, MAP_SHARED, drmfd, map.offset);
if (buffer[i].img == MAP_FAILED) {
printf("failed to map buffer: %s\n", strerror(errno));
return -1;
}
memset(buffer[i].img, 0, arg.size);
buffer[i].width = width;
buffer[i].height = height;
buffer[i].handle = arg.handle;
buffer[i].size = arg.size;
}
return 0;
}
int producer_free_buffer(struct pro_data *ctx)
{
if (!ctx)
return -1;
struct pro_buffer *buffer = ctx->buffer;
for (int i = 0; i < BUFFER_MAX_NUMBER; i++) {
if (buffer[i].img) {
munmap(buffer[i].img, buffer[i].size);
buffer[i].img = NULL;
}
if (buffer[i].fd > 0)
close(buffer[i].fd);
if (buffer[i].handle > 0) {
struct drm_mode_destroy_dumb arg;
memset(&arg, 0, sizeof(arg));
arg.handle = buffer[i].handle;
ioctl(ctx->drmFd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
printf("free handle: %d\n", arg.handle);
}
}
return 0;
}
void fill_nv12_solid(uint8_t *data,
int width, int height,
uint8_t y_val, uint8_t u_val, uint8_t v_val)
{
if (!data || width <= 0 || height <= 0 ||
width % 2 != 0 || height % 2 != 0) {
return;
}
int y_size = width * height;
int uv_width = width / 2;
int uv_height = height / 2;
memset(data, y_val, y_size);
uint8_t *uv_start = data + y_size;
uint8_t *uv_line = (uint8_t *)malloc(width);
for (int j = 0; j < uv_width; j++) {
uv_line[j * 2] = u_val;
uv_line[j * 2 + 1] = v_val;
}
for (int i = 0; i < uv_height; i++) {
memcpy(uv_start + i * width, uv_line, width);
}
free(uv_line);
}
static void *vt_producer_thread(void *arg) {
struct pro_data *ctx = (struct pro_data *)arg;
int dequeue_fd = -1, fence_fd;
int ret;
int buffer_index = 0;
meson_vt_connect(ctx->tunnel_fd, ctx->tunnel_id, 0);
while (!ctx->is_exit) {
meson_vt_queue_buffer(ctx->tunnel_fd,
ctx->tunnel_id, ctx->buffer[buffer_index].fd, -1, VT_TIME_STAMP);
fprintf(stderr, "queuebuffer fd:%d to tunnel:%d\n",
ctx->buffer[buffer_index].fd, ctx->tunnel_id);
sleep(1);
dequeue_fd = -1;
ret = meson_vt_dequeue_buffer(ctx->tunnel_fd,
ctx->tunnel_id, &dequeue_fd, &fence_fd);
fprintf(stderr, "dequeubuffer fd:%d from tunnel:%d, ret: %d\n",
dequeue_fd, ctx->tunnel_id, ret);
buffer_index++;
if (buffer_index >= BUFFER_MAX_NUMBER)
buffer_index = 0;
}
pthread_exit(0);
return NULL;
}
static void start_producer(struct pro_data *ctx, int id)
{
int dev_fd = meson_vt_open();
printf("open videotunnel dev fd:%d\n", dev_fd);
ctx->tunnel_fd = dev_fd;
ctx->is_exit = false;
ctx->tunnel_id = id;
printf("alloc viduotunnel id:%d\n", ctx->tunnel_id);
producer_alloc_buffer(ctx, 960, 540);
fill_nv12_solid((uint8_t *)ctx->buffer[0].img, 960, 540, 76, 84, 255); // red
fill_nv12_solid((uint8_t *)ctx->buffer[1].img, 960, 540, 149, 43, 21); // green
fill_nv12_solid((uint8_t *)ctx->buffer[2].img, 960, 540, 29, 239, 102); // blue
pthread_create(&ctx->thread_id, NULL, vt_producer_thread, ctx);
}
static void stop_producer(struct pro_data *ctx)
{
ctx->is_exit = true;
if (ctx->thread_id)
pthread_join(ctx->thread_id, NULL);
meson_vt_disconnect(ctx->tunnel_fd, ctx->tunnel_id, 0);
meson_vt_free_id(ctx->tunnel_fd, ctx->tunnel_id);
meson_vt_close(ctx->tunnel_fd);
producer_free_buffer(ctx);
}
struct support_func g_func[] = {
{ "WindowProp", get_win_prop, set_win_prop },
{ "ConnectInfo", get_connect_info, set_connect_info },
{ "WindowRegion", get_win_region, set_win_region },
{ "Zorder", get_zorder, set_zorder },
{ "Hdr", get_hdr, set_hdr },
{ "Freeze", get_freeze, set_freeze },
{ "Freeze_frame", get_freeze_frame, set_freeze_frame },
{ "Frame_delay", get_frame_delay, set_frame_delay },
{ "rgb444", get_rgb444, set_rgb444 },
{ "occupation_sub_scaler", get_occupation_sub_scaler, set_occupation_sub_scaler },
{ "adaptive_stream", get_adaptive_stream, set_adaptive_stream },
{ "bg_color", get_bg_color, set_bg_color },
{ "hdmitx_connection", get_hdmitx_connection, NULL },
{ "hdmitx_hdr_mode", get_hdmitx_hdr_mode, NULL },
{ "hdmitx_hdcp_version", get_hdmitx_hdcp_version, NULL },
{ "hdmitx_hdr_policy", get_hdmitx_hdr_policy, set_hdmitx_hdr_policy },
{ "hdmitx_av_mute", NULL, set_hdmitx_av_mute },
{ "hdmitx_hdcp_auth", NULL, set_hdmitx_hdcp_auth },
{ "hdmitx_hdcp_status", get_hdmitx_hdcp_status, NULL },
{ "scan_mode", get_scan_mode, set_scan_mode },
{ "pixed_to_pixed", get_pixed_to_pixed, set_pixed_to_pixed },
{ "subscribe", NULL, set_subscribe_event },
{ "alpha_zorder", get_alpha_zorder, set_alpha_zorder },
{ "orbit_policy", get_orbit_policy, set_orbit_policy },
{ "seamless_info", get_seamless_info, set_seamless_info }
};
int same_name(char *name, const char *dst)
{
if (strlen(name) != strlen(dst))
return 1;
if (strcmp(name, dst) != 0)
return 1;
return 0;
}
struct support_func *get_support_func(int index)
{
return &g_func[index];
}
int get_func_len()
{
return sizeof(g_func) / sizeof(g_func[0]);
}
void exe_func(char *name, int flag, int fd, char *par)
{
struct support_func *func = NULL;
int len = get_func_len();
int i;
for (i = 0; i < len; i++) {
func = get_support_func(i);
if (func && same_name(name, func->name) == 0) {
if (flag == 0 && func->get_func != NULL)
func->get_func(fd);
else if (flag == 1 && func->set_func != NULL)
func->set_func(fd, par);
}
}
}
int main(int argc, char *argv[])
{
int video_fd;
int ch;
char dev[NAME_LEN] = { 0 };
char func[FUNC_NAME_LEN] = { 0 };
char par[FUNC_NAME_LEN] = { 0 };
int flag = 0;
int wait_flag = 0;
int tunnel_flag = 0;
struct ctx_info ctx = { 0 };
struct pro_data pctx = { 0 };
pthread_t thread_id;
int v_flag = -1;
while ((ch = getopt(argc, argv, "d:gsf:p:v:twh")) != -1) {
switch (ch) {
case 'd':
strcpy(dev, optarg);
break;
case 'g':
flag = 0;
break;
case 's':
flag = 1;
break;
case 'f':
strcpy(func, optarg);
break;
case 'p':
strcpy(par, optarg);
break;
case 'w':
wait_flag = 1;
break;
case 'v':
wait_flag = 1;
v_flag = atoi(optarg);
break;
case 't':
wait_flag = 1;
tunnel_flag = 1;
break;
case 'h':
break;
default:
break;
}
}
video_fd = open(dev, O_RDWR);
if ( video_fd < 0) {
fprintf(stderr, "%s: %s\n", dev, strerror(errno));
return -1;
}
if (wait_flag != 0) {
char buffer[200] = { 0 };
char *tok, *tok_s = NULL;
ctx.fd = video_fd;
ctx.exitThread = false;
int ret = pthread_create(&thread_id, NULL, PollThreadMain, &ctx);
if (ret != 0)
printf("create thread error: %d\n", errno);
if (tunnel_flag > 0 && v_flag < 0) {
test_video_play(video_fd, 0, 960, 540);
start_producer(&pctx, 5);
}
if (v_flag >= 0)
test_video_play(video_fd, v_flag, 1920, 1080);
while (true) {
if (fgets(buffer, sizeof(buffer), stdin) == NULL)
continue;
size_t len = strlen(buffer);
if (len > 0 && buffer[len - 1] == '\n') {
buffer[len - 1] = '\0';
}
if (buffer[0] == 'q')
break;
tok = strtok_r(buffer, " ", &tok_s);
if (tok) {
if (!strncmp(tok, "get", 3))
flag = 0;
else if (!strncmp(tok, "set", 3))
flag = 1;
tok = strtok_r(0, " ", &tok_s);
if (tok) {
strcpy(func, tok);
strcpy(par, tok_s);
}
}
exe_func(func, flag, video_fd, par);
}
ctx.exitThread = true;
pthread_join(thread_id, NULL);
if (tunnel_flag > 0 && v_flag < 0)
stop_producer(&pctx);
} else {
exe_func(func, flag, video_fd, par);
}
fprintf(stderr, "ioctl test success\n");
close(video_fd);
return 0;
}