forked from marfrit/libva-v4l2-request-fourier
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6173a8da8e | |||
| de27e95571 | |||
| 2146341460 | |||
| b5b3acf0f7 | |||
| 820557268b | |||
| c6f81c653f |
@@ -4,3 +4,14 @@ option(
|
|||||||
value : '',
|
value : '',
|
||||||
description: 'Path to sanitized Linux Kernel headers'
|
description: 'Path to sanitized Linux Kernel headers'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
option(
|
||||||
|
'daedalus_v4l2',
|
||||||
|
type : 'boolean',
|
||||||
|
value : true,
|
||||||
|
description: 'Enable probe + dispatch for the out-of-tree daedalus_v4l2 ' +
|
||||||
|
'stateless decoder shim (Pi 5 / CM5 daemon-backed VP9/AV1/H264). ' +
|
||||||
|
'Default true; disable on platforms where the daedalus_v4l2 ' +
|
||||||
|
'kernel module will never be present to slim the probe array.'
|
||||||
|
)
|
||||||
|
|
||||||
|
|||||||
+14
@@ -46,6 +46,20 @@ unsigned int pixelformat_for_profile(VAProfile profile)
|
|||||||
return V4L2_PIX_FMT_VP8_FRAME;
|
return V4L2_PIX_FMT_VP8_FRAME;
|
||||||
case VAProfileVP9Profile0:
|
case VAProfileVP9Profile0:
|
||||||
return V4L2_PIX_FMT_VP9_FRAME;
|
return V4L2_PIX_FMT_VP9_FRAME;
|
||||||
|
case VAProfileAV1Profile0:
|
||||||
|
/*
|
||||||
|
* ampere-av1-enablement Phase 2: AV1 Profile 0 routes to
|
||||||
|
* vpu981 (RK3588's dedicated AV1 hantro). Per-codec ctrl
|
||||||
|
* dispatch (V4L2_CID_STATELESS_AV1_*) is NOT YET WIRED on
|
||||||
|
* master — vainfo lists the profile + RequestCreateConfig
|
||||||
|
* succeeds, but consumers that submit decode buffers hit
|
||||||
|
* a NOP path until the per-codec dispatch lands. The
|
||||||
|
* av1-iter1 operator branch has Phase 3 bit-exact bring-up
|
||||||
|
* underway; this commit gives master the bare enumeration +
|
||||||
|
* fd-routing layer so consumers like ffmpeg-vaapi at least
|
||||||
|
* see VAProfileAV1Profile0 today.
|
||||||
|
*/
|
||||||
|
return V4L2_PIX_FMT_AV1_FRAME;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-2
@@ -81,6 +81,16 @@ VAStatus RequestCreateConfig(VADriverContextP context, VAProfile profile,
|
|||||||
// cap is V4L2_MPEG_VIDEO_VP9_PROFILE_0). Do not add a case for
|
// cap is V4L2_MPEG_VIDEO_VP9_PROFILE_0). Do not add a case for
|
||||||
// VAProfileVP9Profile2 — kernel will reject.
|
// VAProfileVP9Profile2 — kernel will reject.
|
||||||
break;
|
break;
|
||||||
|
case VAProfileAV1Profile0:
|
||||||
|
// ampere-av1-enablement Phase 2: AV1 Profile 0 routes to
|
||||||
|
// vpu981 (RK3588 dedicated AV1 hantro instance). Decode-side
|
||||||
|
// ctrl dispatch (V4L2_CID_STATELESS_AV1_*) is NOT YET WIRED
|
||||||
|
// on master — vainfo will list the profile + CreateConfig
|
||||||
|
// succeeds, but consumers that submit decode buffers hit a
|
||||||
|
// NOP path until av1.{c,h} dispatch scaffolding is ported
|
||||||
|
// from the av1-iter1 operator branch (where Phase 3-5 has
|
||||||
|
// 3/10 frames bit-exact already).
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
|
return VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
|
||||||
}
|
}
|
||||||
@@ -162,13 +172,15 @@ VAStatus RequestDestroyConfig(VADriverContextP context, VAConfigID config_id)
|
|||||||
static bool any_fd_supports_output_format(struct request_data *driver_data,
|
static bool any_fd_supports_output_format(struct request_data *driver_data,
|
||||||
unsigned int fmt)
|
unsigned int fmt)
|
||||||
{
|
{
|
||||||
int fds[3] = {
|
int fds[5] = {
|
||||||
driver_data->video_fd,
|
driver_data->video_fd,
|
||||||
driver_data->video_fd_rkvdec,
|
driver_data->video_fd_rkvdec,
|
||||||
driver_data->video_fd_hantro,
|
driver_data->video_fd_hantro,
|
||||||
|
driver_data->video_fd_rpi_hevc_dec, /* iter40 */
|
||||||
|
driver_data->video_fd_vpu981, /* ampere-av1 Phase 2 */
|
||||||
};
|
};
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
if (fds[i] < 0) continue;
|
if (fds[i] < 0) continue;
|
||||||
if (v4l2_find_format(fds[i], V4L2_BUF_TYPE_VIDEO_OUTPUT, fmt))
|
if (v4l2_find_format(fds[i], V4L2_BUF_TYPE_VIDEO_OUTPUT, fmt))
|
||||||
return true;
|
return true;
|
||||||
@@ -249,6 +261,17 @@ VAStatus RequestQueryConfigProfiles(VADriverContextP context,
|
|||||||
if (found && index < (V4L2_REQUEST_MAX_PROFILES - 1))
|
if (found && index < (V4L2_REQUEST_MAX_PROFILES - 1))
|
||||||
profiles[index++] = VAProfileVP9Profile0;
|
profiles[index++] = VAProfileVP9Profile0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ampere-av1-enablement Phase 2: AV1 Profile 0 advertised when
|
||||||
|
* vpu981 (RK3588 dedicated AV1 hantro) is probed. MAX_PROFILES
|
||||||
|
* bumped to 14 in request.h to safely fit even if iter39 Option
|
||||||
|
* B is reverted (Hi10P + Main10 back in enumeration → 13 total
|
||||||
|
* with AV1, the `< MAX - 1` guard then needs MAX ≥ 14).
|
||||||
|
*/
|
||||||
|
found = any_fd_supports_output_format(driver_data, V4L2_PIX_FMT_AV1_FRAME);
|
||||||
|
if (found && index < (V4L2_REQUEST_MAX_PROFILES - 1))
|
||||||
|
profiles[index++] = VAProfileAV1Profile0;
|
||||||
|
|
||||||
*profiles_count = index;
|
*profiles_count = index;
|
||||||
|
|
||||||
return VA_STATUS_SUCCESS;
|
return VA_STATUS_SUCCESS;
|
||||||
@@ -272,6 +295,7 @@ VAStatus RequestQueryConfigEntrypoints(VADriverContextP context,
|
|||||||
case VAProfileHEVCMain10:
|
case VAProfileHEVCMain10:
|
||||||
case VAProfileVP8Version0_3:
|
case VAProfileVP8Version0_3:
|
||||||
case VAProfileVP9Profile0:
|
case VAProfileVP9Profile0:
|
||||||
|
case VAProfileAV1Profile0:
|
||||||
entrypoints[0] = VAEntrypointVLD;
|
entrypoints[0] = VAEntrypointVLD;
|
||||||
*entrypoints_count = 1;
|
*entrypoints_count = 1;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -22,6 +22,9 @@
|
|||||||
|
|
||||||
autoconf_data = configuration_data()
|
autoconf_data = configuration_data()
|
||||||
autoconf_data.set('VA_DRIVER_INIT_FUNC', va_driver_init_func)
|
autoconf_data.set('VA_DRIVER_INIT_FUNC', va_driver_init_func)
|
||||||
|
if get_option('daedalus_v4l2')
|
||||||
|
autoconf_data.set('HAVE_DAEDALUS_V4L2', 1)
|
||||||
|
endif
|
||||||
|
|
||||||
autoconf = configure_file(
|
autoconf = configure_file(
|
||||||
output: 'autoconfig.h',
|
output: 'autoconfig.h',
|
||||||
|
|||||||
+189
-5
@@ -94,6 +94,9 @@ static const char * const known_decoder_drivers[] = {
|
|||||||
"rkvdec",
|
"rkvdec",
|
||||||
"hantro-vpu",
|
"hantro-vpu",
|
||||||
"rpi-hevc-dec", /* iter40: Pi 5 / CM5 stateless HEVC */
|
"rpi-hevc-dec", /* iter40: Pi 5 / CM5 stateless HEVC */
|
||||||
|
#ifdef HAVE_DAEDALUS_V4L2
|
||||||
|
"daedalus_v4l2", /* phase 8.10: Pi 5 daemon-backed VP9/AV1/H264 */
|
||||||
|
#endif
|
||||||
"cedrus",
|
"cedrus",
|
||||||
"sun4i_csi",
|
"sun4i_csi",
|
||||||
NULL
|
NULL
|
||||||
@@ -409,6 +412,16 @@ char request_device_kind_for_profile(VAProfile profile)
|
|||||||
case VAProfileMPEG2Main:
|
case VAProfileMPEG2Main:
|
||||||
case VAProfileVP8Version0_3:
|
case VAProfileVP8Version0_3:
|
||||||
return 'h';
|
return 'h';
|
||||||
|
case VAProfileAV1Profile0:
|
||||||
|
/*
|
||||||
|
* ampere-av1-enablement Phase 2: RK3588 vpu981 dedicated
|
||||||
|
* AV1 hantro instance. 'a' kind dispatches to
|
||||||
|
* driver_data->video_fd_vpu981. On hosts without the AV1
|
||||||
|
* instance the fd stays -1 and RequestQueryConfigProfiles
|
||||||
|
* never enumerates AV1, so this branch is unreachable for
|
||||||
|
* non-RK3588 hosts.
|
||||||
|
*/
|
||||||
|
return 'a';
|
||||||
default:
|
default:
|
||||||
return '?';
|
return '?';
|
||||||
}
|
}
|
||||||
@@ -448,6 +461,44 @@ int request_switch_device_for_profile(struct request_data *driver_data,
|
|||||||
kind = 'p';
|
kind = 'p';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DAEDALUS_V4L2
|
||||||
|
/*
|
||||||
|
* LIBVA-1: VP9/AV1/H.264 → daedalus_v4l2 when the daemon-backed
|
||||||
|
* decoder fd is open. Pi 5 has no rkvdec (those profiles map to
|
||||||
|
* 'r' by default → video_fd_rkvdec = -1 → "stay on whatever's
|
||||||
|
* active" fallback would put H.264 frames on rpi-hevc-dec's fd
|
||||||
|
* and S_FMT would fail). Re-route to the daedalus daemon instead.
|
||||||
|
*
|
||||||
|
* HEVC stays on 'p' (rpi-hevc-dec is HEVC-only — daedalus would
|
||||||
|
* accept it via FFmpeg, but rpi-hevc-dec has the GPU-backed
|
||||||
|
* hardware path so it's the right choice on this SoC).
|
||||||
|
*
|
||||||
|
* AV1 'a' kind (RK3588 vpu981) wins ONLY if vpu981 was probed.
|
||||||
|
* On a Pi 5 the vpu981 slot stays -1, so we still route AV1 to
|
||||||
|
* daedalus here. Check video_fd_vpu981 to preserve the RK3588
|
||||||
|
* priority for that case.
|
||||||
|
*/
|
||||||
|
if (driver_data->video_fd_daedalus >= 0 &&
|
||||||
|
driver_data->media_fd_daedalus >= 0) {
|
||||||
|
switch (profile) {
|
||||||
|
case VAProfileH264Main:
|
||||||
|
case VAProfileH264High:
|
||||||
|
case VAProfileH264ConstrainedBaseline:
|
||||||
|
case VAProfileH264MultiviewHigh:
|
||||||
|
case VAProfileH264StereoHigh:
|
||||||
|
case VAProfileVP9Profile0:
|
||||||
|
kind = 'd';
|
||||||
|
break;
|
||||||
|
case VAProfileAV1Profile0:
|
||||||
|
if (driver_data->video_fd_vpu981 < 0)
|
||||||
|
kind = 'd';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (kind == 'r') {
|
if (kind == 'r') {
|
||||||
target_video = driver_data->video_fd_rkvdec;
|
target_video = driver_data->video_fd_rkvdec;
|
||||||
target_media = driver_data->media_fd_rkvdec;
|
target_media = driver_data->media_fd_rkvdec;
|
||||||
@@ -457,6 +508,14 @@ int request_switch_device_for_profile(struct request_data *driver_data,
|
|||||||
} else if (kind == 'p') {
|
} else if (kind == 'p') {
|
||||||
target_video = driver_data->video_fd_rpi_hevc_dec;
|
target_video = driver_data->video_fd_rpi_hevc_dec;
|
||||||
target_media = driver_data->media_fd_rpi_hevc_dec;
|
target_media = driver_data->media_fd_rpi_hevc_dec;
|
||||||
|
} else if (kind == 'a') {
|
||||||
|
target_video = driver_data->video_fd_vpu981;
|
||||||
|
target_media = driver_data->media_fd_vpu981;
|
||||||
|
#ifdef HAVE_DAEDALUS_V4L2
|
||||||
|
} else if (kind == 'd') {
|
||||||
|
target_video = driver_data->video_fd_daedalus;
|
||||||
|
target_media = driver_data->media_fd_daedalus;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -646,6 +705,10 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context)
|
|||||||
driver_data->media_fd_hantro = -1;
|
driver_data->media_fd_hantro = -1;
|
||||||
driver_data->video_fd_rpi_hevc_dec = -1;
|
driver_data->video_fd_rpi_hevc_dec = -1;
|
||||||
driver_data->media_fd_rpi_hevc_dec = -1;
|
driver_data->media_fd_rpi_hevc_dec = -1;
|
||||||
|
driver_data->video_fd_daedalus = -1;
|
||||||
|
driver_data->media_fd_daedalus = -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
|
* iter38: probe BOTH rkvdec and hantro-vpu so a single libva session
|
||||||
@@ -677,14 +740,35 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context)
|
|||||||
driver_data->video_fd_hantro = video_fd;
|
driver_data->video_fd_hantro = video_fd;
|
||||||
driver_data->media_fd_hantro = media_fd;
|
driver_data->media_fd_hantro = media_fd;
|
||||||
} else if (strcmp(info.driver, "rpi-hevc-dec") == 0) {
|
} else if (strcmp(info.driver, "rpi-hevc-dec") == 0) {
|
||||||
/* iter40: Pi 5 / CM5 — sole decoder is rpi-hevc-dec.
|
/* iter40 + LIBVA-1: Pi 5 / CM5. rpi-hevc-dec is
|
||||||
* No alt driver to probe; the rkvdec / hantro slots
|
* HEVC-only. If daedalus_v4l2 is ALSO loaded (Pi 5
|
||||||
* stay -1 and HEVC routes to 'p' via
|
* mixed deployment — out-of-tree daemon-backed
|
||||||
* request_device_kind_for_profile. */
|
* decoder for VP9/AV1/H264), pick it up as the alt
|
||||||
|
* so VP9/AV1/H264 have somewhere to land. */
|
||||||
primary_driver = "rpi-hevc-dec";
|
primary_driver = "rpi-hevc-dec";
|
||||||
|
#ifdef HAVE_DAEDALUS_V4L2
|
||||||
|
alt_driver = "daedalus_v4l2";
|
||||||
|
#else
|
||||||
alt_driver = NULL;
|
alt_driver = NULL;
|
||||||
|
#endif
|
||||||
driver_data->video_fd_rpi_hevc_dec = video_fd;
|
driver_data->video_fd_rpi_hevc_dec = video_fd;
|
||||||
driver_data->media_fd_rpi_hevc_dec = media_fd;
|
driver_data->media_fd_rpi_hevc_dec = media_fd;
|
||||||
|
#ifdef HAVE_DAEDALUS_V4L2
|
||||||
|
} else if (strcmp(info.driver, "daedalus_v4l2") == 0) {
|
||||||
|
/* phase 8.10 + LIBVA-1: Pi 5 daemon-backed decoder.
|
||||||
|
* VP9 / AV1 / H.264 route through it via the 'd'
|
||||||
|
* kind below. On a mixed-driver box where
|
||||||
|
* rpi-hevc-dec is ALSO loaded, pick it up as the
|
||||||
|
* alt so HEVC has somewhere to land too — find_
|
||||||
|
* codec_device's known_decoder_drivers[] order
|
||||||
|
* normally puts rpi-hevc-dec first (we hit the
|
||||||
|
* other branch in practice), but symmetric handling
|
||||||
|
* keeps us correct if probe order ever flips. */
|
||||||
|
primary_driver = "daedalus_v4l2";
|
||||||
|
alt_driver = "rpi-hevc-dec";
|
||||||
|
driver_data->video_fd_daedalus = video_fd;
|
||||||
|
driver_data->media_fd_daedalus = media_fd;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -696,15 +780,38 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context)
|
|||||||
int alt_v = open(alt_video, O_RDWR | O_NONBLOCK);
|
int alt_v = open(alt_video, O_RDWR | O_NONBLOCK);
|
||||||
int alt_m = (alt_v >= 0) ? open(alt_media, O_RDWR | O_NONBLOCK) : -1;
|
int alt_m = (alt_v >= 0) ? open(alt_media, O_RDWR | O_NONBLOCK) : -1;
|
||||||
if (alt_v >= 0 && alt_m >= 0) {
|
if (alt_v >= 0 && alt_m >= 0) {
|
||||||
|
/* Dispatch into the matching per-driver slot.
|
||||||
|
* iter38 only had rkvdec/hantro pairs; iter40 +
|
||||||
|
* LIBVA-1 extended this to rpi-hevc-dec and
|
||||||
|
* daedalus_v4l2 for the Pi 5 mixed-decoder
|
||||||
|
* deployment. */
|
||||||
if (strcmp(alt_driver, "rkvdec") == 0) {
|
if (strcmp(alt_driver, "rkvdec") == 0) {
|
||||||
driver_data->video_fd_rkvdec = alt_v;
|
driver_data->video_fd_rkvdec = alt_v;
|
||||||
driver_data->media_fd_rkvdec = alt_m;
|
driver_data->media_fd_rkvdec = alt_m;
|
||||||
} else {
|
} else if (strcmp(alt_driver, "hantro-vpu") == 0) {
|
||||||
driver_data->video_fd_hantro = alt_v;
|
driver_data->video_fd_hantro = alt_v;
|
||||||
driver_data->media_fd_hantro = alt_m;
|
driver_data->media_fd_hantro = alt_m;
|
||||||
|
} else if (strcmp(alt_driver, "rpi-hevc-dec") == 0) {
|
||||||
|
driver_data->video_fd_rpi_hevc_dec = alt_v;
|
||||||
|
driver_data->media_fd_rpi_hevc_dec = alt_m;
|
||||||
|
#ifdef HAVE_DAEDALUS_V4L2
|
||||||
|
} else if (strcmp(alt_driver, "daedalus_v4l2") == 0) {
|
||||||
|
driver_data->video_fd_daedalus = alt_v;
|
||||||
|
driver_data->media_fd_daedalus = alt_m;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
/* Shouldn't happen — primary_driver branches
|
||||||
|
* above only set alt_driver to one of the
|
||||||
|
* names handled here. Close and move on. */
|
||||||
|
close(alt_v);
|
||||||
|
close(alt_m);
|
||||||
|
alt_v = -1;
|
||||||
|
alt_m = -1;
|
||||||
}
|
}
|
||||||
|
if (alt_v >= 0) {
|
||||||
request_log("iter38: also opened %s decoder at %s + %s\n",
|
request_log("iter38: also opened %s decoder at %s + %s\n",
|
||||||
alt_driver, alt_video, alt_media);
|
alt_driver, alt_video, alt_media);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (alt_v >= 0) close(alt_v);
|
if (alt_v >= 0) close(alt_v);
|
||||||
if (alt_m >= 0) close(alt_m);
|
if (alt_m >= 0) close(alt_m);
|
||||||
@@ -712,6 +819,61 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
(void)primary_driver;
|
(void)primary_driver;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ampere-av1-enablement Phase 2: walk hantro-vpu media nodes
|
||||||
|
* for a SECOND one that advertises V4L2_PIX_FMT_AV1_FRAME
|
||||||
|
* (AV1F) as OUTPUT pixfmt. RK3588 has 3 hantro-vpu instances
|
||||||
|
* (legacy MPEG2/VP8 decoder, vepu121 encoder, vpu981 AV1
|
||||||
|
* decoder) all reporting driver="hantro-vpu" / model="hantro-
|
||||||
|
* vpu" — so OUTPUT-format probe is the only reliable
|
||||||
|
* disambiguator that doesn't depend on parsing card-name
|
||||||
|
* strings (which are DTS-dependent). First match wins.
|
||||||
|
*
|
||||||
|
* On non-RK3588 hosts the slot stays -1; RequestQueryConfig
|
||||||
|
* Profiles' AV1 push then no-ops because any_fd_supports_
|
||||||
|
* output_format() returns false for AV1F.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char path[32], av1_video[32];
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
int mfd, vfd;
|
||||||
|
struct media_device_info info;
|
||||||
|
|
||||||
|
snprintf(path, sizeof path, "/dev/media%d", i);
|
||||||
|
mfd = open(path, O_RDWR | O_NONBLOCK);
|
||||||
|
if (mfd < 0) continue;
|
||||||
|
memset(&info, 0, sizeof info);
|
||||||
|
if (ioctl(mfd, MEDIA_IOC_DEVICE_INFO, &info) != 0 ||
|
||||||
|
strcmp(info.driver, "hantro-vpu") != 0) {
|
||||||
|
close(mfd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (find_decoder_video_node_via_topology(
|
||||||
|
mfd, av1_video, sizeof av1_video) != 0) {
|
||||||
|
close(mfd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
vfd = open(av1_video, O_RDWR | O_NONBLOCK);
|
||||||
|
if (vfd < 0) {
|
||||||
|
close(mfd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!v4l2_find_format(vfd, V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_PIX_FMT_AV1_FRAME) &&
|
||||||
|
!v4l2_find_format(vfd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_PIX_FMT_AV1_FRAME)) {
|
||||||
|
close(vfd);
|
||||||
|
close(mfd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
driver_data->video_fd_vpu981 = vfd;
|
||||||
|
driver_data->media_fd_vpu981 = mfd;
|
||||||
|
request_log("ampere-av1: vpu981 AV1 decoder at %s + %s\n",
|
||||||
|
av1_video, path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -737,6 +899,14 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context)
|
|||||||
driver_data->video_fd_rpi_hevc_dec,
|
driver_data->video_fd_rpi_hevc_dec,
|
||||||
driver_data->media_fd_rpi_hevc_dec);
|
driver_data->media_fd_rpi_hevc_dec);
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_DAEDALUS_V4L2
|
||||||
|
if (driver_data->video_fd_daedalus >= 0) {
|
||||||
|
request_log("phase 8.10: opened daedalus_v4l2 at video_fd=%d "
|
||||||
|
"media_fd=%d (Pi 5 daemon-backed VP9/AV1/H264)\n",
|
||||||
|
driver_data->video_fd_daedalus,
|
||||||
|
driver_data->media_fd_daedalus);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
status = VA_STATUS_SUCCESS;
|
status = VA_STATUS_SUCCESS;
|
||||||
goto complete;
|
goto complete;
|
||||||
@@ -784,6 +954,20 @@ VAStatus RequestTerminate(VADriverContextP context)
|
|||||||
close(driver_data->video_fd_hantro);
|
close(driver_data->video_fd_hantro);
|
||||||
if (driver_data->media_fd_hantro >= 0)
|
if (driver_data->media_fd_hantro >= 0)
|
||||||
close(driver_data->media_fd_hantro);
|
close(driver_data->media_fd_hantro);
|
||||||
|
if (driver_data->video_fd_rpi_hevc_dec >= 0)
|
||||||
|
close(driver_data->video_fd_rpi_hevc_dec);
|
||||||
|
if (driver_data->media_fd_rpi_hevc_dec >= 0)
|
||||||
|
close(driver_data->media_fd_rpi_hevc_dec);
|
||||||
|
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);
|
||||||
|
#ifdef HAVE_DAEDALUS_V4L2
|
||||||
|
if (driver_data->video_fd_daedalus >= 0)
|
||||||
|
close(driver_data->video_fd_daedalus);
|
||||||
|
if (driver_data->media_fd_daedalus >= 0)
|
||||||
|
close(driver_data->media_fd_daedalus);
|
||||||
|
#endif
|
||||||
/* Fall back to direct close if neither alt fd captured the active
|
/* Fall back to direct close if neither alt fd captured the active
|
||||||
* pair (env-override path). */
|
* 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) {
|
||||||
|
|||||||
+43
-1
@@ -42,7 +42,16 @@
|
|||||||
|
|
||||||
#define V4L2_REQUEST_STR_VENDOR "v4l2-request"
|
#define V4L2_REQUEST_STR_VENDOR "v4l2-request"
|
||||||
|
|
||||||
#define V4L2_REQUEST_MAX_PROFILES 13
|
/*
|
||||||
|
* Sized for max-possible enumeration with iter39 Option B reverted:
|
||||||
|
* MPEG2(2) + H264(6 incl. Hi10P) + HEVC(2 incl. Main10) + VP8 + VP9 + AV1 = 13.
|
||||||
|
* The per-group guards use `if (... && index < (MAX_PROFILES - N))` where N
|
||||||
|
* is the push-group size, so MAX must be ≥ total+1 — 14 here. Bumping
|
||||||
|
* defensively now so a future re-enable of Hi10P/Main10 doesn't silently
|
||||||
|
* drop AV1 through the off-by-one trap that ate ampere-av1's enumeration
|
||||||
|
* for a week (see issue marfrit/libva-v4l2-request-fourier#2).
|
||||||
|
*/
|
||||||
|
#define V4L2_REQUEST_MAX_PROFILES 14
|
||||||
#define V4L2_REQUEST_MAX_ENTRYPOINTS 5
|
#define V4L2_REQUEST_MAX_ENTRYPOINTS 5
|
||||||
#define V4L2_REQUEST_MAX_CONFIG_ATTRIBUTES 10
|
#define V4L2_REQUEST_MAX_CONFIG_ATTRIBUTES 10
|
||||||
#define V4L2_REQUEST_MAX_IMAGE_FORMATS 10
|
#define V4L2_REQUEST_MAX_IMAGE_FORMATS 10
|
||||||
@@ -87,6 +96,39 @@ struct request_data {
|
|||||||
*/
|
*/
|
||||||
int video_fd_rpi_hevc_dec;
|
int video_fd_rpi_hevc_dec;
|
||||||
int media_fd_rpi_hevc_dec;
|
int media_fd_rpi_hevc_dec;
|
||||||
|
/*
|
||||||
|
* phase 8.10: fifth multi-device-probe slot for daedalus_v4l2 — the
|
||||||
|
* out-of-tree V4L2 stateless decoder shim that forwards bitstream
|
||||||
|
* to a userspace daemon (daedalus-v4l2 sibling repo). Daemon does
|
||||||
|
* FFmpeg-software decode for VP9 / AV1 / H.264 and ships pixels
|
||||||
|
* back via dmabuf into the CAPTURE buffer. Picked up via the
|
||||||
|
* same media-controller probe + known_decoder_drivers[] entry
|
||||||
|
* pattern as iter40 rpi-hevc-dec. Stays -1 on hosts without the
|
||||||
|
* daedalus module loaded; HEVC routes to rpi-hevc-dec as before.
|
||||||
|
*
|
||||||
|
* Fields are unconditional (8 bytes per session) so the struct
|
||||||
|
* layout is stable regardless of meson option. The active
|
||||||
|
* probe + dispatch code in request.c is gated by
|
||||||
|
* HAVE_DAEDALUS_V4L2; when disabled the fields stay at their
|
||||||
|
* -1 init and no codepath touches them.
|
||||||
|
*/
|
||||||
|
int video_fd_daedalus;
|
||||||
|
int media_fd_daedalus;
|
||||||
|
/*
|
||||||
|
* ampere-av1-enablement Phase 2: fourth multi-device-probe slot
|
||||||
|
* for vpu981 (RK3588's dedicated AV1 hantro instance, kernel
|
||||||
|
* card="rockchip,rk3588-av1-vpu-dec", driver name "hantro-vpu" —
|
||||||
|
* shared with the legacy MPEG-2/VP8/H.264 hantro). Discriminated
|
||||||
|
* by V4L2_PIX_FMT_AV1_FRAME (AV1F) OUTPUT-pixfmt capability since
|
||||||
|
* the driver name alone is ambiguous on RK3588. Stays -1 on hosts
|
||||||
|
* without the AV1 vpu-dec.
|
||||||
|
*
|
||||||
|
* Named "vpu981" for consistency with the in-progress av1-iter1
|
||||||
|
* operator branch (Phase 3-5 bit-exact AV1 work — when that lands
|
||||||
|
* these fields receive the actual decode dispatch wiring).
|
||||||
|
*/
|
||||||
|
int video_fd_vpu981;
|
||||||
|
int media_fd_vpu981;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* iter2 (ampere-kernel-decoders campaign) — per-fd probe result
|
* iter2 (ampere-kernel-decoders campaign) — per-fd probe result
|
||||||
|
|||||||
+26
-3
@@ -476,12 +476,35 @@ int v4l2_set_controls(int video_fd, int request_fd,
|
|||||||
struct v4l2_ext_control *control_array,
|
struct v4l2_ext_control *control_array,
|
||||||
unsigned int num_controls)
|
unsigned int num_controls)
|
||||||
{
|
{
|
||||||
|
struct v4l2_ext_controls controls;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = v4l2_ioctl_controls(video_fd, request_fd, VIDIOC_S_EXT_CTRLS,
|
memset(&controls, 0, sizeof(controls));
|
||||||
control_array, num_controls);
|
controls.controls = control_array;
|
||||||
|
controls.count = num_controls;
|
||||||
|
if (request_fd >= 0) {
|
||||||
|
controls.which = V4L2_CTRL_WHICH_REQUEST_VAL;
|
||||||
|
controls.request_fd = request_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ioctl(video_fd, VIDIOC_S_EXT_CTRLS, &controls);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
request_log("Unable to set control(s): %s\n", strerror(errno));
|
/* error_idx is the index of the first failing control;
|
||||||
|
* if it equals count, the ioctl itself failed (not a
|
||||||
|
* specific control payload). Useful for triaging
|
||||||
|
* which V4L2_CID_STATELESS_* the kernel rejected. */
|
||||||
|
if (controls.error_idx < num_controls)
|
||||||
|
request_log("Unable to set control(s): %s "
|
||||||
|
"(error_idx=%u/%u failing_ctrl_id=0x%x size=%u)\n",
|
||||||
|
strerror(errno),
|
||||||
|
controls.error_idx, controls.count,
|
||||||
|
control_array[controls.error_idx].id,
|
||||||
|
control_array[controls.error_idx].size);
|
||||||
|
else
|
||||||
|
request_log("Unable to set control(s): %s "
|
||||||
|
"(error_idx=%u/%u ioctl-level)\n",
|
||||||
|
strerror(errno),
|
||||||
|
controls.error_idx, controls.count);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user