#include "media_info.h"
|
|
void print_flags(const struct flag_name* flag_names, unsigned int num_entries, __u32 flags)
|
{
|
bool first = true;
|
unsigned int i;
|
|
for (i = 0; i < num_entries; i++) {
|
if (!(flags & flag_names[i].flag)) {
|
continue;
|
}
|
if (!first) {
|
printf(",");
|
}
|
printf("%s", flag_names[i].name);
|
flags &= ~flag_names[i].flag;
|
first = false;
|
}
|
|
if (flags) {
|
if (!first) {
|
printf(",");
|
}
|
printf("0x%x", flags);
|
}
|
}
|
|
void v4l2_subdev_print_format(struct media_entity* entity, unsigned int pad, enum v4l2_subdev_format_whence which)
|
{
|
struct v4l2_mbus_framefmt format;
|
struct v4l2_fract interval = {0, 0};
|
struct v4l2_rect rect;
|
int ret;
|
|
ret = v4l2_subdev_get_format(entity, &format, pad, which);
|
if (ret != 0) {
|
return;
|
}
|
|
ret = v4l2_subdev_get_frame_interval(entity, &interval, pad);
|
if (ret != 0 && ret != -ENOTTY && ret != -EINVAL) {
|
return;
|
}
|
|
printf("\t\t[fmt:%s/%ux%u", v4l2_subdev_pixelcode_to_string(format.code), format.width, format.height);
|
|
if (interval.numerator || interval.denominator) {
|
printf("@%u/%u", interval.numerator, interval.denominator);
|
}
|
|
if (format.field) {
|
printf(" field:%s", v4l2_subdev_field_to_string(format.field));
|
}
|
|
if (format.colorspace) {
|
printf(" colorspace:%s", v4l2_subdev_colorspace_to_string(format.colorspace));
|
|
if (format.xfer_func) {
|
printf(" xfer:%s", v4l2_subdev_xfer_func_to_string(format.xfer_func));
|
}
|
|
if (format.ycbcr_enc)
|
printf(" ycbcr:%s", v4l2_subdev_ycbcr_encoding_to_string(format.ycbcr_enc));
|
|
if (format.quantization)
|
printf(" quantization:%s", v4l2_subdev_quantization_to_string(format.quantization));
|
}
|
|
ret = v4l2_subdev_get_selection(entity, &rect, pad, V4L2_SEL_TGT_CROP_BOUNDS, which);
|
if (ret == 0)
|
printf("\n\t\t crop.bounds:(%u,%u)/%ux%u", rect.left, rect.top, rect.width, rect.height);
|
|
ret = v4l2_subdev_get_selection(entity, &rect, pad, V4L2_SEL_TGT_CROP, which);
|
if (ret == 0)
|
printf("\n\t\t crop:(%u,%u)/%ux%u", rect.left, rect.top, rect.width, rect.height);
|
|
ret = v4l2_subdev_get_selection(entity, &rect, pad, V4L2_SEL_TGT_COMPOSE_BOUNDS, which);
|
if (ret == 0)
|
printf("\n\t\t compose.bounds:(%u,%u)/%ux%u", rect.left, rect.top, rect.width, rect.height);
|
|
ret = v4l2_subdev_get_selection(entity, &rect, pad, V4L2_SEL_TGT_COMPOSE, which);
|
if (ret == 0)
|
printf("\n\t\t compose:(%u,%u)/%ux%u", rect.left, rect.top, rect.width, rect.height);
|
|
printf("]\n");
|
}
|
|
const char* v4l2_dv_type_to_string(unsigned int type)
|
{
|
static const struct {
|
__u32 type;
|
const char* name;
|
} types[] = {
|
{V4L2_DV_BT_656_1120, "BT.656/1120"},
|
};
|
|
static char unknown[20];
|
unsigned int i;
|
|
for (i = 0; i < ARRAY_SIZE(types); i++) {
|
if (types[i].type == type) {
|
return types[i].name;
|
}
|
}
|
|
sprintf(unknown, "Unknown (%u)", type);
|
return unknown;
|
}
|
|
static const struct flag_name bt_standards[] = {
|
{V4L2_DV_BT_STD_CEA861, "CEA-861"}, {V4L2_DV_BT_STD_DMT, "DMT"}, {V4L2_DV_BT_STD_CVT, "CVT"},
|
{V4L2_DV_BT_STD_GTF, "GTF"}, {V4L2_DV_BT_STD_SDI, "SDI"},
|
};
|
|
static const struct flag_name bt_capabilities[] = {
|
{V4L2_DV_BT_CAP_INTERLACED, "interlaced"},
|
{V4L2_DV_BT_CAP_PROGRESSIVE, "progressive"},
|
{V4L2_DV_BT_CAP_REDUCED_BLANKING, "reduced-blanking"},
|
{V4L2_DV_BT_CAP_CUSTOM, "custom"},
|
};
|
|
static const struct flag_name bt_flags[] = {
|
{V4L2_DV_FL_REDUCED_BLANKING, "reduced-blanking"},
|
{V4L2_DV_FL_CAN_REDUCE_FPS, "can-reduce-fps"},
|
{V4L2_DV_FL_REDUCED_FPS, "reduced-fps"},
|
{V4L2_DV_FL_HALF_LINE, "half-line"},
|
{V4L2_DV_FL_IS_CE_VIDEO, "CE-video"},
|
{V4L2_DV_FL_FIRST_FIELD_EXTRA_LINE, "first-field-extra-line"},
|
{V4L2_DV_FL_HAS_PICTURE_ASPECT, "has-picture-aspect"},
|
{V4L2_DV_FL_HAS_CEA861_VIC, "has-cea861-vic"},
|
{V4L2_DV_FL_HAS_HDMI_VIC, "has-hdmi-vic"},
|
{V4L2_DV_FL_CAN_DETECT_REDUCED_FPS, "can-detect-reduced-fps"},
|
};
|
|
void v4l2_subdev_print_dv_timings(const struct v4l2_dv_timings* timings, const char* name)
|
{
|
printf("\t\t[dv.%s:%s", name, v4l2_dv_type_to_string(timings->type));
|
|
switch (timings->type) {
|
case V4L2_DV_BT_656_1120: {
|
const struct v4l2_bt_timings* bt = &timings->bt;
|
unsigned int htotal, vtotal;
|
|
htotal = V4L2_DV_BT_FRAME_WIDTH(bt);
|
vtotal = V4L2_DV_BT_FRAME_HEIGHT(bt);
|
|
printf(" %ux%u%s%llu (%ux%u)", bt->width, bt->height, bt->interlaced ? "i" : "p",
|
(htotal * vtotal) > 0 ? (bt->pixelclock / (htotal * vtotal)) : 0, htotal, vtotal);
|
|
printf(" stds:");
|
print_flags(bt_standards, ARRAY_SIZE(bt_standards), bt->standards);
|
printf(" flags:");
|
print_flags(bt_flags, ARRAY_SIZE(bt_flags), bt->flags);
|
|
break;
|
}
|
}
|
|
printf("]\n");
|
}
|
|
void v4l2_subdev_print_pad_dv(struct media_entity* entity, unsigned int pad, enum v4l2_subdev_format_whence which)
|
{
|
struct v4l2_dv_timings_cap caps;
|
int ret;
|
|
caps.pad = pad;
|
ret = v4l2_subdev_get_dv_timings_caps(entity, &caps);
|
if (ret != 0) {
|
return;
|
}
|
|
printf("\t\t[dv.caps:%s", v4l2_dv_type_to_string(caps.type));
|
|
switch (caps.type) {
|
case V4L2_DV_BT_656_1120:
|
printf(" min:%ux%u@%llu max:%ux%u@%llu", caps.bt.min_width, caps.bt.min_height, caps.bt.min_pixelclock,
|
caps.bt.max_width, caps.bt.max_height, caps.bt.max_pixelclock);
|
|
printf(" stds:");
|
print_flags(bt_standards, ARRAY_SIZE(bt_standards), caps.bt.standards);
|
printf(" caps:");
|
print_flags(bt_capabilities, ARRAY_SIZE(bt_capabilities), caps.bt.capabilities);
|
|
break;
|
}
|
|
printf("]\n");
|
}
|
|
void v4l2_subdev_print_subdev_dv(struct media_entity* entity)
|
{
|
struct v4l2_dv_timings timings;
|
int ret;
|
|
ret = v4l2_subdev_query_dv_timings(entity, &timings);
|
switch (ret) {
|
case -ENOLINK:
|
printf("\t\t[dv.query:no-link]\n");
|
break;
|
case -ENOLCK:
|
printf("\t\t[dv.query:no-lock]\n");
|
break;
|
case -ERANGE:
|
printf("\t\t[dv.query:out-of-range]\n");
|
break;
|
case 0:
|
v4l2_subdev_print_dv_timings(&timings, "detect");
|
break;
|
default:
|
return;
|
}
|
|
ret = v4l2_subdev_get_dv_timings(entity, &timings);
|
if (ret == 0) {
|
v4l2_subdev_print_dv_timings(&timings, "current");
|
}
|
}
|
|
const char* media_entity_type_to_string(unsigned type)
|
{
|
static const struct {
|
__u32 type;
|
const char* name;
|
} types[] = {
|
{MEDIA_ENT_T_DEVNODE, "Node"},
|
{MEDIA_ENT_T_V4L2_SUBDEV, "V4L2 subdev"},
|
};
|
|
unsigned int i;
|
|
type &= MEDIA_ENT_TYPE_MASK;
|
|
for (i = 0; i < ARRAY_SIZE(types); i++) {
|
if (types[i].type == type) {
|
return types[i].name;
|
}
|
}
|
|
return "Unknown";
|
}
|
|
const char* media_entity_subtype_to_string(unsigned type)
|
{
|
static const char* node_types[] = {
|
"Unknown", "V4L", "FB", "ALSA", "DVB",
|
};
|
static const char* subdev_types[] = {
|
"Unknown", "Sensor", "Flash", "Lens", "Decoder", "Tuner",
|
};
|
|
unsigned int subtype = type & MEDIA_ENT_SUBTYPE_MASK;
|
|
switch (type & MEDIA_ENT_TYPE_MASK) {
|
case MEDIA_ENT_T_DEVNODE:
|
if (subtype >= ARRAY_SIZE(node_types)) {
|
subtype = 0;
|
}
|
return node_types[subtype];
|
|
case MEDIA_ENT_T_V4L2_SUBDEV:
|
if (subtype >= ARRAY_SIZE(subdev_types)) {
|
subtype = 0;
|
}
|
return subdev_types[subtype];
|
default:
|
return node_types[0];
|
}
|
}
|
|
const char* media_pad_type_to_string(unsigned flag)
|
{
|
static const struct {
|
__u32 flag;
|
const char* name;
|
} flags[] = {
|
{MEDIA_PAD_FL_SINK, "Sink"},
|
{MEDIA_PAD_FL_SOURCE, "Source"},
|
};
|
|
unsigned int i;
|
|
for (i = 0; i < ARRAY_SIZE(flags); i++) {
|
if (flags[i].flag & flag) {
|
return flags[i].name;
|
}
|
}
|
|
return "Unknown";
|
}
|
|
void media_print_pad_text(struct media_entity* entity, const struct media_pad* pad)
|
{
|
if (media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV) {
|
return;
|
}
|
|
v4l2_subdev_print_format(entity, pad->index, V4L2_SUBDEV_FORMAT_ACTIVE);
|
v4l2_subdev_print_pad_dv(entity, pad->index, V4L2_SUBDEV_FORMAT_ACTIVE);
|
|
if (pad->flags & MEDIA_PAD_FL_SOURCE) {
|
v4l2_subdev_print_subdev_dv(entity);
|
}
|
}
|