diff --git a/src/codec.c b/src/codec.c index e408e6e..5021942 100644 --- a/src/codec.c +++ b/src/codec.c @@ -44,6 +44,8 @@ unsigned int pixelformat_for_profile(VAProfile profile) return V4L2_PIX_FMT_VP8_FRAME; case VAProfileVP9Profile0: return V4L2_PIX_FMT_VP9_FRAME; + case VAProfileAV1Profile0: + return V4L2_PIX_FMT_AV1_FRAME; default: return 0; } diff --git a/src/request.c b/src/request.c index 20884be..3769e15 100644 --- a/src/request.c +++ b/src/request.c @@ -325,6 +325,37 @@ static bool probe_hevc_ext_sps_rps_controls(int video_fd) return true; } +/* + * Inspect a /dev/videoN's OUTPUT formats for `want_pixfmt`. Returns true + * iff at least one OUTPUT/OUTPUT_MPLANE format matches. + * + * Used to discriminate between multiple devices sharing a driver name — + * RK3588 has 3 hantro-vpu instances and only one of them is vpu981 (the + * dedicated AV1 decoder advertising V4L2_PIX_FMT_AV1_FRAME). + */ +static bool video_node_supports_output_fmt(int video_fd, uint32_t want_pixfmt) +{ + struct v4l2_fmtdesc desc; + const enum v4l2_buf_type types[] = { + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + V4L2_BUF_TYPE_VIDEO_OUTPUT, + }; + unsigned int t, i; + + for (t = 0; t < sizeof(types) / sizeof(types[0]); t++) { + for (i = 0; i < 64; i++) { + memset(&desc, 0, sizeof desc); + desc.index = i; + desc.type = types[t]; + if (ioctl(video_fd, VIDIOC_ENUM_FMT, &desc) < 0) + break; + if (desc.pixelformat == want_pixfmt) + return true; + } + } + return false; +} + static int find_decoder_device_by_driver(const char *want_driver, char *video_out, size_t video_out_sz, char *media_out, size_t media_out_sz) @@ -372,6 +403,65 @@ static int find_decoder_device_by_driver(const char *want_driver, return -1; } +/* + * ampere-av1-enablement Phase 2 — like find_decoder_device_by_driver but + * additionally verifies the resolved /dev/videoN advertises `want_pixfmt` + * as an OUTPUT format. Required for RK3588 where 3 hantro-vpu instances + * share the driver name but only one is vpu981 (AV1 decoder). + * + * Walks all /dev/media* with matching driver name; takes the first hit + * whose OUTPUT formats include `want_pixfmt`. Non-matching candidates + * (encoder-only nodes, legacy hantro for MPEG2/VP8) are skipped. + */ +static int find_decoder_device_by_driver_with_fmt(const char *want_driver, + uint32_t want_pixfmt, + char *video_out, + size_t video_out_sz, + char *media_out, + size_t media_out_sz) +{ + struct media_device_info info; + char path[32]; + char vpath[32]; + int fd, vfd, i; + + for (i = 0; i < 16; i++) { + snprintf(path, sizeof path, "/dev/media%d", i); + fd = open(path, O_RDWR | O_NONBLOCK); + if (fd < 0) + continue; + memset(&info, 0, sizeof info); + if (ioctl(fd, MEDIA_IOC_DEVICE_INFO, &info) != 0) { + close(fd); + continue; + } + if (strcmp(info.driver, want_driver) != 0) { + close(fd); + continue; + } + if (find_decoder_video_node_via_topology(fd, vpath, + sizeof vpath) != 0) { + close(fd); + continue; + } + close(fd); + + /* Capability check: does this /dev/videoN advertise the + * codec-specific OUTPUT format? */ + vfd = open(vpath, O_RDWR | O_NONBLOCK); + if (vfd < 0) + continue; + if (video_node_supports_output_fmt(vfd, want_pixfmt)) { + close(vfd); + snprintf(video_out, video_out_sz, "%s", vpath); + snprintf(media_out, media_out_sz, "%s", path); + return 0; + } + close(vfd); + } + return -1; +} + static int find_codec_device(char *video_out, size_t video_out_sz, char *media_out, size_t media_out_sz) { @@ -408,6 +498,8 @@ char request_device_kind_for_profile(VAProfile profile) case VAProfileMPEG2Main: case VAProfileVP8Version0_3: return 'h'; + case VAProfileAV1Profile0: + return 'a'; /* ampere-av1-enablement: vpu981 dedicated AV1 */ default: return '?'; } @@ -437,6 +529,9 @@ int request_switch_device_for_profile(struct request_data *driver_data, } else if (kind == 'h') { target_video = driver_data->video_fd_hantro; target_media = driver_data->media_fd_hantro; + } else if (kind == 'a') { + target_video = driver_data->video_fd_vpu981; + target_media = driver_data->media_fd_vpu981; } else { return -1; } @@ -624,6 +719,8 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context) driver_data->media_fd_rkvdec = -1; driver_data->video_fd_hantro = -1; driver_data->media_fd_hantro = -1; + driver_data->video_fd_vpu981 = -1; + driver_data->media_fd_vpu981 = -1; /* * iter38: probe BOTH rkvdec and hantro-vpu so a single libva session @@ -681,6 +778,40 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context) } } (void)primary_driver; + + /* + * ampere-av1-enablement Phase 2 — additionally probe for + * vpu981 (RK3588's dedicated AV1 decoder). Driver name + * "hantro-vpu" alone is ambiguous on RK3588 (3 instances: + * legacy MPEG2/VP8, encoder, vpu981 AV1). Discriminate by + * V4L2_PIX_FMT_AV1_FRAME capability. If the primary or alt + * hantro happens to BE vpu981 (unlikely but possible on + * non-RK3588 boards), this probe finds it again and we just + * dedupe via the fd value. + */ + { + static char av1_video[32], av1_media[32]; + if (find_decoder_device_by_driver_with_fmt( + "hantro-vpu", V4L2_PIX_FMT_AV1_FRAME, + av1_video, sizeof av1_video, + av1_media, sizeof av1_media) == 0) { + int av1_v = open(av1_video, O_RDWR | O_NONBLOCK); + int av1_m = (av1_v >= 0) + ? open(av1_media, O_RDWR | O_NONBLOCK) + : -1; + if (av1_v >= 0 && av1_m >= 0) { + driver_data->video_fd_vpu981 = av1_v; + driver_data->media_fd_vpu981 = av1_m; + request_log( + "ampere-av1: vpu981 AV1 decoder " + "at %s + %s\n", + av1_video, av1_media); + } else { + if (av1_v >= 0) close(av1_v); + if (av1_m >= 0) close(av1_m); + } + } + } } /* @@ -745,9 +876,15 @@ VAStatus RequestTerminate(VADriverContextP context) close(driver_data->video_fd_hantro); if (driver_data->media_fd_hantro >= 0) close(driver_data->media_fd_hantro); + if (driver_data->video_fd_vpu981 >= 0) + close(driver_data->video_fd_vpu981); + if (driver_data->media_fd_vpu981 >= 0) + close(driver_data->media_fd_vpu981); /* Fall back to direct close if neither alt fd captured the active * pair (env-override path). */ - if (driver_data->video_fd_rkvdec < 0 && driver_data->video_fd_hantro < 0) { + if (driver_data->video_fd_rkvdec < 0 && + driver_data->video_fd_hantro < 0 && + driver_data->video_fd_vpu981 < 0) { if (driver_data->video_fd >= 0) close(driver_data->video_fd); if (driver_data->media_fd >= 0) diff --git a/src/request.h b/src/request.h index 66c7c52..a58a44d 100644 --- a/src/request.h +++ b/src/request.h @@ -79,6 +79,20 @@ struct request_data { int video_fd_hantro; int media_fd_hantro; + /* + * ampere-av1-enablement Phase 2 — vpu981 is a THIRD physical + * hantro-vpu instance on RK3588 (separate from the legacy MPEG2/VP8 + * hantro at /dev/video2). It's the dedicated AV1 decoder at + * /dev/video4 with card name "rockchip,rk3588-av1-vpu-dec". + * + * Driver-name alone ("hantro-vpu") is ambiguous on RK3588 — three + * instances share the name. The probe discriminates by capability: + * which OUTPUT format does the device advertise? Only vpu981 + * exposes V4L2_PIX_FMT_AV1_FRAME. + */ + int video_fd_vpu981; + int media_fd_vpu981; + /* * iter2 (ampere-kernel-decoders campaign) — per-fd probe result * for the V4L2_CID_STATELESS_HEVC_EXT_SPS_{ST,LT}_RPS controls