mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-10 04:07:23 +00:00
Reland "Add a VAAPI wrapper crate"
This is a reland of commit 213f9fe8a7
.
In light of the upcoming VAAPI video decoder backend, add a VAAPI
wrapper crate that exposes a safe Rust API for a subset of the VAAPI C
code. This crate will be called from the VAAPI video decoder backend in
order to decode frames.
BUG=b:214478588
TEST=cargo build --features "video-decoder,vaapi"
TEST=`cargo test -- --include-ignored` in `media/libva` passes on a
device with Intel GPU and libva installed.
Change-Id: I586a160e477e466985c5cfa65a527542ddc03226
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3752274
Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org>
Commit-Queue: Alexandre Courbot <acourbot@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
155f7ad98a
commit
9dbb169557
23 changed files with 11147 additions and 0 deletions
|
@ -65,6 +65,7 @@ members = [
|
|||
"kvm_sys",
|
||||
"linux_input_sys",
|
||||
"media/ffmpeg",
|
||||
"media/libva",
|
||||
"media/libvda",
|
||||
"net_sys",
|
||||
"net_util",
|
||||
|
|
15
media/libva/Cargo.toml
Normal file
15
media/libva/Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "libva"
|
||||
version = "0.1.0"
|
||||
authors = ["The Chromium OS Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "*"
|
||||
bitflags = "1"
|
||||
base = { path = "../../base" }
|
||||
libudev = "0.2.0"
|
||||
crc32fast = "1.2.1"
|
||||
|
||||
[build-dependencies]
|
||||
pkg-config = "*"
|
52
media/libva/README.md
Normal file
52
media/libva/README.md
Normal file
|
@ -0,0 +1,52 @@
|
|||
# Libva Rust wrapper
|
||||
|
||||
Rust wrapper for libva. Provides safe libva abstractions for use within Rust code using its own
|
||||
bindgen-generated bindings.
|
||||
|
||||
This crate is used as part of the VirtIO Video VA-API backend. VA-API uses the GPU to perform the
|
||||
actual decoding/encoding of frames. In doing so, it frees the CPU for other uses and reduces power
|
||||
usage in the system. Hardware accelerated media workflows also tend to be faster than their software
|
||||
counterparts.
|
||||
|
||||
Note: This create requires the native [libva](https://github.com/intel/libva) library at link time.
|
||||
It also requires a VA-API driver to be installed on the system. The VA-API driver to use depends on
|
||||
the underlying hardware, e.g.: the implementation for Intel hardware is in
|
||||
[intel-media-driver](https://github.com/intel/media-driver), whereas AMD hardware will depend on
|
||||
[Mesa](https://gitlab.freedesktop.org/mesa/mesa).
|
||||
|
||||
An easy way to see whether everything is in order is to run the `vainfo` utility. This is usually
|
||||
packaged with `libva-utils` or as a standalone package in some distributions. `vainfo` will print
|
||||
the VA-API version, the driver string, and a list of supported profiles and endpoints, i.e.:
|
||||
|
||||
```
|
||||
vainfo: VA-API version: 1.13 (libva 2.13.0)
|
||||
vainfo: Driver version: Intel iHD driver for Intel(R) Gen Graphics - 22.2.2 ()
|
||||
vainfo: Supported profile and entrypoints
|
||||
VAProfileNone : VAEntrypointVideoProc
|
||||
VAProfileNone : VAEntrypointStats
|
||||
VAProfileMPEG2Simple : VAEntrypointVLD
|
||||
VAProfileMPEG2Simple : VAEntrypointEncSlice
|
||||
VAProfileMPEG2Main : VAEntrypointVLD
|
||||
VAProfileMPEG2Main : VAEntrypointEncSlice
|
||||
VAProfileH264Main : VAEntrypointVLD
|
||||
etc
|
||||
```
|
||||
|
||||
For decoding, the desired profile must be supported under `VAEntrypointVLD`. For example, in order
|
||||
to decode VP8 media, this line must be present in the output of `vainfo`:
|
||||
|
||||
```
|
||||
VAProfileVP8Version0_3 : VAEntrypointVLD
|
||||
```
|
||||
|
||||
Whereas to decode H264 Main profile media, this line must be present:
|
||||
|
||||
```
|
||||
VAProfileH264Main : VAEntrypointVLD
|
||||
```
|
||||
|
||||
For more information on VA-API and its usage within ChromeOS, see
|
||||
[this guide](https://chromium.googlesource.com/chromium/src/+/master/docs/gpu/vaapi.md).
|
||||
|
||||
For a brief introduction on how to use this crate, see the `libva_utils_mpeg2vldemo` test under
|
||||
src/lib.rs.
|
22
media/libva/bindgen.sh
Executable file
22
media/libva/bindgen.sh
Executable file
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
#
|
||||
# Regenerate libva bindgen bindings.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")/../.."
|
||||
source tools/impl/bindgen-common.sh
|
||||
bindgen_generate \
|
||||
--raw-line "pub mod constants;" \
|
||||
--with-derive-eq \
|
||||
--constified-enum-module "VA.*" \
|
||||
--allowlist-function "va.*" \
|
||||
--allowlist-type ".*MPEG2.*|.*VP8.*|.*VP9.*|.*H264.*" \
|
||||
"media/libva/libva-wrapper.h" \
|
||||
> media/libva/src/bindings/va.rs
|
||||
|
||||
bindgen_generate \
|
||||
--allowlist-var "VA.*" \
|
||||
"media/libva/libva-wrapper.h" \
|
||||
> media/libva/src/bindings/va/constants.rs
|
18
media/libva/build.rs
Normal file
18
media/libva/build.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
fn main() {
|
||||
// Skip installing dependencies when generating documents.
|
||||
if std::env::var("CARGO_DOC").is_ok() {
|
||||
return;
|
||||
}
|
||||
|
||||
match pkg_config::probe_library("libva") {
|
||||
Ok(_) => (),
|
||||
Err(e) => panic!("Libva not found: {}", e),
|
||||
};
|
||||
|
||||
println!("cargo:rustc-link-lib=dylib=va");
|
||||
println!("cargo:rustc-link-lib=dylib=va-drm"); // for the vaGetDisplayDRM entrypoint
|
||||
}
|
6
media/libva/libva-wrapper.h
Normal file
6
media/libva/libva-wrapper.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <va/va.h>
|
||||
#include <va/va_drm.h>
|
10
media/libva/src/bindings.rs
Normal file
10
media/libva/src/bindings.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
//! This module implements the bindgen C FFI bindings for use within this crate
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub mod va;
|
||||
|
||||
pub use va::*;
|
8126
media/libva/src/bindings/va.rs
Normal file
8126
media/libva/src/bindings/va.rs
Normal file
File diff suppressed because it is too large
Load diff
345
media/libva/src/bindings/va/constants.rs
Normal file
345
media/libva/src/bindings/va/constants.rs
Normal file
|
@ -0,0 +1,345 @@
|
|||
/* automatically generated by tools/bindgen-all-the-things */
|
||||
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub const VA_MAJOR_VERSION: u32 = 1;
|
||||
pub const VA_MINOR_VERSION: u32 = 14;
|
||||
pub const VA_MICRO_VERSION: u32 = 0;
|
||||
pub const VA_VERSION_S: &[u8; 7usize] = b"1.14.0\0";
|
||||
pub const VA_VERSION_HEX: u32 = 17694720;
|
||||
pub const VA_STATUS_SUCCESS: u32 = 0;
|
||||
pub const VA_STATUS_ERROR_OPERATION_FAILED: u32 = 1;
|
||||
pub const VA_STATUS_ERROR_ALLOCATION_FAILED: u32 = 2;
|
||||
pub const VA_STATUS_ERROR_INVALID_DISPLAY: u32 = 3;
|
||||
pub const VA_STATUS_ERROR_INVALID_CONFIG: u32 = 4;
|
||||
pub const VA_STATUS_ERROR_INVALID_CONTEXT: u32 = 5;
|
||||
pub const VA_STATUS_ERROR_INVALID_SURFACE: u32 = 6;
|
||||
pub const VA_STATUS_ERROR_INVALID_BUFFER: u32 = 7;
|
||||
pub const VA_STATUS_ERROR_INVALID_IMAGE: u32 = 8;
|
||||
pub const VA_STATUS_ERROR_INVALID_SUBPICTURE: u32 = 9;
|
||||
pub const VA_STATUS_ERROR_ATTR_NOT_SUPPORTED: u32 = 10;
|
||||
pub const VA_STATUS_ERROR_MAX_NUM_EXCEEDED: u32 = 11;
|
||||
pub const VA_STATUS_ERROR_UNSUPPORTED_PROFILE: u32 = 12;
|
||||
pub const VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT: u32 = 13;
|
||||
pub const VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT: u32 = 14;
|
||||
pub const VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE: u32 = 15;
|
||||
pub const VA_STATUS_ERROR_SURFACE_BUSY: u32 = 16;
|
||||
pub const VA_STATUS_ERROR_FLAG_NOT_SUPPORTED: u32 = 17;
|
||||
pub const VA_STATUS_ERROR_INVALID_PARAMETER: u32 = 18;
|
||||
pub const VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED: u32 = 19;
|
||||
pub const VA_STATUS_ERROR_UNIMPLEMENTED: u32 = 20;
|
||||
pub const VA_STATUS_ERROR_SURFACE_IN_DISPLAYING: u32 = 21;
|
||||
pub const VA_STATUS_ERROR_INVALID_IMAGE_FORMAT: u32 = 22;
|
||||
pub const VA_STATUS_ERROR_DECODING_ERROR: u32 = 23;
|
||||
pub const VA_STATUS_ERROR_ENCODING_ERROR: u32 = 24;
|
||||
pub const VA_STATUS_ERROR_INVALID_VALUE: u32 = 25;
|
||||
pub const VA_STATUS_ERROR_UNSUPPORTED_FILTER: u32 = 32;
|
||||
pub const VA_STATUS_ERROR_INVALID_FILTER_CHAIN: u32 = 33;
|
||||
pub const VA_STATUS_ERROR_HW_BUSY: u32 = 34;
|
||||
pub const VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE: u32 = 36;
|
||||
pub const VA_STATUS_ERROR_NOT_ENOUGH_BUFFER: u32 = 37;
|
||||
pub const VA_STATUS_ERROR_TIMEDOUT: u32 = 38;
|
||||
pub const VA_STATUS_ERROR_UNKNOWN: u32 = 4294967295;
|
||||
pub const VA_FRAME_PICTURE: u32 = 0;
|
||||
pub const VA_TOP_FIELD: u32 = 1;
|
||||
pub const VA_BOTTOM_FIELD: u32 = 2;
|
||||
pub const VA_TOP_FIELD_FIRST: u32 = 4;
|
||||
pub const VA_BOTTOM_FIELD_FIRST: u32 = 8;
|
||||
pub const VA_ENABLE_BLEND: u32 = 4;
|
||||
pub const VA_CLEAR_DRAWABLE: u32 = 8;
|
||||
pub const VA_SRC_COLOR_MASK: u32 = 240;
|
||||
pub const VA_SRC_BT601: u32 = 16;
|
||||
pub const VA_SRC_BT709: u32 = 32;
|
||||
pub const VA_SRC_SMPTE_240: u32 = 64;
|
||||
pub const VA_FILTER_SCALING_DEFAULT: u32 = 0;
|
||||
pub const VA_FILTER_SCALING_FAST: u32 = 256;
|
||||
pub const VA_FILTER_SCALING_HQ: u32 = 512;
|
||||
pub const VA_FILTER_SCALING_NL_ANAMORPHIC: u32 = 768;
|
||||
pub const VA_FILTER_SCALING_MASK: u32 = 3840;
|
||||
pub const VA_FILTER_INTERPOLATION_DEFAULT: u32 = 0;
|
||||
pub const VA_FILTER_INTERPOLATION_NEAREST_NEIGHBOR: u32 = 4096;
|
||||
pub const VA_FILTER_INTERPOLATION_BILINEAR: u32 = 8192;
|
||||
pub const VA_FILTER_INTERPOLATION_ADVANCED: u32 = 12288;
|
||||
pub const VA_FILTER_INTERPOLATION_MASK: u32 = 61440;
|
||||
pub const VA_PADDING_LOW: u32 = 4;
|
||||
pub const VA_PADDING_MEDIUM: u32 = 8;
|
||||
pub const VA_PADDING_HIGH: u32 = 16;
|
||||
pub const VA_PADDING_LARGE: u32 = 32;
|
||||
pub const VA_EXEC_SYNC: u32 = 0;
|
||||
pub const VA_EXEC_ASYNC: u32 = 1;
|
||||
pub const VA_EXEC_MODE_DEFAULT: u32 = 0;
|
||||
pub const VA_EXEC_MODE_POWER_SAVING: u32 = 1;
|
||||
pub const VA_EXEC_MODE_PERFORMANCE: u32 = 2;
|
||||
pub const VA_FEATURE_NOT_SUPPORTED: u32 = 0;
|
||||
pub const VA_FEATURE_SUPPORTED: u32 = 1;
|
||||
pub const VA_FEATURE_REQUIRED: u32 = 2;
|
||||
pub const VA_RT_FORMAT_YUV420: u32 = 1;
|
||||
pub const VA_RT_FORMAT_YUV422: u32 = 2;
|
||||
pub const VA_RT_FORMAT_YUV444: u32 = 4;
|
||||
pub const VA_RT_FORMAT_YUV411: u32 = 8;
|
||||
pub const VA_RT_FORMAT_YUV400: u32 = 16;
|
||||
pub const VA_RT_FORMAT_YUV420_10: u32 = 256;
|
||||
pub const VA_RT_FORMAT_YUV422_10: u32 = 512;
|
||||
pub const VA_RT_FORMAT_YUV444_10: u32 = 1024;
|
||||
pub const VA_RT_FORMAT_YUV420_12: u32 = 4096;
|
||||
pub const VA_RT_FORMAT_YUV422_12: u32 = 8192;
|
||||
pub const VA_RT_FORMAT_YUV444_12: u32 = 16384;
|
||||
pub const VA_RT_FORMAT_RGB16: u32 = 65536;
|
||||
pub const VA_RT_FORMAT_RGB32: u32 = 131072;
|
||||
pub const VA_RT_FORMAT_RGBP: u32 = 1048576;
|
||||
pub const VA_RT_FORMAT_RGB32_10: u32 = 2097152;
|
||||
pub const VA_RT_FORMAT_PROTECTED: u32 = 2147483648;
|
||||
pub const VA_RT_FORMAT_RGB32_10BPP: u32 = 2097152;
|
||||
pub const VA_RT_FORMAT_YUV420_10BPP: u32 = 256;
|
||||
pub const VA_RC_NONE: u32 = 1;
|
||||
pub const VA_RC_CBR: u32 = 2;
|
||||
pub const VA_RC_VBR: u32 = 4;
|
||||
pub const VA_RC_VCM: u32 = 8;
|
||||
pub const VA_RC_CQP: u32 = 16;
|
||||
pub const VA_RC_VBR_CONSTRAINED: u32 = 32;
|
||||
pub const VA_RC_ICQ: u32 = 64;
|
||||
pub const VA_RC_MB: u32 = 128;
|
||||
pub const VA_RC_CFS: u32 = 256;
|
||||
pub const VA_RC_PARALLEL: u32 = 512;
|
||||
pub const VA_RC_QVBR: u32 = 1024;
|
||||
pub const VA_RC_AVBR: u32 = 2048;
|
||||
pub const VA_RC_TCBRC: u32 = 4096;
|
||||
pub const VA_DEC_SLICE_MODE_NORMAL: u32 = 1;
|
||||
pub const VA_DEC_SLICE_MODE_BASE: u32 = 2;
|
||||
pub const VA_DEC_PROCESSING_NONE: u32 = 0;
|
||||
pub const VA_DEC_PROCESSING: u32 = 1;
|
||||
pub const VA_ENC_PACKED_HEADER_NONE: u32 = 0;
|
||||
pub const VA_ENC_PACKED_HEADER_SEQUENCE: u32 = 1;
|
||||
pub const VA_ENC_PACKED_HEADER_PICTURE: u32 = 2;
|
||||
pub const VA_ENC_PACKED_HEADER_SLICE: u32 = 4;
|
||||
pub const VA_ENC_PACKED_HEADER_MISC: u32 = 8;
|
||||
pub const VA_ENC_PACKED_HEADER_RAW_DATA: u32 = 16;
|
||||
pub const VA_ENC_INTERLACED_NONE: u32 = 0;
|
||||
pub const VA_ENC_INTERLACED_FRAME: u32 = 1;
|
||||
pub const VA_ENC_INTERLACED_FIELD: u32 = 2;
|
||||
pub const VA_ENC_INTERLACED_MBAFF: u32 = 4;
|
||||
pub const VA_ENC_INTERLACED_PAFF: u32 = 8;
|
||||
pub const VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS: u32 = 1;
|
||||
pub const VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS: u32 = 2;
|
||||
pub const VA_ENC_SLICE_STRUCTURE_EQUAL_ROWS: u32 = 4;
|
||||
pub const VA_ENC_SLICE_STRUCTURE_MAX_SLICE_SIZE: u32 = 8;
|
||||
pub const VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS: u32 = 16;
|
||||
pub const VA_ENC_SLICE_STRUCTURE_EQUAL_MULTI_ROWS: u32 = 32;
|
||||
pub const VA_ENC_QUANTIZATION_NONE: u32 = 0;
|
||||
pub const VA_ENC_QUANTIZATION_TRELLIS_SUPPORTED: u32 = 1;
|
||||
pub const VA_PREDICTION_DIRECTION_PREVIOUS: u32 = 1;
|
||||
pub const VA_PREDICTION_DIRECTION_FUTURE: u32 = 2;
|
||||
pub const VA_PREDICTION_DIRECTION_BI_NOT_EMPTY: u32 = 4;
|
||||
pub const VA_ENC_INTRA_REFRESH_NONE: u32 = 0;
|
||||
pub const VA_ENC_INTRA_REFRESH_ROLLING_COLUMN: u32 = 1;
|
||||
pub const VA_ENC_INTRA_REFRESH_ROLLING_ROW: u32 = 2;
|
||||
pub const VA_ENC_INTRA_REFRESH_ADAPTIVE: u32 = 16;
|
||||
pub const VA_ENC_INTRA_REFRESH_CYCLIC: u32 = 32;
|
||||
pub const VA_ENC_INTRA_REFRESH_P_FRAME: u32 = 65536;
|
||||
pub const VA_ENC_INTRA_REFRESH_B_FRAME: u32 = 131072;
|
||||
pub const VA_ENC_INTRA_REFRESH_MULTI_REF: u32 = 262144;
|
||||
pub const VA_PC_CIPHER_AES: u32 = 1;
|
||||
pub const VA_PC_BLOCK_SIZE_128: u32 = 1;
|
||||
pub const VA_PC_BLOCK_SIZE_192: u32 = 2;
|
||||
pub const VA_PC_BLOCK_SIZE_256: u32 = 4;
|
||||
pub const VA_PC_CIPHER_MODE_ECB: u32 = 1;
|
||||
pub const VA_PC_CIPHER_MODE_CBC: u32 = 2;
|
||||
pub const VA_PC_CIPHER_MODE_CTR: u32 = 4;
|
||||
pub const VA_PC_SAMPLE_TYPE_FULLSAMPLE: u32 = 1;
|
||||
pub const VA_PC_SAMPLE_TYPE_SUBSAMPLE: u32 = 2;
|
||||
pub const VA_PC_USAGE_DEFAULT: u32 = 0;
|
||||
pub const VA_PC_USAGE_WIDEVINE: u32 = 1;
|
||||
pub const VA_PROCESSING_RATE_NONE: u32 = 0;
|
||||
pub const VA_PROCESSING_RATE_ENCODE: u32 = 1;
|
||||
pub const VA_PROCESSING_RATE_DECODE: u32 = 2;
|
||||
pub const VA_ATTRIB_NOT_SUPPORTED: u32 = 2147483648;
|
||||
pub const VA_INVALID_ID: u32 = 4294967295;
|
||||
pub const VA_INVALID_SURFACE: u32 = 4294967295;
|
||||
pub const VA_SURFACE_ATTRIB_NOT_SUPPORTED: u32 = 0;
|
||||
pub const VA_SURFACE_ATTRIB_GETTABLE: u32 = 1;
|
||||
pub const VA_SURFACE_ATTRIB_SETTABLE: u32 = 2;
|
||||
pub const VA_SURFACE_ATTRIB_MEM_TYPE_VA: u32 = 1;
|
||||
pub const VA_SURFACE_ATTRIB_MEM_TYPE_V4L2: u32 = 2;
|
||||
pub const VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR: u32 = 4;
|
||||
pub const VA_SURFACE_EXTBUF_DESC_ENABLE_TILING: u32 = 1;
|
||||
pub const VA_SURFACE_EXTBUF_DESC_CACHED: u32 = 2;
|
||||
pub const VA_SURFACE_EXTBUF_DESC_UNCACHED: u32 = 4;
|
||||
pub const VA_SURFACE_EXTBUF_DESC_WC: u32 = 8;
|
||||
pub const VA_SURFACE_EXTBUF_DESC_PROTECTED: u32 = 2147483648;
|
||||
pub const VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC: u32 = 0;
|
||||
pub const VA_SURFACE_ATTRIB_USAGE_HINT_DECODER: u32 = 1;
|
||||
pub const VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER: u32 = 2;
|
||||
pub const VA_SURFACE_ATTRIB_USAGE_HINT_VPP_READ: u32 = 4;
|
||||
pub const VA_SURFACE_ATTRIB_USAGE_HINT_VPP_WRITE: u32 = 8;
|
||||
pub const VA_SURFACE_ATTRIB_USAGE_HINT_DISPLAY: u32 = 16;
|
||||
pub const VA_SURFACE_ATTRIB_USAGE_HINT_EXPORT: u32 = 32;
|
||||
pub const VA_PROGRESSIVE: u32 = 1;
|
||||
pub const VA_ENCRYPTION_TYPE_FULLSAMPLE_CTR: u32 = 1;
|
||||
pub const VA_ENCRYPTION_TYPE_FULLSAMPLE_CBC: u32 = 2;
|
||||
pub const VA_ENCRYPTION_TYPE_SUBSAMPLE_CTR: u32 = 4;
|
||||
pub const VA_ENCRYPTION_TYPE_SUBSAMPLE_CBC: u32 = 8;
|
||||
pub const VA_SLICE_DATA_FLAG_ALL: u32 = 0;
|
||||
pub const VA_SLICE_DATA_FLAG_BEGIN: u32 = 1;
|
||||
pub const VA_SLICE_DATA_FLAG_MIDDLE: u32 = 2;
|
||||
pub const VA_SLICE_DATA_FLAG_END: u32 = 4;
|
||||
pub const VA_MB_TYPE_MOTION_FORWARD: u32 = 2;
|
||||
pub const VA_MB_TYPE_MOTION_BACKWARD: u32 = 4;
|
||||
pub const VA_MB_TYPE_MOTION_PATTERN: u32 = 8;
|
||||
pub const VA_MB_TYPE_MOTION_INTRA: u32 = 16;
|
||||
pub const VA_PICTURE_H264_INVALID: u32 = 1;
|
||||
pub const VA_PICTURE_H264_TOP_FIELD: u32 = 2;
|
||||
pub const VA_PICTURE_H264_BOTTOM_FIELD: u32 = 4;
|
||||
pub const VA_PICTURE_H264_SHORT_TERM_REFERENCE: u32 = 8;
|
||||
pub const VA_PICTURE_H264_LONG_TERM_REFERENCE: u32 = 16;
|
||||
pub const VA_CODED_BUF_STATUS_PICTURE_AVE_QP_MASK: u32 = 255;
|
||||
pub const VA_CODED_BUF_STATUS_LARGE_SLICE_MASK: u32 = 256;
|
||||
pub const VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK: u32 = 512;
|
||||
pub const VA_CODED_BUF_STATUS_BITRATE_OVERFLOW: u32 = 1024;
|
||||
pub const VA_CODED_BUF_STATUS_BITRATE_HIGH: u32 = 2048;
|
||||
pub const VA_CODED_BUF_STATUS_FRAME_SIZE_OVERFLOW: u32 = 4096;
|
||||
pub const VA_CODED_BUF_STATUS_BAD_BITSTREAM: u32 = 32768;
|
||||
pub const VA_CODED_BUF_STATUS_AIR_MB_OVER_THRESHOLD: u32 = 16711680;
|
||||
pub const VA_CODED_BUF_STATUS_NUMBER_PASSES_MASK: u32 = 251658240;
|
||||
pub const VA_CODED_BUF_STATUS_SINGLE_NALU: u32 = 268435456;
|
||||
pub const VA_EXPORT_SURFACE_READ_ONLY: u32 = 1;
|
||||
pub const VA_EXPORT_SURFACE_WRITE_ONLY: u32 = 2;
|
||||
pub const VA_EXPORT_SURFACE_READ_WRITE: u32 = 3;
|
||||
pub const VA_EXPORT_SURFACE_SEPARATE_LAYERS: u32 = 4;
|
||||
pub const VA_EXPORT_SURFACE_COMPOSED_LAYERS: u32 = 8;
|
||||
pub const VA_TIMEOUT_INFINITE: i32 = -1;
|
||||
pub const VA_FOURCC_NV12: u32 = 842094158;
|
||||
pub const VA_FOURCC_NV21: u32 = 825382478;
|
||||
pub const VA_FOURCC_AI44: u32 = 875839817;
|
||||
pub const VA_FOURCC_RGBA: u32 = 1094862674;
|
||||
pub const VA_FOURCC_RGBX: u32 = 1480738642;
|
||||
pub const VA_FOURCC_BGRA: u32 = 1095911234;
|
||||
pub const VA_FOURCC_BGRX: u32 = 1481787202;
|
||||
pub const VA_FOURCC_ARGB: u32 = 1111970369;
|
||||
pub const VA_FOURCC_XRGB: u32 = 1111970392;
|
||||
pub const VA_FOURCC_ABGR: u32 = 1380401729;
|
||||
pub const VA_FOURCC_XBGR: u32 = 1380401752;
|
||||
pub const VA_FOURCC_UYVY: u32 = 1498831189;
|
||||
pub const VA_FOURCC_YUY2: u32 = 844715353;
|
||||
pub const VA_FOURCC_AYUV: u32 = 1448433985;
|
||||
pub const VA_FOURCC_NV11: u32 = 825316942;
|
||||
pub const VA_FOURCC_YV12: u32 = 842094169;
|
||||
pub const VA_FOURCC_P208: u32 = 942682704;
|
||||
pub const VA_FOURCC_I420: u32 = 808596553;
|
||||
pub const VA_FOURCC_YV24: u32 = 875714137;
|
||||
pub const VA_FOURCC_YV32: u32 = 842225241;
|
||||
pub const VA_FOURCC_Y800: u32 = 808466521;
|
||||
pub const VA_FOURCC_IMC3: u32 = 860048713;
|
||||
pub const VA_FOURCC_411P: u32 = 1345401140;
|
||||
pub const VA_FOURCC_411R: u32 = 1378955572;
|
||||
pub const VA_FOURCC_422H: u32 = 1211249204;
|
||||
pub const VA_FOURCC_422V: u32 = 1446130228;
|
||||
pub const VA_FOURCC_444P: u32 = 1345598516;
|
||||
pub const VA_FOURCC_RGBP: u32 = 1346520914;
|
||||
pub const VA_FOURCC_BGRP: u32 = 1347569474;
|
||||
pub const VA_FOURCC_RGB565: u32 = 909199186;
|
||||
pub const VA_FOURCC_BGR565: u32 = 909199170;
|
||||
pub const VA_FOURCC_Y210: u32 = 808530521;
|
||||
pub const VA_FOURCC_Y212: u32 = 842084953;
|
||||
pub const VA_FOURCC_Y216: u32 = 909193817;
|
||||
pub const VA_FOURCC_Y410: u32 = 808531033;
|
||||
pub const VA_FOURCC_Y412: u32 = 842085465;
|
||||
pub const VA_FOURCC_Y416: u32 = 909194329;
|
||||
pub const VA_FOURCC_YV16: u32 = 909203033;
|
||||
pub const VA_FOURCC_P010: u32 = 808530000;
|
||||
pub const VA_FOURCC_P012: u32 = 842084432;
|
||||
pub const VA_FOURCC_P016: u32 = 909193296;
|
||||
pub const VA_FOURCC_I010: u32 = 808529993;
|
||||
pub const VA_FOURCC_IYUV: u32 = 1448433993;
|
||||
pub const VA_FOURCC_A2R10G10B10: u32 = 808669761;
|
||||
pub const VA_FOURCC_A2B10G10R10: u32 = 808665665;
|
||||
pub const VA_FOURCC_X2R10G10B10: u32 = 808669784;
|
||||
pub const VA_FOURCC_X2B10G10R10: u32 = 808665688;
|
||||
pub const VA_FOURCC_Y8: u32 = 538982489;
|
||||
pub const VA_FOURCC_Y16: u32 = 540422489;
|
||||
pub const VA_FOURCC_VYUY: u32 = 1498765654;
|
||||
pub const VA_FOURCC_YVYU: u32 = 1431918169;
|
||||
pub const VA_FOURCC_ARGB64: u32 = 877089345;
|
||||
pub const VA_FOURCC_ABGR64: u32 = 877085249;
|
||||
pub const VA_FOURCC_XYUV: u32 = 1448434008;
|
||||
pub const VA_LSB_FIRST: u32 = 1;
|
||||
pub const VA_MSB_FIRST: u32 = 2;
|
||||
pub const VA_SUBPICTURE_CHROMA_KEYING: u32 = 1;
|
||||
pub const VA_SUBPICTURE_GLOBAL_ALPHA: u32 = 2;
|
||||
pub const VA_SUBPICTURE_DESTINATION_IS_SCREEN_COORD: u32 = 4;
|
||||
pub const VA_ROTATION_NONE: u32 = 0;
|
||||
pub const VA_ROTATION_90: u32 = 1;
|
||||
pub const VA_ROTATION_180: u32 = 2;
|
||||
pub const VA_ROTATION_270: u32 = 3;
|
||||
pub const VA_MIRROR_NONE: u32 = 0;
|
||||
pub const VA_MIRROR_HORIZONTAL: u32 = 1;
|
||||
pub const VA_MIRROR_VERTICAL: u32 = 2;
|
||||
pub const VA_OOL_DEBLOCKING_FALSE: u32 = 0;
|
||||
pub const VA_OOL_DEBLOCKING_TRUE: u32 = 1;
|
||||
pub const VA_RENDER_MODE_UNDEFINED: u32 = 0;
|
||||
pub const VA_RENDER_MODE_LOCAL_OVERLAY: u32 = 1;
|
||||
pub const VA_RENDER_MODE_LOCAL_GPU: u32 = 2;
|
||||
pub const VA_RENDER_MODE_EXTERNAL_OVERLAY: u32 = 4;
|
||||
pub const VA_RENDER_MODE_EXTERNAL_GPU: u32 = 8;
|
||||
pub const VA_RENDER_DEVICE_UNDEFINED: u32 = 0;
|
||||
pub const VA_RENDER_DEVICE_LOCAL: u32 = 1;
|
||||
pub const VA_RENDER_DEVICE_EXTERNAL: u32 = 2;
|
||||
pub const VA_DISPLAY_ATTRIB_NOT_SUPPORTED: u32 = 0;
|
||||
pub const VA_DISPLAY_ATTRIB_GETTABLE: u32 = 1;
|
||||
pub const VA_DISPLAY_ATTRIB_SETTABLE: u32 = 2;
|
||||
pub const VA_PICTURE_HEVC_INVALID: u32 = 1;
|
||||
pub const VA_PICTURE_HEVC_FIELD_PIC: u32 = 2;
|
||||
pub const VA_PICTURE_HEVC_BOTTOM_FIELD: u32 = 4;
|
||||
pub const VA_PICTURE_HEVC_LONG_TERM_REFERENCE: u32 = 8;
|
||||
pub const VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE: u32 = 16;
|
||||
pub const VA_PICTURE_HEVC_RPS_ST_CURR_AFTER: u32 = 32;
|
||||
pub const VA_PICTURE_HEVC_RPS_LT_CURR: u32 = 64;
|
||||
pub const VA_FEI_FUNCTION_ENC: u32 = 1;
|
||||
pub const VA_FEI_FUNCTION_PAK: u32 = 2;
|
||||
pub const VA_FEI_FUNCTION_ENC_PAK: u32 = 4;
|
||||
pub const VA_PICTURE_STATS_INVALID: u32 = 1;
|
||||
pub const VA_PICTURE_STATS_PROGRESSIVE: u32 = 0;
|
||||
pub const VA_PICTURE_STATS_TOP_FIELD: u32 = 2;
|
||||
pub const VA_PICTURE_STATS_BOTTOM_FIELD: u32 = 4;
|
||||
pub const VA_PICTURE_STATS_CONTENT_UPDATED: u32 = 16;
|
||||
pub const VA_MB_PRED_AVAIL_TOP_LEFT: u32 = 4;
|
||||
pub const VA_MB_PRED_AVAIL_TOP: u32 = 16;
|
||||
pub const VA_MB_PRED_AVAIL_TOP_RIGHT: u32 = 8;
|
||||
pub const VA_MB_PRED_AVAIL_LEFT: u32 = 64;
|
||||
pub const VA_AV1_MAX_SEGMENTS: u32 = 8;
|
||||
pub const VA_AV1_SEG_LVL_MAX: u32 = 8;
|
||||
pub const VA_BLEND_GLOBAL_ALPHA: u32 = 1;
|
||||
pub const VA_BLEND_PREMULTIPLIED_ALPHA: u32 = 2;
|
||||
pub const VA_BLEND_LUMA_KEY: u32 = 16;
|
||||
pub const VA_PROC_PIPELINE_SUBPICTURES: u32 = 1;
|
||||
pub const VA_PROC_PIPELINE_FAST: u32 = 2;
|
||||
pub const VA_PROC_FILTER_MANDATORY: u32 = 1;
|
||||
pub const VA_PIPELINE_FLAG_END: u32 = 4;
|
||||
pub const VA_CHROMA_SITING_UNKNOWN: u32 = 0;
|
||||
pub const VA_CHROMA_SITING_VERTICAL_TOP: u32 = 1;
|
||||
pub const VA_CHROMA_SITING_VERTICAL_CENTER: u32 = 2;
|
||||
pub const VA_CHROMA_SITING_VERTICAL_BOTTOM: u32 = 3;
|
||||
pub const VA_CHROMA_SITING_HORIZONTAL_LEFT: u32 = 4;
|
||||
pub const VA_CHROMA_SITING_HORIZONTAL_CENTER: u32 = 8;
|
||||
pub const VA_SOURCE_RANGE_UNKNOWN: u32 = 0;
|
||||
pub const VA_SOURCE_RANGE_REDUCED: u32 = 1;
|
||||
pub const VA_SOURCE_RANGE_FULL: u32 = 2;
|
||||
pub const VA_TONE_MAPPING_HDR_TO_HDR: u32 = 1;
|
||||
pub const VA_TONE_MAPPING_HDR_TO_SDR: u32 = 2;
|
||||
pub const VA_TONE_MAPPING_HDR_TO_EDR: u32 = 4;
|
||||
pub const VA_TONE_MAPPING_SDR_TO_HDR: u32 = 8;
|
||||
pub const VA_DEINTERLACING_BOTTOM_FIELD_FIRST: u32 = 1;
|
||||
pub const VA_DEINTERLACING_BOTTOM_FIELD: u32 = 2;
|
||||
pub const VA_DEINTERLACING_ONE_FIELD: u32 = 4;
|
||||
pub const VA_DEINTERLACING_FMD_ENABLE: u32 = 8;
|
||||
pub const VA_DEINTERLACING_SCD_ENABLE: u32 = 16;
|
||||
pub const VA_PROC_HVS_DENOISE_DEFAULT: u32 = 0;
|
||||
pub const VA_PROC_HVS_DENOISE_AUTO_BDRATE: u32 = 1;
|
||||
pub const VA_PROC_HVS_DENOISE_AUTO_SUBJECTIVE: u32 = 2;
|
||||
pub const VA_PROC_HVS_DENOISE_MANUAL: u32 = 3;
|
||||
pub const VA_3DLUT_CHANNEL_UNKNOWN: u32 = 0;
|
||||
pub const VA_3DLUT_CHANNEL_RGB_RGB: u32 = 1;
|
||||
pub const VA_3DLUT_CHANNEL_YUV_RGB: u32 = 2;
|
||||
pub const VA_3DLUT_CHANNEL_VUY_RGB: u32 = 4;
|
131
media/libva/src/buffer.rs
Normal file
131
media/libva/src/buffer.rs
Normal file
|
@ -0,0 +1,131 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use anyhow::Result;
|
||||
use base::error;
|
||||
|
||||
use crate::{
|
||||
bindings, buffer_type::BufferType, status::Status, Context, IQMatrix, PictureParameter,
|
||||
SliceParameter,
|
||||
};
|
||||
|
||||
/// A wrapper type representing a buffer created with vaCreateBuffer
|
||||
pub struct Buffer {
|
||||
context: Rc<Context>,
|
||||
id: bindings::VABufferID,
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
/// Creates a new Buffer
|
||||
pub(crate) fn new(context: Rc<Context>, mut type_: BufferType) -> Result<Self> {
|
||||
let mut buffer_id = 0;
|
||||
|
||||
let (ptr, size) = match type_ {
|
||||
BufferType::PictureParameter(ref mut picture_param) => match picture_param {
|
||||
PictureParameter::MPEG2(ref mut wrapper) => (
|
||||
wrapper.inner_mut() as *mut _ as *mut std::ffi::c_void,
|
||||
std::mem::size_of_val(wrapper.inner_mut()),
|
||||
),
|
||||
PictureParameter::VP8(ref mut wrapper) => (
|
||||
wrapper.inner_mut() as *mut _ as *mut std::ffi::c_void,
|
||||
std::mem::size_of_val(wrapper.inner_mut()),
|
||||
),
|
||||
PictureParameter::VP9(ref mut wrapper) => (
|
||||
wrapper.inner_mut() as *mut _ as *mut std::ffi::c_void,
|
||||
std::mem::size_of_val(wrapper.inner_mut()),
|
||||
),
|
||||
PictureParameter::H264(ref mut wrapper) => (
|
||||
wrapper.inner_mut() as *mut _ as *mut std::ffi::c_void,
|
||||
std::mem::size_of_val(wrapper.inner_mut()),
|
||||
),
|
||||
},
|
||||
|
||||
BufferType::SliceParameter(ref mut slice_param) => match slice_param {
|
||||
SliceParameter::MPEG2(ref mut wrapper) => (
|
||||
wrapper.inner_mut() as *mut _ as *mut std::ffi::c_void,
|
||||
std::mem::size_of_val(wrapper.inner_mut()),
|
||||
),
|
||||
SliceParameter::VP8(ref mut wrapper) => (
|
||||
wrapper.inner_mut() as *mut _ as *mut std::ffi::c_void,
|
||||
std::mem::size_of_val(wrapper.inner_mut()),
|
||||
),
|
||||
SliceParameter::VP9(ref mut wrapper) => (
|
||||
wrapper.inner_mut() as *mut _ as *mut std::ffi::c_void,
|
||||
std::mem::size_of_val(wrapper.inner_mut()),
|
||||
),
|
||||
SliceParameter::H264(ref mut wrapper) => (
|
||||
wrapper.inner_mut() as *mut _ as *mut std::ffi::c_void,
|
||||
std::mem::size_of_val(wrapper.inner_mut()),
|
||||
),
|
||||
},
|
||||
|
||||
BufferType::IQMatrix(ref mut iq_matrix) => match iq_matrix {
|
||||
IQMatrix::MPEG2(ref mut wrapper) => (
|
||||
wrapper.inner_mut() as *mut _ as *mut std::ffi::c_void,
|
||||
std::mem::size_of_val(wrapper.inner_mut()),
|
||||
),
|
||||
IQMatrix::VP8(ref mut wrapper) => (
|
||||
wrapper.inner_mut() as *mut _ as *mut std::ffi::c_void,
|
||||
std::mem::size_of_val(wrapper.inner_mut()),
|
||||
),
|
||||
IQMatrix::H264(ref mut wrapper) => (
|
||||
wrapper.inner_mut() as *mut _ as *mut std::ffi::c_void,
|
||||
std::mem::size_of_val(wrapper.inner_mut()),
|
||||
),
|
||||
},
|
||||
|
||||
BufferType::Probability(ref mut wrapper) => (
|
||||
wrapper.inner_mut() as *mut _ as *mut std::ffi::c_void,
|
||||
std::mem::size_of_val(wrapper.inner_mut()),
|
||||
),
|
||||
|
||||
BufferType::SliceData(ref mut data) => {
|
||||
(data.as_mut_ptr() as *mut std::ffi::c_void, data.len())
|
||||
}
|
||||
};
|
||||
|
||||
// Safe because `self` represents a valid VAContext. `ptr` and `size`
|
||||
// are also ensured to be correct, as `ptr` is just a cast to `*c_void`
|
||||
// from a Rust struct, and `size` is computed from
|
||||
// `std::mem::size_of_val`
|
||||
Status(unsafe {
|
||||
bindings::vaCreateBuffer(
|
||||
context.display().handle(),
|
||||
context.id(),
|
||||
type_.inner(),
|
||||
size as u32,
|
||||
1,
|
||||
ptr,
|
||||
&mut buffer_id,
|
||||
)
|
||||
})
|
||||
.check()?;
|
||||
|
||||
Ok(Self {
|
||||
context,
|
||||
id: buffer_id,
|
||||
})
|
||||
}
|
||||
|
||||
/// Convenience function to return a VABufferID vector. Useful to interface
|
||||
/// with the C API where a buffer array might be needed.
|
||||
pub fn as_id_vec(buffers: &[Self]) -> Vec<bindings::VABufferID> {
|
||||
buffers.iter().map(|buffer| buffer.id).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Buffer {
|
||||
fn drop(&mut self) {
|
||||
// Safe because `self` represents a valid buffer, created with
|
||||
// vaCreateBuffers.
|
||||
let status =
|
||||
Status(unsafe { bindings::vaDestroyBuffer(self.context.display().handle(), self.id) })
|
||||
.check();
|
||||
if status.is_err() {
|
||||
error!("vaDestroyBuffer failed: {}", status.unwrap_err());
|
||||
}
|
||||
}
|
||||
}
|
941
media/libva/src/buffer_type.rs
Normal file
941
media/libva/src/buffer_type.rs
Normal file
|
@ -0,0 +1,941 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use crate::bindings;
|
||||
|
||||
/// An abstraction over VA BufferTypes
|
||||
pub enum BufferType {
|
||||
/// An abstraction over VAPictureParameterBufferType. Needed for MPEG2, VP8, VP9, H264
|
||||
PictureParameter(PictureParameter),
|
||||
/// An abstraction over VASliceParameterBufferType. Needed for MPEG2, VP8, VP9, H264
|
||||
SliceParameter(SliceParameter),
|
||||
/// An abstraction over VAIQMatrixBufferType. Needed for VP8, H264
|
||||
IQMatrix(IQMatrix),
|
||||
/// An abstraction over VAProbabilityDataBuffeTyper. Needed for VP8
|
||||
Probability(ProbabilityDataBufferVP8),
|
||||
/// An abstraction over VASliceDataBufferType. Needed for VP9, H264
|
||||
SliceData(Vec<u8>),
|
||||
}
|
||||
|
||||
impl BufferType {
|
||||
/// Returns the inner FFI buffer type.
|
||||
pub(crate) fn inner(&self) -> bindings::VABufferType::Type {
|
||||
match self {
|
||||
BufferType::PictureParameter(_) => bindings::VABufferType::VAPictureParameterBufferType,
|
||||
BufferType::SliceParameter(_) => bindings::VABufferType::VASliceParameterBufferType,
|
||||
BufferType::IQMatrix(_) => bindings::VABufferType::VAIQMatrixBufferType,
|
||||
BufferType::Probability(_) => bindings::VABufferType::VAProbabilityBufferType,
|
||||
BufferType::SliceData { .. } => bindings::VABufferType::VASliceDataBufferType,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the `picture_coding_extension` bindgen field in VAPictureParameterBufferMPEG2
|
||||
pub struct MPEG2PictureCodingExtension(bindings::_VAPictureParameterBufferMPEG2__bindgen_ty_1);
|
||||
|
||||
impl MPEG2PictureCodingExtension {
|
||||
/// Creates the bindgen field
|
||||
pub fn new(
|
||||
intra_dc_precision: u32,
|
||||
picture_structure: u32,
|
||||
top_field_first: u32,
|
||||
frame_pred_frame_dct: u32,
|
||||
concealment_motion_vectors: u32,
|
||||
q_scale_type: u32,
|
||||
intra_vlc_format: u32,
|
||||
alternate_scan: u32,
|
||||
repeat_first_field: u32,
|
||||
progressive_frame: u32,
|
||||
is_first_field: u32,
|
||||
) -> Self {
|
||||
let _bitfield_1 =
|
||||
bindings::_VAPictureParameterBufferMPEG2__bindgen_ty_1__bindgen_ty_1::new_bitfield_1(
|
||||
intra_dc_precision,
|
||||
picture_structure,
|
||||
top_field_first,
|
||||
frame_pred_frame_dct,
|
||||
concealment_motion_vectors,
|
||||
q_scale_type,
|
||||
intra_vlc_format,
|
||||
alternate_scan,
|
||||
repeat_first_field,
|
||||
progressive_frame,
|
||||
is_first_field,
|
||||
);
|
||||
|
||||
Self(bindings::_VAPictureParameterBufferMPEG2__bindgen_ty_1 {
|
||||
bits: bindings::_VAPictureParameterBufferMPEG2__bindgen_ty_1__bindgen_ty_1 {
|
||||
_bitfield_align_1: Default::default(),
|
||||
_bitfield_1,
|
||||
__bindgen_padding_0: Default::default(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&mut self) -> &bindings::_VAPictureParameterBufferMPEG2__bindgen_ty_1 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the PictureParameterBufferMPEG2 FFI type.
|
||||
pub struct PictureParameterBufferMPEG2(Box<bindings::VAPictureParameterBufferMPEG2>);
|
||||
|
||||
impl PictureParameterBufferMPEG2 {
|
||||
/// Creates the wrapper
|
||||
pub fn new(
|
||||
horizontal_size: u16,
|
||||
vertical_size: u16,
|
||||
forward_reference_picture: bindings::VASurfaceID,
|
||||
backward_reference_picture: bindings::VASurfaceID,
|
||||
picture_coding_type: i32,
|
||||
f_code: i32,
|
||||
picture_coding_extension: &MPEG2PictureCodingExtension,
|
||||
) -> Self {
|
||||
let picture_coding_extension = picture_coding_extension.0;
|
||||
|
||||
Self(Box::new(bindings::VAPictureParameterBufferMPEG2 {
|
||||
horizontal_size,
|
||||
vertical_size,
|
||||
forward_reference_picture,
|
||||
backward_reference_picture,
|
||||
picture_coding_type,
|
||||
f_code,
|
||||
picture_coding_extension,
|
||||
va_reserved: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn inner_mut(&mut self) -> &mut bindings::VAPictureParameterBufferMPEG2 {
|
||||
self.0.as_mut()
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&mut self) -> &bindings::VAPictureParameterBufferMPEG2 {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the `pic_fields` bindgen field in VAPictureParameterBufferVP8
|
||||
pub struct VP8PicFields(bindings::_VAPictureParameterBufferVP8__bindgen_ty_1);
|
||||
|
||||
impl VP8PicFields {
|
||||
/// Creates the bindgen field
|
||||
pub fn new(
|
||||
key_frame: u32,
|
||||
version: u32,
|
||||
segmentation_enabled: u32,
|
||||
update_mb_segmentation_map: u32,
|
||||
update_segment_feature_data: u32,
|
||||
filter_type: u32,
|
||||
sharpness_level: u32,
|
||||
loop_filter_adj_enable: u32,
|
||||
mode_ref_lf_delta_update: u32,
|
||||
sign_bias_golden: u32,
|
||||
sign_bias_alternate: u32,
|
||||
mb_no_coeff_skip: u32,
|
||||
loop_filter_disable: u32,
|
||||
) -> Self {
|
||||
let _bitfield_1 =
|
||||
bindings::_VAPictureParameterBufferVP8__bindgen_ty_1__bindgen_ty_1::new_bitfield_1(
|
||||
key_frame,
|
||||
version,
|
||||
segmentation_enabled,
|
||||
update_mb_segmentation_map,
|
||||
update_segment_feature_data,
|
||||
filter_type,
|
||||
sharpness_level,
|
||||
loop_filter_adj_enable,
|
||||
mode_ref_lf_delta_update,
|
||||
sign_bias_golden,
|
||||
sign_bias_alternate,
|
||||
mb_no_coeff_skip,
|
||||
loop_filter_disable,
|
||||
);
|
||||
|
||||
Self(bindings::_VAPictureParameterBufferVP8__bindgen_ty_1 {
|
||||
bits: bindings::_VAPictureParameterBufferVP8__bindgen_ty_1__bindgen_ty_1 {
|
||||
_bitfield_align_1: Default::default(),
|
||||
_bitfield_1,
|
||||
__bindgen_padding_0: Default::default(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&self) -> &bindings::_VAPictureParameterBufferVP8__bindgen_ty_1 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the VABoolCoderContextVPX FFI type
|
||||
pub struct BoolCoderContextVPX(bindings::VABoolCoderContextVPX);
|
||||
|
||||
impl BoolCoderContextVPX {
|
||||
/// Creates the wrapper
|
||||
pub fn new(range: u8, value: u8, count: u8) -> Self {
|
||||
Self(bindings::VABoolCoderContextVPX {
|
||||
range,
|
||||
value,
|
||||
count,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the PictureParameterBufferVP8 FFI type
|
||||
pub struct PictureParameterBufferVP8(Box<bindings::VAPictureParameterBufferVP8>);
|
||||
|
||||
impl PictureParameterBufferVP8 {
|
||||
/// Creates the wrapper
|
||||
pub fn new(
|
||||
frame_width: u32,
|
||||
frame_height: u32,
|
||||
last_ref_frame: bindings::VASurfaceID,
|
||||
golden_ref_frame: bindings::VASurfaceID,
|
||||
alt_ref_frame: bindings::VASurfaceID,
|
||||
pic_fields: &VP8PicFields,
|
||||
mb_segment_tree_probs: [u8; 3usize],
|
||||
loop_filter_level: [u8; 4usize],
|
||||
loop_filter_deltas_ref_frame: [i8; 4usize],
|
||||
loop_filter_deltas_mode: [i8; 4usize],
|
||||
prob_skip_false: u8,
|
||||
prob_intra: u8,
|
||||
prob_last: u8,
|
||||
prob_gf: u8,
|
||||
y_mode_probs: [u8; 4usize],
|
||||
uv_mode_probs: [u8; 3usize],
|
||||
mv_probs: [[u8; 19usize]; 2usize],
|
||||
bool_coder_ctx: &BoolCoderContextVPX,
|
||||
) -> Self {
|
||||
let pic_fields = pic_fields.0;
|
||||
let bool_coder_ctx = bool_coder_ctx.0;
|
||||
|
||||
Self(Box::new(bindings::VAPictureParameterBufferVP8 {
|
||||
frame_width,
|
||||
frame_height,
|
||||
last_ref_frame,
|
||||
golden_ref_frame,
|
||||
alt_ref_frame,
|
||||
out_of_loop_frame: bindings::constants::VA_INVALID_SURFACE,
|
||||
pic_fields,
|
||||
mb_segment_tree_probs,
|
||||
loop_filter_level,
|
||||
loop_filter_deltas_ref_frame,
|
||||
loop_filter_deltas_mode,
|
||||
prob_skip_false,
|
||||
prob_intra,
|
||||
prob_last,
|
||||
prob_gf,
|
||||
y_mode_probs,
|
||||
uv_mode_probs,
|
||||
mv_probs,
|
||||
bool_coder_ctx,
|
||||
va_reserved: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn inner_mut(&mut self) -> &mut bindings::VAPictureParameterBufferVP8 {
|
||||
self.0.as_mut()
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&self) -> &bindings::VAPictureParameterBufferVP8 {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the `pic_fields` bindgen field in VAPictureParameterBufferVP9
|
||||
pub struct VP9PicFields(bindings::_VADecPictureParameterBufferVP9__bindgen_ty_1);
|
||||
|
||||
impl VP9PicFields {
|
||||
/// Creates the bindgen field
|
||||
pub fn new(
|
||||
subsampling_x: u32,
|
||||
subsampling_y: u32,
|
||||
frame_type: u32,
|
||||
show_frame: u32,
|
||||
error_resilient_mode: u32,
|
||||
intra_only: u32,
|
||||
allow_high_precision_mv: u32,
|
||||
mcomp_filter_type: u32,
|
||||
frame_parallel_decoding_mode: u32,
|
||||
reset_frame_context: u32,
|
||||
refresh_frame_context: u32,
|
||||
frame_context_idx: u32,
|
||||
segmentation_enabled: u32,
|
||||
segmentation_temporal_update: u32,
|
||||
segmentation_update_map: u32,
|
||||
last_ref_frame: u32,
|
||||
last_ref_frame_sign_bias: u32,
|
||||
golden_ref_frame: u32,
|
||||
golden_ref_frame_sign_bias: u32,
|
||||
alt_ref_frame: u32,
|
||||
alt_ref_frame_sign_bias: u32,
|
||||
lossless_flag: u32,
|
||||
) -> Self {
|
||||
let _bitfield_1 =
|
||||
bindings::_VADecPictureParameterBufferVP9__bindgen_ty_1__bindgen_ty_1::new_bitfield_1(
|
||||
subsampling_x,
|
||||
subsampling_y,
|
||||
frame_type,
|
||||
show_frame,
|
||||
error_resilient_mode,
|
||||
intra_only,
|
||||
allow_high_precision_mv,
|
||||
mcomp_filter_type,
|
||||
frame_parallel_decoding_mode,
|
||||
reset_frame_context,
|
||||
refresh_frame_context,
|
||||
frame_context_idx,
|
||||
segmentation_enabled,
|
||||
segmentation_temporal_update,
|
||||
segmentation_update_map,
|
||||
last_ref_frame,
|
||||
last_ref_frame_sign_bias,
|
||||
golden_ref_frame,
|
||||
golden_ref_frame_sign_bias,
|
||||
alt_ref_frame,
|
||||
alt_ref_frame_sign_bias,
|
||||
lossless_flag,
|
||||
);
|
||||
|
||||
Self(bindings::_VADecPictureParameterBufferVP9__bindgen_ty_1 {
|
||||
bits: bindings::_VADecPictureParameterBufferVP9__bindgen_ty_1__bindgen_ty_1 {
|
||||
_bitfield_align_1: Default::default(),
|
||||
_bitfield_1,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&mut self) -> &bindings::_VADecPictureParameterBufferVP9__bindgen_ty_1 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the PictureParameterBufferVP9 FFI type
|
||||
pub struct PictureParameterBufferVP9(Box<bindings::VADecPictureParameterBufferVP9>);
|
||||
|
||||
impl PictureParameterBufferVP9 {
|
||||
/// Creates the wrapper
|
||||
pub fn new(
|
||||
frame_width: u16,
|
||||
frame_height: u16,
|
||||
reference_frames: [bindings::VASurfaceID; 8],
|
||||
pic_fields: &VP9PicFields,
|
||||
filter_level: u8,
|
||||
sharpness_level: u8,
|
||||
log2_tile_rows: u8,
|
||||
log2_tile_columns: u8,
|
||||
frame_header_length_in_bytes: u8,
|
||||
first_partition_size: u16,
|
||||
mb_segment_tree_probs: [u8; 7usize],
|
||||
segment_pred_probs: [u8; 3usize],
|
||||
profile: u8,
|
||||
bit_depth: u8,
|
||||
) -> Self {
|
||||
let pic_fields = pic_fields.0;
|
||||
|
||||
Self(Box::new(bindings::VADecPictureParameterBufferVP9 {
|
||||
frame_width,
|
||||
frame_height,
|
||||
reference_frames,
|
||||
pic_fields,
|
||||
filter_level,
|
||||
sharpness_level,
|
||||
log2_tile_rows,
|
||||
log2_tile_columns,
|
||||
frame_header_length_in_bytes,
|
||||
first_partition_size,
|
||||
mb_segment_tree_probs,
|
||||
segment_pred_probs,
|
||||
profile,
|
||||
bit_depth,
|
||||
va_reserved: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn inner_mut(&mut self) -> &mut bindings::VADecPictureParameterBufferVP9 {
|
||||
self.0.as_mut()
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&self) -> &bindings::VADecPictureParameterBufferVP9 {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the VAPictureH264 FFI type
|
||||
pub struct PictureH264(bindings::VAPictureH264);
|
||||
|
||||
impl PictureH264 {
|
||||
/// Creates the wrapper
|
||||
pub fn new(
|
||||
picture_id: bindings::VASurfaceID,
|
||||
frame_idx: u32,
|
||||
flags: u32,
|
||||
top_field_order_cnt: i32,
|
||||
bottom_field_order_cnt: i32,
|
||||
) -> Self {
|
||||
Self(bindings::VAPictureH264 {
|
||||
picture_id,
|
||||
frame_idx,
|
||||
flags,
|
||||
TopFieldOrderCnt: top_field_order_cnt,
|
||||
BottomFieldOrderCnt: bottom_field_order_cnt,
|
||||
va_reserved: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the `seq_fields` bindgen field in VAPictureParameterBufferH264
|
||||
pub struct H264SeqFields(bindings::_VAPictureParameterBufferH264__bindgen_ty_1);
|
||||
|
||||
impl H264SeqFields {
|
||||
/// Creates the bindgen field
|
||||
pub fn new(
|
||||
chroma_format_idc: u32,
|
||||
residual_colour_transform_flag: u32,
|
||||
gaps_in_frame_num_value_allowed_flag: u32,
|
||||
frame_mbs_only_flag: u32,
|
||||
mb_adaptive_frame_field_flag: u32,
|
||||
direct_8x8_inference_flag: u32,
|
||||
min_luma_bi_pred_size8x8: u32,
|
||||
log2_max_frame_num_minus4: u32,
|
||||
pic_order_cnt_type: u32,
|
||||
log2_max_pic_order_cnt_lsb_minus4: u32,
|
||||
delta_pic_order_always_zero_flag: u32,
|
||||
) -> Self {
|
||||
let _bitfield_1 =
|
||||
bindings::_VAPictureParameterBufferH264__bindgen_ty_1__bindgen_ty_1::new_bitfield_1(
|
||||
chroma_format_idc,
|
||||
residual_colour_transform_flag,
|
||||
gaps_in_frame_num_value_allowed_flag,
|
||||
frame_mbs_only_flag,
|
||||
mb_adaptive_frame_field_flag,
|
||||
direct_8x8_inference_flag,
|
||||
min_luma_bi_pred_size8x8,
|
||||
log2_max_frame_num_minus4,
|
||||
pic_order_cnt_type,
|
||||
log2_max_pic_order_cnt_lsb_minus4,
|
||||
delta_pic_order_always_zero_flag,
|
||||
);
|
||||
|
||||
Self(bindings::_VAPictureParameterBufferH264__bindgen_ty_1 {
|
||||
bits: bindings::_VAPictureParameterBufferH264__bindgen_ty_1__bindgen_ty_1 {
|
||||
_bitfield_align_1: Default::default(),
|
||||
_bitfield_1,
|
||||
__bindgen_padding_0: Default::default(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&mut self) -> &bindings::_VAPictureParameterBufferH264__bindgen_ty_1 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the `pic_fields` bindgen field in VAPictureParameterBufferH264
|
||||
pub struct H264PicFields(bindings::_VAPictureParameterBufferH264__bindgen_ty_2);
|
||||
|
||||
impl H264PicFields {
|
||||
/// Creates the bindgen field
|
||||
pub fn new(
|
||||
entropy_coding_mode_flag: u32,
|
||||
weighted_pred_flag: u32,
|
||||
weighted_bipred_idc: u32,
|
||||
transform_8x8_mode_flag: u32,
|
||||
field_pic_flag: u32,
|
||||
constrained_intra_pred_flag: u32,
|
||||
pic_order_present_flag: u32,
|
||||
deblocking_filter_control_present_flag: u32,
|
||||
redundant_pic_cnt_present_flag: u32,
|
||||
reference_pic_flag: u32,
|
||||
) -> Self {
|
||||
let _bitfield_1 =
|
||||
bindings::_VAPictureParameterBufferH264__bindgen_ty_2__bindgen_ty_1::new_bitfield_1(
|
||||
entropy_coding_mode_flag,
|
||||
weighted_pred_flag,
|
||||
weighted_bipred_idc,
|
||||
transform_8x8_mode_flag,
|
||||
field_pic_flag,
|
||||
constrained_intra_pred_flag,
|
||||
pic_order_present_flag,
|
||||
deblocking_filter_control_present_flag,
|
||||
redundant_pic_cnt_present_flag,
|
||||
reference_pic_flag,
|
||||
);
|
||||
|
||||
Self(bindings::_VAPictureParameterBufferH264__bindgen_ty_2 {
|
||||
bits: bindings::_VAPictureParameterBufferH264__bindgen_ty_2__bindgen_ty_1 {
|
||||
_bitfield_align_1: Default::default(),
|
||||
_bitfield_1,
|
||||
__bindgen_padding_0: Default::default(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&mut self) -> &bindings::_VAPictureParameterBufferH264__bindgen_ty_2 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper over VAPictureParameterBufferH264 FFI type
|
||||
pub struct PictureParameterBufferH264(Box<bindings::VAPictureParameterBufferH264>);
|
||||
|
||||
impl PictureParameterBufferH264 {
|
||||
/// Creates the wrapper
|
||||
pub fn new(
|
||||
curr_pic: PictureH264,
|
||||
reference_frames: [PictureH264; 16],
|
||||
picture_width_in_mbs_minus1: u16,
|
||||
picture_height_in_mbs_minus1: u16,
|
||||
bit_depth_luma_minus8: u8,
|
||||
bit_depth_chroma_minus8: u8,
|
||||
num_ref_frames: u8,
|
||||
seq_fields: &H264SeqFields,
|
||||
num_slice_groups_minus1: u8,
|
||||
slice_group_map_type: u8,
|
||||
slice_group_change_rate_minus1: u16,
|
||||
pic_init_qp_minus26: i8,
|
||||
pic_init_qs_minus26: i8,
|
||||
chroma_qp_index_offset: i8,
|
||||
second_chroma_qp_index_offset: i8,
|
||||
pic_fields: &H264PicFields,
|
||||
frame_num: u16,
|
||||
) -> Self {
|
||||
let reference_frames = (0..16usize)
|
||||
.map(|i| reference_frames[i].0)
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
// try_into is guaranteed to work because the iterator and target array have the same
|
||||
// size.
|
||||
.unwrap();
|
||||
|
||||
let seq_fields = seq_fields.0;
|
||||
let pic_fields = pic_fields.0;
|
||||
|
||||
Self(Box::new(bindings::VAPictureParameterBufferH264 {
|
||||
CurrPic: curr_pic.0,
|
||||
ReferenceFrames: reference_frames,
|
||||
picture_width_in_mbs_minus1,
|
||||
picture_height_in_mbs_minus1,
|
||||
bit_depth_luma_minus8,
|
||||
bit_depth_chroma_minus8,
|
||||
num_ref_frames,
|
||||
seq_fields,
|
||||
num_slice_groups_minus1,
|
||||
slice_group_map_type,
|
||||
slice_group_change_rate_minus1,
|
||||
pic_init_qp_minus26,
|
||||
pic_init_qs_minus26,
|
||||
chroma_qp_index_offset,
|
||||
second_chroma_qp_index_offset,
|
||||
pic_fields,
|
||||
frame_num,
|
||||
va_reserved: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn inner_mut(&mut self) -> &mut bindings::VAPictureParameterBufferH264 {
|
||||
self.0.as_mut()
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&self) -> &bindings::VAPictureParameterBufferH264 {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// An abstraction over the PictureParameterBuffer types we support
|
||||
pub enum PictureParameter {
|
||||
/// A wrapper over VAPictureParameterBufferMPEG2
|
||||
MPEG2(PictureParameterBufferMPEG2),
|
||||
/// A wrapper over VAPictureParameterBufferVP8
|
||||
VP8(PictureParameterBufferVP8),
|
||||
/// A wrapper over VAPictureParameterBufferVP9
|
||||
VP9(PictureParameterBufferVP9),
|
||||
/// A wrapper over VAPictureParameterBufferH264
|
||||
H264(PictureParameterBufferH264),
|
||||
}
|
||||
|
||||
/// Wrapper over the VASliceParameterBufferMPEG2 FFI type
|
||||
pub struct SliceParameterBufferMPEG2(Box<bindings::VASliceParameterBufferMPEG2>);
|
||||
|
||||
impl SliceParameterBufferMPEG2 {
|
||||
/// Creates the wrapper
|
||||
pub fn new(
|
||||
slice_data_size: u32,
|
||||
slice_data_offset: u32,
|
||||
slice_data_flag: u32,
|
||||
macroblock_offset: u32,
|
||||
slice_horizontal_position: u32,
|
||||
slice_vertical_position: u32,
|
||||
quantiser_scale_code: i32,
|
||||
intra_slice_flag: i32,
|
||||
) -> Self {
|
||||
Self(Box::new(bindings::VASliceParameterBufferMPEG2 {
|
||||
slice_data_size,
|
||||
slice_data_offset,
|
||||
slice_data_flag,
|
||||
macroblock_offset,
|
||||
slice_horizontal_position,
|
||||
slice_vertical_position,
|
||||
quantiser_scale_code,
|
||||
intra_slice_flag,
|
||||
va_reserved: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn inner_mut(&mut self) -> &mut bindings::VASliceParameterBufferMPEG2 {
|
||||
self.0.as_mut()
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&self) -> &bindings::VASliceParameterBufferMPEG2 {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// An abstraction over the SliceParameterBuffer types we support
|
||||
pub enum SliceParameter {
|
||||
/// A wrapper over VASliceParameterBufferMPEG2
|
||||
MPEG2(SliceParameterBufferMPEG2),
|
||||
/// A wrapper over VASliceParameterBufferVP8
|
||||
VP8(SliceParameterBufferVP8),
|
||||
/// A wrapper over VASliceParameterBufferVP9
|
||||
VP9(SliceParameterBufferVP9),
|
||||
/// A wrapper over VASliceParameterBufferH264
|
||||
H264(SliceParameterBufferH264),
|
||||
}
|
||||
|
||||
/// Wrapper over the VASliceParameterBufferVP8 FFI type
|
||||
pub struct SliceParameterBufferVP8(Box<bindings::VASliceParameterBufferVP8>);
|
||||
|
||||
impl SliceParameterBufferVP8 {
|
||||
/// Creates the wrapper
|
||||
pub fn new(
|
||||
slice_data_size: u32,
|
||||
slice_data_offset: u32,
|
||||
slice_data_flag: u32,
|
||||
macroblock_offset: u32,
|
||||
num_of_partitions: u8,
|
||||
partition_size: [u32; 9usize],
|
||||
) -> Self {
|
||||
Self(Box::new(bindings::VASliceParameterBufferVP8 {
|
||||
slice_data_size,
|
||||
slice_data_offset,
|
||||
slice_data_flag,
|
||||
macroblock_offset,
|
||||
num_of_partitions,
|
||||
partition_size,
|
||||
va_reserved: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn inner_mut(&mut self) -> &mut bindings::VASliceParameterBufferVP8 {
|
||||
self.0.as_mut()
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&self) -> &bindings::VASliceParameterBufferVP8 {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the `segment_flags` bindgen field in VASegmentParameterVP9
|
||||
pub struct VP9SegmentFlags(bindings::_VASegmentParameterVP9__bindgen_ty_1);
|
||||
|
||||
impl VP9SegmentFlags {
|
||||
/// Creates the wrapper
|
||||
pub fn new(
|
||||
segment_reference_enabled: u16,
|
||||
segment_reference: u16,
|
||||
segment_reference_skipped: u16,
|
||||
) -> Self {
|
||||
let _bitfield_1 =
|
||||
bindings::_VASegmentParameterVP9__bindgen_ty_1__bindgen_ty_1::new_bitfield_1(
|
||||
segment_reference_enabled,
|
||||
segment_reference,
|
||||
segment_reference_skipped,
|
||||
);
|
||||
|
||||
Self(bindings::_VASegmentParameterVP9__bindgen_ty_1 {
|
||||
fields: bindings::_VASegmentParameterVP9__bindgen_ty_1__bindgen_ty_1 {
|
||||
_bitfield_align_1: Default::default(),
|
||||
_bitfield_1,
|
||||
__bindgen_padding_0: Default::default(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&mut self) -> &bindings::_VASegmentParameterVP9__bindgen_ty_1 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the VASegmentParameterVP9 FFI type
|
||||
pub struct SegmentParameterVP9(bindings::VASegmentParameterVP9);
|
||||
|
||||
impl SegmentParameterVP9 {
|
||||
/// Creates the wrapper
|
||||
pub fn new(
|
||||
segment_flags: &VP9SegmentFlags,
|
||||
filter_level: [[u8; 2usize]; 4usize],
|
||||
luma_ac_quant_scale: i16,
|
||||
luma_dc_quant_scale: i16,
|
||||
chroma_ac_quant_scale: i16,
|
||||
chroma_dc_quant_scale: i16,
|
||||
) -> Self {
|
||||
let segment_flags = segment_flags.0;
|
||||
|
||||
Self(bindings::VASegmentParameterVP9 {
|
||||
segment_flags,
|
||||
filter_level,
|
||||
luma_ac_quant_scale,
|
||||
luma_dc_quant_scale,
|
||||
chroma_ac_quant_scale,
|
||||
chroma_dc_quant_scale,
|
||||
va_reserved: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the VASliceParameterBufferVP9 FFI type
|
||||
pub struct SliceParameterBufferVP9(Box<bindings::VASliceParameterBufferVP9>);
|
||||
|
||||
impl SliceParameterBufferVP9 {
|
||||
/// Creates the wrapper
|
||||
pub fn new(
|
||||
slice_data_size: u32,
|
||||
slice_data_offset: u32,
|
||||
slice_data_flag: u32,
|
||||
seg_param: [&SegmentParameterVP9; 8usize],
|
||||
) -> Self {
|
||||
let seg_param = seg_param.map(|param| param.0);
|
||||
|
||||
Self(Box::new(bindings::VASliceParameterBufferVP9 {
|
||||
slice_data_size,
|
||||
slice_data_offset,
|
||||
slice_data_flag,
|
||||
seg_param,
|
||||
va_reserved: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn inner_mut(&mut self) -> &mut bindings::VASliceParameterBufferVP9 {
|
||||
self.0.as_mut()
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&self) -> &bindings::VASliceParameterBufferVP9 {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the VASliceParameterBufferH264 FFI type
|
||||
pub struct SliceParameterBufferH264(Box<bindings::VASliceParameterBufferH264>);
|
||||
|
||||
impl SliceParameterBufferH264 {
|
||||
/// Creates the wrapper
|
||||
pub fn new(
|
||||
slice_data_size: u32,
|
||||
slice_data_offset: u32,
|
||||
slice_data_flag: u32,
|
||||
slice_data_bit_offset: u16,
|
||||
first_mb_in_slice: u16,
|
||||
slice_type: u8,
|
||||
direct_spatial_mv_pred_flag: u8,
|
||||
num_ref_idx_l0_active_minus1: u8,
|
||||
num_ref_idx_l1_active_minus1: u8,
|
||||
cabac_init_idc: u8,
|
||||
slice_qp_delta: i8,
|
||||
disable_deblocking_filter_idc: u8,
|
||||
slice_alpha_c0_offset_div2: i8,
|
||||
slice_beta_offset_div2: i8,
|
||||
ref_pic_list_0: [&PictureH264; 32usize],
|
||||
ref_pic_list_1: [&PictureH264; 32usize],
|
||||
luma_log2_weight_denom: u8,
|
||||
chroma_log2_weight_denom: u8,
|
||||
luma_weight_l0_flag: u8,
|
||||
luma_weight_l0: [i16; 32usize],
|
||||
luma_offset_l0: [i16; 32usize],
|
||||
chroma_weight_l0_flag: u8,
|
||||
chroma_weight_l0: [[i16; 2usize]; 32usize],
|
||||
chroma_offset_l0: [[i16; 2usize]; 32usize],
|
||||
luma_weight_l1_flag: u8,
|
||||
luma_weight_l1: [i16; 32usize],
|
||||
luma_offset_l1: [i16; 32usize],
|
||||
chroma_weight_l1_flag: u8,
|
||||
chroma_weight_l1: [[i16; 2usize]; 32usize],
|
||||
chroma_offset_l1: [[i16; 2usize]; 32usize],
|
||||
) -> Self {
|
||||
let ref_pic_list_0 = ref_pic_list_0.map(|pic| pic.0);
|
||||
let ref_pic_list_1 = ref_pic_list_1.map(|pic| pic.0);
|
||||
|
||||
Self(Box::new(bindings::VASliceParameterBufferH264 {
|
||||
slice_data_size,
|
||||
slice_data_offset,
|
||||
slice_data_flag,
|
||||
slice_data_bit_offset,
|
||||
first_mb_in_slice,
|
||||
slice_type,
|
||||
direct_spatial_mv_pred_flag,
|
||||
num_ref_idx_l0_active_minus1,
|
||||
num_ref_idx_l1_active_minus1,
|
||||
cabac_init_idc,
|
||||
slice_qp_delta,
|
||||
disable_deblocking_filter_idc,
|
||||
slice_alpha_c0_offset_div2,
|
||||
slice_beta_offset_div2,
|
||||
RefPicList0: ref_pic_list_0,
|
||||
RefPicList1: ref_pic_list_1,
|
||||
luma_log2_weight_denom,
|
||||
chroma_log2_weight_denom,
|
||||
luma_weight_l0_flag,
|
||||
luma_weight_l0,
|
||||
luma_offset_l0,
|
||||
chroma_weight_l0_flag,
|
||||
chroma_weight_l0,
|
||||
chroma_offset_l0,
|
||||
luma_weight_l1_flag,
|
||||
luma_weight_l1,
|
||||
luma_offset_l1,
|
||||
chroma_weight_l1_flag,
|
||||
chroma_weight_l1,
|
||||
chroma_offset_l1,
|
||||
va_reserved: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn inner_mut(&mut self) -> &mut bindings::VASliceParameterBufferH264 {
|
||||
self.0.as_mut()
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&self) -> &bindings::VASliceParameterBufferH264 {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the VAIQMatrixBufferMPEG2 FFI type
|
||||
pub struct IQMatrixBufferMPEG2(Box<bindings::VAIQMatrixBufferMPEG2>);
|
||||
|
||||
impl IQMatrixBufferMPEG2 {
|
||||
/// Creates the wrapper
|
||||
pub fn new(
|
||||
load_intra_quantiser_matrix: i32,
|
||||
load_non_intra_quantiser_matrix: i32,
|
||||
load_chroma_intra_quantiser_matrix: i32,
|
||||
load_chroma_non_intra_quantiser_matrix: i32,
|
||||
intra_quantiser_matrix: [u8; 64usize],
|
||||
non_intra_quantiser_matrix: [u8; 64usize],
|
||||
chroma_intra_quantiser_matrix: [u8; 64usize],
|
||||
chroma_non_intra_quantiser_matrix: [u8; 64usize],
|
||||
) -> Self {
|
||||
Self(Box::new(bindings::VAIQMatrixBufferMPEG2 {
|
||||
load_intra_quantiser_matrix,
|
||||
load_non_intra_quantiser_matrix,
|
||||
load_chroma_intra_quantiser_matrix,
|
||||
load_chroma_non_intra_quantiser_matrix,
|
||||
intra_quantiser_matrix,
|
||||
non_intra_quantiser_matrix,
|
||||
chroma_intra_quantiser_matrix,
|
||||
chroma_non_intra_quantiser_matrix,
|
||||
va_reserved: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn inner_mut(&mut self) -> &mut bindings::VAIQMatrixBufferMPEG2 {
|
||||
self.0.as_mut()
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&self) -> &bindings::VAIQMatrixBufferMPEG2 {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the VAIQMatrixBufferVP8 FFI type
|
||||
pub struct IQMatrixBufferVP8(Box<bindings::VAIQMatrixBufferVP8>);
|
||||
|
||||
impl IQMatrixBufferVP8 {
|
||||
/// Creates the wrapper
|
||||
pub fn new(quantization_index: [[u16; 6usize]; 4usize]) -> Self {
|
||||
Self(Box::new(bindings::VAIQMatrixBufferVP8 {
|
||||
quantization_index,
|
||||
va_reserved: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn inner_mut(&mut self) -> &mut bindings::VAIQMatrixBufferVP8 {
|
||||
self.0.as_mut()
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&self) -> &bindings::VAIQMatrixBufferVP8 {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper over the VAIQMatrixBufferH264 FFI type
|
||||
pub struct IQMatrixBufferH264(Box<bindings::VAIQMatrixBufferH264>);
|
||||
|
||||
impl IQMatrixBufferH264 {
|
||||
/// Creates the wrapper
|
||||
pub fn new(
|
||||
scaling_list4x4: [[u8; 16usize]; 6usize],
|
||||
scaling_list8x8: [[u8; 64usize]; 2usize],
|
||||
) -> Self {
|
||||
Self(Box::new(bindings::VAIQMatrixBufferH264 {
|
||||
ScalingList4x4: scaling_list4x4,
|
||||
ScalingList8x8: scaling_list8x8,
|
||||
va_reserved: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn inner_mut(&mut self) -> &mut bindings::VAIQMatrixBufferH264 {
|
||||
self.0.as_mut()
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&self) -> &bindings::VAIQMatrixBufferH264 {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// An abstraction over the IQMatrixBuffer types we support
|
||||
pub enum IQMatrix {
|
||||
/// An abstraction over VAIQMatrixBufferMPEG2
|
||||
MPEG2(IQMatrixBufferMPEG2),
|
||||
/// An abstraction over VAIQMatrixBufferVP8
|
||||
VP8(IQMatrixBufferVP8),
|
||||
/// An abstraction over VAIQMatrixBufferH264
|
||||
H264(IQMatrixBufferH264),
|
||||
}
|
||||
|
||||
/// Wrapper over the VAProbabilityDataBufferVP8 FFI type
|
||||
pub struct ProbabilityDataBufferVP8(Box<bindings::VAProbabilityDataBufferVP8>);
|
||||
|
||||
impl ProbabilityDataBufferVP8 {
|
||||
/// Creates the wrapper
|
||||
pub fn new(dct_coeff_probs: [[[[u8; 11usize]; 3usize]; 8usize]; 4usize]) -> Self {
|
||||
Self(Box::new(bindings::VAProbabilityDataBufferVP8 {
|
||||
dct_coeff_probs,
|
||||
va_reserved: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn inner_mut(&mut self) -> &mut bindings::VAProbabilityDataBufferVP8 {
|
||||
self.0.as_mut()
|
||||
}
|
||||
|
||||
/// Returns the inner FFI type. Useful for testing purposes.
|
||||
pub fn inner(&self) -> &bindings::VAProbabilityDataBufferVP8 {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
129
media/libva/src/config.rs
Normal file
129
media/libva/src/config.rs
Normal file
|
@ -0,0 +1,129 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use anyhow::Result;
|
||||
use base::error;
|
||||
|
||||
use crate::{bindings, display::Display, generic_value::GenericValue, status::Status};
|
||||
|
||||
/// An owned VAConfig that is tied to the lifetime of a particular VADisplay
|
||||
pub struct Config {
|
||||
display: Rc<Display>,
|
||||
id: bindings::VAConfigID,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Create a VAConfig by wrapping around the vaCreateConfig call. `attrs`
|
||||
/// describe the attributes to set for this config. A list of the supported
|
||||
/// attributes for a given profile/entrypoint pair can be retrieved using
|
||||
/// Display::get_config_attributes. Other attributes will take their default
|
||||
/// values
|
||||
pub(crate) fn new(
|
||||
display: Rc<Display>,
|
||||
attrs: Option<Vec<bindings::VAConfigAttrib>>,
|
||||
profile: bindings::VAProfile::Type,
|
||||
entrypoint: bindings::VAEntrypoint::Type,
|
||||
) -> Result<Self> {
|
||||
let mut config_id = 0u32;
|
||||
let mut attrs = attrs.unwrap_or_default();
|
||||
|
||||
// Safe because `self` represents a valid VADisplay The "attrs" vectors
|
||||
// is properly initialized and a valid size is passed to the C function,
|
||||
// so it is impossible to write past the end of the vector's storage by
|
||||
// mistake
|
||||
Status(unsafe {
|
||||
bindings::vaCreateConfig(
|
||||
display.handle(),
|
||||
profile,
|
||||
entrypoint,
|
||||
attrs.as_mut_ptr(),
|
||||
attrs.len() as i32,
|
||||
&mut config_id,
|
||||
)
|
||||
})
|
||||
.check()?;
|
||||
|
||||
Ok(Self {
|
||||
display,
|
||||
id: config_id,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the associated VAConfigID
|
||||
pub(crate) fn id(&self) -> bindings::VAConfigID {
|
||||
self.id
|
||||
}
|
||||
|
||||
// Queries surface attributes for the supplied config. This function
|
||||
// queries for all supported attributes for the supplied VA config. In
|
||||
// particular, if the underlying hardware supports the creation of VA
|
||||
// surfaces in various formats, then this function will enumerate all pixel
|
||||
// formats that are supported.
|
||||
fn query_surface_attributes(&mut self) -> Result<Vec<bindings::VASurfaceAttrib>> {
|
||||
// Safe because `self` represents a valid VAConfig. We first query how
|
||||
// much space is needed by the C API by passing in NULL in the first
|
||||
// call to `vaQuerySurfaceAttributes`.
|
||||
let attrs_len: std::os::raw::c_uint = 0;
|
||||
Status(unsafe {
|
||||
bindings::vaQuerySurfaceAttributes(
|
||||
self.display.handle(),
|
||||
self.id,
|
||||
std::ptr::null_mut(),
|
||||
&attrs_len as *const _ as *mut std::os::raw::c_uint,
|
||||
)
|
||||
})
|
||||
.check()?;
|
||||
|
||||
let mut attrs = Vec::with_capacity(attrs_len as usize);
|
||||
// Safe because we allocate a vector with the required capacity as
|
||||
// returned by the initial call to vaQuerySurfaceAttributes. We then
|
||||
// pass a valid pointer to it.
|
||||
Status(unsafe {
|
||||
bindings::vaQuerySurfaceAttributes(
|
||||
self.display.handle(),
|
||||
self.id,
|
||||
attrs.as_mut_ptr(),
|
||||
&attrs_len as *const _ as *mut std::os::raw::c_uint,
|
||||
)
|
||||
})
|
||||
.check()?;
|
||||
|
||||
// Safe because vaQuerySurfaceAttributes will have written to
|
||||
// exactly attrs_len entries in the vector.
|
||||
unsafe {
|
||||
attrs.set_len(attrs_len as usize);
|
||||
}
|
||||
|
||||
Ok(attrs)
|
||||
}
|
||||
|
||||
/// Query the surface attribute of type `attr_type`. The attribute may or
|
||||
/// may not be defined by the driver.
|
||||
pub fn query_surface_attribute(
|
||||
&mut self,
|
||||
attr_type: bindings::VASurfaceAttribType::Type,
|
||||
) -> Result<Option<GenericValue>> {
|
||||
let surface_attributes = self.query_surface_attributes()?;
|
||||
|
||||
surface_attributes
|
||||
.into_iter()
|
||||
.find(|attr| attr.type_ == attr_type)
|
||||
.map_or(Ok(None), |attrib| {
|
||||
Ok(Some(GenericValue::try_from(attrib.value)?))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Config {
|
||||
fn drop(&mut self) {
|
||||
// Safe because `self` represents a valid Config.
|
||||
let status =
|
||||
Status(unsafe { bindings::vaDestroyConfig(self.display.handle(), self.id) }).check();
|
||||
if status.is_err() {
|
||||
error!("vaDestroyConfig failed: {}", status.unwrap_err());
|
||||
}
|
||||
}
|
||||
}
|
97
media/libva/src/context.rs
Normal file
97
media/libva/src/context.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use anyhow::Result;
|
||||
use base::error;
|
||||
|
||||
use crate::{
|
||||
bindings, buffer::Buffer, buffer_type::BufferType, display::Display, status::Status, Config,
|
||||
Surface,
|
||||
};
|
||||
|
||||
/// An owned Context that is tied to the lifetime of a particular Display
|
||||
pub struct Context {
|
||||
display: Rc<Display>,
|
||||
id: bindings::VAContextID,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Create a Context by wrapping around a vaCreateContext call.
|
||||
/// `config` is the configuration for the context
|
||||
/// `coded_width` is the coded picture width
|
||||
/// `coded_height` is the coded picture height
|
||||
/// `progressive` is whether only progressive frame pictures are present in the sequence
|
||||
/// `surfaces` are a hint for the amount of surfaces tied to the context
|
||||
pub(crate) fn new(
|
||||
display: Rc<Display>,
|
||||
config: &Config,
|
||||
coded_width: i32,
|
||||
coded_height: i32,
|
||||
surfaces: Option<&Vec<Surface>>,
|
||||
progressive: bool,
|
||||
) -> Result<Self> {
|
||||
let mut context_id = 0;
|
||||
let flags = if progressive {
|
||||
bindings::constants::VA_PROGRESSIVE as i32
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let mut render_targets = match surfaces {
|
||||
Some(surfaces) => Surface::as_id_vec(surfaces),
|
||||
None => Default::default(),
|
||||
};
|
||||
|
||||
// Safe because `self` represents a valid VADisplay and render_targets
|
||||
// and ntargets are properly initialized. Note that render_targets==NULL
|
||||
// is valid so long as ntargets==0.
|
||||
Status(unsafe {
|
||||
bindings::vaCreateContext(
|
||||
display.handle(),
|
||||
config.id(),
|
||||
coded_width,
|
||||
coded_height,
|
||||
flags,
|
||||
render_targets.as_mut_ptr(),
|
||||
render_targets.len() as i32,
|
||||
&mut context_id,
|
||||
)
|
||||
})
|
||||
.check()?;
|
||||
|
||||
Ok(Self {
|
||||
display,
|
||||
id: context_id,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the inner VADisplay
|
||||
pub fn display(&self) -> Rc<Display> {
|
||||
Rc::clone(&self.display)
|
||||
}
|
||||
|
||||
/// Returns the VAContextID for this Context
|
||||
pub(crate) fn id(&self) -> bindings::VAContextID {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Create a buffer by wrapping a vaCreateBuffer call. `type_` describes the
|
||||
/// underlying data to libva.
|
||||
pub fn create_buffer(self: &Rc<Self>, type_: BufferType) -> Result<Buffer> {
|
||||
Buffer::new(Rc::clone(self), type_)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Context {
|
||||
fn drop(&mut self) {
|
||||
// Safe because `self` represents a valid VAContext.
|
||||
let status =
|
||||
Status(unsafe { bindings::vaDestroyContext(self.display.handle(), self.id) }).check();
|
||||
if status.is_err() {
|
||||
error!("vaDestroyContext failed: {}", status.unwrap_err());
|
||||
}
|
||||
}
|
||||
}
|
299
media/libva/src/display.rs
Normal file
299
media/libva/src/display.rs
Normal file
|
@ -0,0 +1,299 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::{ffi::CStr, fs::File, rc::Rc};
|
||||
|
||||
use anyhow::Context as AnyhowContext;
|
||||
use anyhow::{anyhow, Result};
|
||||
use base::AsRawDescriptor;
|
||||
|
||||
use crate::{
|
||||
bindings, config::Config, context::Context, status::Status, surface::Surface, UsageHint,
|
||||
};
|
||||
|
||||
/// An owned VADisplay
|
||||
pub struct Display {
|
||||
/// The handle to interact with the underlying VADisplay.
|
||||
handle: bindings::VADisplay,
|
||||
/// The DRM file that must be kept open while the VADisplay is in use.
|
||||
#[allow(dead_code)]
|
||||
drm_file: File,
|
||||
}
|
||||
|
||||
impl Display {
|
||||
/// Opens and initializes an owned Display
|
||||
pub fn open() -> Result<Self> {
|
||||
let (display, drm_file) = match Display::drm_open()? {
|
||||
Some(x) => x,
|
||||
None => return Err(anyhow!("Couldn't open a suitable DRM file descriptor")),
|
||||
};
|
||||
|
||||
let mut major = 0i32;
|
||||
let mut minor = 0i32;
|
||||
// Safe because we ensure that the display is valid (i.e not NULL)
|
||||
// before calling vaInitialize
|
||||
let result =
|
||||
Status(unsafe { bindings::vaInitialize(display, &mut major, &mut minor) }).check();
|
||||
|
||||
if let Err(error) = result {
|
||||
// The File will close the DRM fd on drop.
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
handle: display,
|
||||
drm_file,
|
||||
})
|
||||
}
|
||||
|
||||
fn drm_open() -> Result<Option<(bindings::VADisplay, File)>> {
|
||||
let udev_context = libudev::Context::new()?;
|
||||
let mut enumerator = libudev::Enumerator::new(&udev_context)?;
|
||||
|
||||
enumerator
|
||||
.match_subsystem("drm")
|
||||
.context("udev error when matching DRM devices")?;
|
||||
|
||||
for device in enumerator.scan_devices()? {
|
||||
let path = device
|
||||
.devnode()
|
||||
.and_then(|f| f.file_name())
|
||||
.and_then(|f| f.to_str());
|
||||
|
||||
match path {
|
||||
Some(name) => {
|
||||
if !name.contains("renderD") {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
None => continue,
|
||||
}
|
||||
|
||||
let file = std::fs::File::open(device.devnode().unwrap())?;
|
||||
let fd = file.as_raw_descriptor();
|
||||
|
||||
// Safe because fd represents a valid file descriptor and
|
||||
// the pointer is checked for NULL afterwards.
|
||||
let display = unsafe { bindings::vaGetDisplayDRM(fd) };
|
||||
|
||||
if display.is_null() {
|
||||
// The File will close the DRM fd on drop.
|
||||
return Err(anyhow!("va_open_display() failed"));
|
||||
}
|
||||
|
||||
return Ok(Some((display, file)));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Returns the associated handle
|
||||
pub(crate) fn handle(&self) -> bindings::VADisplay {
|
||||
self.handle
|
||||
}
|
||||
|
||||
/// Queries supported profiles
|
||||
pub fn query_config_profiles(&self) -> Result<Vec<bindings::VAProfile::Type>> {
|
||||
// Safe because `self` represents a valid VADisplay.
|
||||
let mut max_num_profiles = unsafe { bindings::vaMaxNumProfiles(self.handle) };
|
||||
let mut profiles = Vec::with_capacity(max_num_profiles as usize);
|
||||
|
||||
// Safe because `self` represents a valid VADisplay and the vector has
|
||||
// "max_num_profiles" as capacity.
|
||||
Status(unsafe {
|
||||
bindings::vaQueryConfigProfiles(
|
||||
self.handle,
|
||||
profiles.as_mut_ptr(),
|
||||
&mut max_num_profiles,
|
||||
)
|
||||
})
|
||||
.check()?;
|
||||
|
||||
// Safe because "profiles" is allocated with a "max_num_profiles"
|
||||
// capacity. Additionally, vaQueryConfigProfiles will write to
|
||||
// "max_num_entrypoints" entries in the vector.
|
||||
unsafe {
|
||||
profiles.set_len(max_num_profiles as usize);
|
||||
};
|
||||
|
||||
Ok(profiles)
|
||||
}
|
||||
|
||||
/// Returns a String describing some aspects of the VA implemenation on a
|
||||
/// specific hardware accelerator. The format of the returned string is
|
||||
/// vendor specific and at the discretion of the implementer. e.g. for the
|
||||
/// Intel GMA500 implementation, an example would be: "Intel GMA500 -
|
||||
/// 2.0.0.32L.0005"
|
||||
pub fn query_vendor_string(&self) -> std::result::Result<String, &'static str> {
|
||||
// Safe because `self` represents a valid VADisplay.
|
||||
let vendor_string = unsafe { bindings::vaQueryVendorString(self.handle) };
|
||||
|
||||
if vendor_string.is_null() {
|
||||
return Err("vaQueryVendorString() returned NULL");
|
||||
}
|
||||
|
||||
// Safe because we check the whether the vendor_String pointer is NULL
|
||||
Ok(unsafe { CStr::from_ptr(vendor_string) }
|
||||
.to_string_lossy()
|
||||
.to_string())
|
||||
}
|
||||
|
||||
/// Query supported entrypoints for a given profile
|
||||
pub fn query_config_entrypoints(
|
||||
&self,
|
||||
profile: bindings::VAProfile::Type,
|
||||
) -> Result<Vec<bindings::VAEntrypoint::Type>> {
|
||||
// Safe because `self` represents a valid VADisplay.
|
||||
let mut max_num_entrypoints = unsafe { bindings::vaMaxNumEntrypoints(self.handle) };
|
||||
let mut entrypoints = Vec::with_capacity(max_num_entrypoints as usize);
|
||||
|
||||
// Safe because `self` represents a valid VADisplay and the vector has
|
||||
// "max_num_entrypoints" as capacity.
|
||||
Status(unsafe {
|
||||
bindings::vaQueryConfigEntrypoints(
|
||||
self.handle,
|
||||
profile,
|
||||
entrypoints.as_mut_ptr(),
|
||||
&mut max_num_entrypoints,
|
||||
)
|
||||
})
|
||||
.check()?;
|
||||
|
||||
// Safe because "entrypoints" is allocated with a
|
||||
// "max_num_entrypoints" capacity. Safe because
|
||||
// vaQueryConfigEntrypoints will write to "max_num_entrypoints"
|
||||
// entries in the vector.
|
||||
unsafe {
|
||||
entrypoints.set_len(max_num_entrypoints as usize);
|
||||
}
|
||||
|
||||
Ok(entrypoints)
|
||||
}
|
||||
|
||||
/// Get attributes for a given profile/entrypoint pair
|
||||
pub fn get_config_attributes(
|
||||
&self,
|
||||
profile: bindings::VAProfile::Type,
|
||||
entrypoint: bindings::VAEntrypoint::Type,
|
||||
attributes: &mut Vec<bindings::VAConfigAttrib>,
|
||||
) -> Result<()> {
|
||||
// Safe because `self` represents a valid VADisplay. The vector length
|
||||
// is passed to the C function, so it is impossible to write past the
|
||||
// end of the vector's storage by mistake.
|
||||
Status(unsafe {
|
||||
bindings::vaGetConfigAttributes(
|
||||
self.handle,
|
||||
profile,
|
||||
entrypoint,
|
||||
attributes.as_mut_ptr(),
|
||||
attributes.len() as i32,
|
||||
)
|
||||
})
|
||||
.check()
|
||||
}
|
||||
|
||||
/// Create VASurfaces by wrapping around a vaCreateSurfaces call
|
||||
/// `rt_format` is the desired surface format. See VA_RT_FORMAT_*
|
||||
/// `va_fourcc` is the desired pixel format. See VA_FOURCC_*
|
||||
/// `width` is the surface width
|
||||
/// `height` is the surface height
|
||||
/// `usage_hint` gives the driver a hint of intended usage to optimize allocation (e.g. tiling)
|
||||
/// `num_surfaces` is the number of surfaces to create
|
||||
pub fn create_surfaces(
|
||||
self: &Rc<Self>,
|
||||
rt_format: u32,
|
||||
va_fourcc: Option<u32>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
usage_hint: Option<UsageHint>,
|
||||
num_surfaces: u32,
|
||||
) -> Result<Vec<Surface>> {
|
||||
Surface::new(
|
||||
Rc::clone(self),
|
||||
rt_format,
|
||||
va_fourcc,
|
||||
width,
|
||||
height,
|
||||
usage_hint,
|
||||
num_surfaces,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a Context by wrapping around a vaCreateContext call.
|
||||
/// `config` is the configuration for the context
|
||||
/// `coded_width` is the coded picture width
|
||||
/// `coded_height` is the coded picture height
|
||||
/// `progressive` is whether only progressive frame pictures are present in the sequence
|
||||
/// `surfaces` are a hint for the amount of surfaces tied to the context
|
||||
pub fn create_context(
|
||||
self: &Rc<Self>,
|
||||
config: &Config,
|
||||
coded_width: i32,
|
||||
coded_height: i32,
|
||||
surfaces: Option<&Vec<Surface>>,
|
||||
progressive: bool,
|
||||
) -> Result<Context> {
|
||||
Context::new(
|
||||
Rc::clone(self),
|
||||
config,
|
||||
coded_width,
|
||||
coded_height,
|
||||
surfaces,
|
||||
progressive,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a VAConfig by wrapping around the vaCreateConfig call. `attrs`
|
||||
/// describe the attributes to set for this config. A list of the supported
|
||||
/// attributes for a given profile/entrypoint pair can be retrieved using
|
||||
/// Display::get_config_attributes. Other attributes will take their default
|
||||
/// values
|
||||
pub fn create_config(
|
||||
self: &Rc<Self>,
|
||||
attrs: Option<Vec<bindings::VAConfigAttrib>>,
|
||||
profile: bindings::VAProfile::Type,
|
||||
entrypoint: bindings::VAEntrypoint::Type,
|
||||
) -> Result<Config> {
|
||||
Config::new(Rc::clone(self), attrs, profile, entrypoint)
|
||||
}
|
||||
|
||||
/// A wrapper over vaQueryImageFormats.
|
||||
pub fn query_image_formats(self: &Rc<Self>) -> Result<Vec<bindings::VAImageFormat>> {
|
||||
// Safe because `self` represents a valid VADisplay
|
||||
let mut num_image_formats = unsafe { bindings::vaMaxNumImageFormats(self.handle) };
|
||||
let mut image_formats = Vec::with_capacity(num_image_formats as usize);
|
||||
|
||||
// Safe because `self` represents a valid VADisplay. The "image_formats"
|
||||
// vector is properly initialized and a valid size is passed to the C
|
||||
// function, so it is impossible to write past the end of their storage
|
||||
// by mistake
|
||||
Status(unsafe {
|
||||
bindings::vaQueryImageFormats(
|
||||
self.handle,
|
||||
image_formats.as_mut_ptr(),
|
||||
&mut num_image_formats,
|
||||
)
|
||||
})
|
||||
.check()?;
|
||||
|
||||
// Safe because the C function will have writter to exactly
|
||||
// "num_image_format" entries, which is known to be within the vector's
|
||||
// capacity.
|
||||
unsafe {
|
||||
image_formats.set_len(num_image_formats as usize);
|
||||
}
|
||||
|
||||
Ok(image_formats)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Display {
|
||||
fn drop(&mut self) {
|
||||
// Safe because `self` represents a valid VADisplay.
|
||||
unsafe {
|
||||
bindings::vaTerminate(self.handle);
|
||||
// The File will close the DRM fd on drop.
|
||||
}
|
||||
}
|
||||
}
|
50
media/libva/src/generic_value.rs
Normal file
50
media/libva/src/generic_value.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
use crate::bindings;
|
||||
|
||||
/// A wrapper over VAGenericValue so we can safely access the underlying union
|
||||
/// members
|
||||
#[derive(Debug)]
|
||||
pub enum GenericValue {
|
||||
/// A wrapper over VAGenericValueTypeInteger
|
||||
Integer(i32),
|
||||
/// A wrapper over VAGenericValueTypeFloat
|
||||
Float(f32),
|
||||
/// A wrapper over VAGenericValueTypePointer
|
||||
Pointer(*mut std::os::raw::c_void),
|
||||
/// A wrapper over VAGenericValueTypeFunc
|
||||
Func(bindings::VAGenericFunc),
|
||||
}
|
||||
|
||||
impl TryFrom<bindings::VAGenericValue> for GenericValue {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: bindings::VAGenericValue) -> Result<Self, Self::Error> {
|
||||
// Safe because we check the type before accessing the union.
|
||||
match value.type_ {
|
||||
// Safe because we check the type before accessing the union.
|
||||
bindings::VAGenericValueType::VAGenericValueTypeInteger => {
|
||||
Ok(Self::Integer(unsafe { value.value.i }))
|
||||
}
|
||||
bindings::VAGenericValueType::VAGenericValueTypeFloat => {
|
||||
Ok(Self::Float(unsafe { value.value.f }))
|
||||
}
|
||||
bindings::VAGenericValueType::VAGenericValueTypePointer => {
|
||||
Ok(Self::Pointer(unsafe { value.value.p }))
|
||||
}
|
||||
bindings::VAGenericValueType::VAGenericValueTypeFunc => {
|
||||
Ok(Self::Func(unsafe { value.value.fn_ }))
|
||||
}
|
||||
other => {
|
||||
return Err(anyhow!(
|
||||
"Conversion failed for unexpected VAGenericValueType: {}",
|
||||
other
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
232
media/libva/src/image.rs
Normal file
232
media/libva/src/image.rs
Normal file
|
@ -0,0 +1,232 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::{
|
||||
bindings,
|
||||
picture::{Picture, PictureSync},
|
||||
status::Status,
|
||||
};
|
||||
|
||||
/// An owned VAImage that is tied to the lifetime of a given Picture.
|
||||
/// A VAImage is used to either get the surface data to client memory, or
|
||||
/// to copy image data in client memory to a surface.
|
||||
pub struct Image<'a> {
|
||||
/// The picture whose Surface we use in the vaGetImage call.
|
||||
picture: &'a Picture<PictureSync>,
|
||||
/// The VAImage returned by libva.
|
||||
image: bindings::VAImage,
|
||||
/// The mapped surface data.
|
||||
data: &'a mut [u8],
|
||||
/// Whether the image was derived using the `vaDeriveImage` API or created
|
||||
/// using the `vaCreateImage` API.
|
||||
derived: bool,
|
||||
/// Tracks whether the underlying data has possibly been written to, i.e. an
|
||||
/// encoder will create an Image and map its buffer in order to write to it,
|
||||
/// so we must writeback later.
|
||||
dirty: bool,
|
||||
}
|
||||
|
||||
impl<'a> Image<'a> {
|
||||
/// Creates a new `Image` either by calling `vaCreateImage` or
|
||||
/// `vaDeriveImage`. Creating an Image depends on acquiring a ready Surface
|
||||
/// from an underlying Picture. Note that Image has a borrowed Picture, so
|
||||
/// it will be dropped before the underlying Surface is dropped, as mandated
|
||||
/// by VAAPI.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `picture` is the Picture that owns the Surface this Image will be created from.
|
||||
/// * `format` is a VAImageFormat returned by the vaQueryImageFormats wrapper.
|
||||
/// * `width` is the Image's desired width.
|
||||
/// * `height` is the Image's desired height.
|
||||
/// * `derive` whether to try deriving the image. Deriving may fail, in
|
||||
/// which case vaCreateImage will be used instead.
|
||||
pub fn new(
|
||||
picture: &'a mut Picture<PictureSync>,
|
||||
mut format: bindings::VAImageFormat,
|
||||
width: u32,
|
||||
height: u32,
|
||||
derive: bool,
|
||||
) -> Result<Self> {
|
||||
// Safe because an all-zero byte-pattern represent a valid value for
|
||||
// bindings::VAImage. Note that this is a FFI type and that it does not have
|
||||
// any references in it.
|
||||
let mut image: bindings::VAImage = Default::default();
|
||||
let mut addr = std::ptr::null_mut();
|
||||
let mut derived = false;
|
||||
|
||||
if derive {
|
||||
derived = Image::derive_image(picture, &mut image)?;
|
||||
}
|
||||
|
||||
if !derived {
|
||||
Image::create_image(picture, &mut image, &mut format, width, height)?;
|
||||
}
|
||||
|
||||
// Safe since `picture.inner.context` represents a valid VAContext.
|
||||
// Image creation is ensured by either the vaDeriveImage or
|
||||
// vaCreateImage APIs and vaGetImage is called if the VAImage was not
|
||||
// derived, as mandated by VAAPI.
|
||||
match Status(unsafe {
|
||||
bindings::vaMapBuffer(
|
||||
picture.inner().context().display().handle(),
|
||||
image.buf,
|
||||
&mut addr,
|
||||
)
|
||||
})
|
||||
.check()
|
||||
{
|
||||
Ok(_) => {
|
||||
// Safe since addr will point to data mapped onto our address
|
||||
// space since we call vaGetImage above, which also guarantees
|
||||
// that the data is valid for len * mem::size_of<u8>().
|
||||
// Furthermore, we can only access the underlying memory using
|
||||
// the slice below.
|
||||
let data =
|
||||
unsafe { std::slice::from_raw_parts_mut(addr as _, image.data_size as usize) };
|
||||
Ok(Self {
|
||||
picture,
|
||||
image,
|
||||
data,
|
||||
derived,
|
||||
dirty: false,
|
||||
})
|
||||
}
|
||||
Err(e) => {
|
||||
// Safe because `picture.inner.context` represents a valid
|
||||
// VAContext and `image` represents a valid VAImage.
|
||||
unsafe {
|
||||
bindings::vaDestroyImage(
|
||||
picture.inner().context().display().handle(),
|
||||
image.image_id,
|
||||
);
|
||||
}
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_image(
|
||||
picture: &'a mut Picture<PictureSync>,
|
||||
image: &mut bindings::VAImage,
|
||||
format: &mut bindings::VAImageFormat,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<()> {
|
||||
let dpy = picture.inner().context().display().handle();
|
||||
|
||||
// Safe because `picture.inner.context` represents a valid
|
||||
// VAContext.
|
||||
Status(unsafe { bindings::vaCreateImage(dpy, format, width as i32, height as i32, image) })
|
||||
.check()?;
|
||||
|
||||
// Safe because `picture.inner.context` represents a valid VAContext,
|
||||
// `picture.surface` represents a valid VASurface and `image` represents
|
||||
// a valid `VAImage`.
|
||||
if let Err(e) = Status(unsafe {
|
||||
bindings::vaGetImage(
|
||||
dpy,
|
||||
picture.surface_mut().id(),
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
image.image_id,
|
||||
)
|
||||
})
|
||||
.check()
|
||||
{
|
||||
// Safe since `image` represents a valid `VAImage`.
|
||||
unsafe {
|
||||
bindings::vaDestroyImage(dpy, image.image_id);
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn derive_image(
|
||||
picture: &'a mut Picture<PictureSync>,
|
||||
image: &mut bindings::VAImage,
|
||||
) -> Result<bool> {
|
||||
let status = Status(unsafe {
|
||||
bindings::vaDeriveImage(
|
||||
picture.inner().context().display().handle(),
|
||||
picture.surface_mut().id(),
|
||||
image,
|
||||
)
|
||||
});
|
||||
|
||||
if status.0 == bindings::constants::VA_STATUS_ERROR_OPERATION_FAILED as i32 {
|
||||
// The implementation can't derive, try the create API instead.
|
||||
return Ok(false);
|
||||
} else {
|
||||
status.check()?;
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference to the underlying VAImage that describes this Image.
|
||||
pub fn image(&self) -> &bindings::VAImage {
|
||||
&self.image
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsRef<[u8]> for Image<'a> {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsMut<[u8]> for Image<'a> {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
self.dirty = true;
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for Image<'a> {
|
||||
fn drop(&mut self) {
|
||||
// Safe because `picture.inner.context` represents a valid VAContext,
|
||||
// `picture.surface` represents a valid VASurface and `image` represents
|
||||
// a valid `VAImage`. Lastly, the buffer is mapped in Image::new, so
|
||||
// self.image.buf points to a valid VABufferID.
|
||||
let surface = self.picture.surface();
|
||||
|
||||
if !self.derived && self.dirty {
|
||||
unsafe {
|
||||
bindings::vaPutImage(
|
||||
self.picture.inner().context().display().handle(),
|
||||
surface.id(),
|
||||
self.image.image_id,
|
||||
0,
|
||||
0,
|
||||
self.image.width as u32,
|
||||
self.image.height as u32,
|
||||
0,
|
||||
0,
|
||||
self.image.width as u32,
|
||||
self.image.height as u32,
|
||||
);
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
// Safe since the buffer is mapped in Image::new, so self.image.buf
|
||||
// points to a valid VABufferID.
|
||||
bindings::vaUnmapBuffer(
|
||||
self.picture.inner().context().display().handle(),
|
||||
self.image.buf,
|
||||
);
|
||||
}
|
||||
unsafe {
|
||||
// Safe since `self.image` represents a valid VAImage.
|
||||
bindings::vaDestroyImage(
|
||||
self.picture.inner().context().display().handle(),
|
||||
self.image.image_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
236
media/libva/src/lib.rs
Normal file
236
media/libva/src/lib.rs
Normal file
|
@ -0,0 +1,236 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
//! This module implements a lightweight and safe decoder interface over
|
||||
//! `libva`. It is designed to concentrate all calls to unsafe methods in one
|
||||
//! place
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
mod bindings;
|
||||
mod buffer;
|
||||
mod buffer_type;
|
||||
mod config;
|
||||
mod context;
|
||||
mod display;
|
||||
mod generic_value;
|
||||
mod image;
|
||||
mod picture;
|
||||
mod status;
|
||||
mod surface;
|
||||
mod usage_hint;
|
||||
|
||||
pub use bindings::constants;
|
||||
pub use bindings::VAConfigAttrib;
|
||||
pub use bindings::VAConfigAttribType;
|
||||
pub use bindings::VAEntrypoint;
|
||||
pub use bindings::VAImageFormat;
|
||||
pub use bindings::VAProfile;
|
||||
pub use bindings::VASurfaceAttribType;
|
||||
pub use buffer::*;
|
||||
pub use buffer_type::*;
|
||||
pub use config::*;
|
||||
pub use context::*;
|
||||
pub use display::*;
|
||||
pub use generic_value::*;
|
||||
pub use image::*;
|
||||
pub use picture::*;
|
||||
pub use surface::*;
|
||||
pub use usage_hint::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Returns a 32-bit CRC for the visible part of `image`, which must be in NV12 format.
|
||||
fn crc_nv12_image(image: &Image) -> u32 {
|
||||
let data = image.as_ref();
|
||||
let va_image = image.image();
|
||||
let offsets = &va_image.offsets;
|
||||
let pitches = &va_image.pitches;
|
||||
let width = va_image.width as usize;
|
||||
let height = va_image.height as usize;
|
||||
|
||||
// We only support NV12 images
|
||||
assert_eq!(va_image.format.fourcc, u32::from_ne_bytes(*b"NV12"));
|
||||
// Consistency check
|
||||
assert_eq!(va_image.num_planes, 2);
|
||||
|
||||
let mut hasher = crc32fast::Hasher::new();
|
||||
|
||||
let offset = offsets[0] as usize;
|
||||
let pitch = pitches[0] as usize;
|
||||
let y_plane = data[offset..(offset + pitch * height)]
|
||||
.chunks(pitch)
|
||||
.map(|line| &line[0..width]);
|
||||
|
||||
let offset = offsets[1] as usize;
|
||||
let pitch = pitches[1] as usize;
|
||||
let uv_plane = data[offset..(offset + pitch * ((height + 1) / 2))]
|
||||
.chunks(pitch)
|
||||
.map(|line| &line[0..width]);
|
||||
|
||||
for line in y_plane.chain(uv_plane) {
|
||||
hasher.update(line);
|
||||
}
|
||||
|
||||
hasher.finalize()
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Ignore this test by default as it requires libva-compatible hardware.
|
||||
#[ignore]
|
||||
fn libva_utils_mpeg2vldemo() {
|
||||
// Adapted from <https://github.com/intel/libva-utils/blob/master/decode/mpeg2vldemo.cpp>
|
||||
let display = Rc::new(Display::open().unwrap());
|
||||
|
||||
assert!(!display.query_vendor_string().unwrap().is_empty());
|
||||
let profiles = display.query_config_profiles().unwrap();
|
||||
assert!(!profiles.is_empty());
|
||||
|
||||
let profile = bindings::VAProfile::VAProfileMPEG2Main;
|
||||
let entrypoints = display.query_config_entrypoints(profile).unwrap();
|
||||
assert!(!entrypoints.is_empty());
|
||||
assert!(entrypoints
|
||||
.iter()
|
||||
.any(|e| *e == bindings::VAEntrypoint::VAEntrypointVLD));
|
||||
|
||||
let format = bindings::constants::VA_RT_FORMAT_YUV420;
|
||||
let width = 16;
|
||||
let height = 16;
|
||||
|
||||
let mut attrs = vec![bindings::VAConfigAttrib {
|
||||
type_: bindings::VAConfigAttribType::VAConfigAttribRTFormat,
|
||||
value: 0,
|
||||
}];
|
||||
|
||||
let entrypoint = bindings::VAEntrypoint::VAEntrypointVLD;
|
||||
display
|
||||
.get_config_attributes(profile, entrypoint, &mut attrs)
|
||||
.unwrap();
|
||||
assert!(attrs[0].value != bindings::constants::VA_ATTRIB_NOT_SUPPORTED);
|
||||
assert!(attrs[0].value & bindings::constants::VA_RT_FORMAT_YUV420 != 0);
|
||||
|
||||
let config = display
|
||||
.create_config(Some(attrs), profile, entrypoint)
|
||||
.unwrap();
|
||||
|
||||
let mut surfaces = display
|
||||
.create_surfaces(
|
||||
format,
|
||||
None,
|
||||
width,
|
||||
height,
|
||||
Some(UsageHint::USAGE_HINT_DECODER),
|
||||
1,
|
||||
)
|
||||
.unwrap();
|
||||
let context = Rc::new(
|
||||
display
|
||||
.create_context(
|
||||
&config,
|
||||
width as i32,
|
||||
(((height + 15) / 16) * 16) as i32,
|
||||
Some(&surfaces),
|
||||
true,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
// The picture data is adapted from libva-utils at decode/mpeg2vldemo.cpp
|
||||
// Data dump of a 16x16 MPEG2 video clip,it has one I frame
|
||||
let mut mpeg2_clip: Vec<u8> = vec![
|
||||
0x00, 0x00, 0x01, 0xb3, 0x01, 0x00, 0x10, 0x13, 0xff, 0xff, 0xe0, 0x18, 0x00, 0x00,
|
||||
0x01, 0xb5, 0x14, 0x8a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x08,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xb5,
|
||||
0x8f, 0xff, 0xf3, 0x41, 0x80, 0x00, 0x00, 0x01, 0x01, 0x13, 0xe1, 0x00, 0x15, 0x81,
|
||||
0x54, 0xe0, 0x2a, 0x05, 0x43, 0x00, 0x2d, 0x60, 0x18, 0x01, 0x4e, 0x82, 0xb9, 0x58,
|
||||
0xb1, 0x83, 0x49, 0xa4, 0xa0, 0x2e, 0x05, 0x80, 0x4b, 0x7a, 0x00, 0x01, 0x38, 0x20,
|
||||
0x80, 0xe8, 0x05, 0xff, 0x60, 0x18, 0xe0, 0x1d, 0x80, 0x98, 0x01, 0xf8, 0x06, 0x00,
|
||||
0x54, 0x02, 0xc0, 0x18, 0x14, 0x03, 0xb2, 0x92, 0x80, 0xc0, 0x18, 0x94, 0x42, 0x2c,
|
||||
0xb2, 0x11, 0x64, 0xa0, 0x12, 0x5e, 0x78, 0x03, 0x3c, 0x01, 0x80, 0x0e, 0x80, 0x18,
|
||||
0x80, 0x6b, 0xca, 0x4e, 0x01, 0x0f, 0xe4, 0x32, 0xc9, 0xbf, 0x01, 0x42, 0x69, 0x43,
|
||||
0x50, 0x4b, 0x01, 0xc9, 0x45, 0x80, 0x50, 0x01, 0x38, 0x65, 0xe8, 0x01, 0x03, 0xf3,
|
||||
0xc0, 0x76, 0x00, 0xe0, 0x03, 0x20, 0x28, 0x18, 0x01, 0xa9, 0x34, 0x04, 0xc5, 0xe0,
|
||||
0x0b, 0x0b, 0x04, 0x20, 0x06, 0xc0, 0x89, 0xff, 0x60, 0x12, 0x12, 0x8a, 0x2c, 0x34,
|
||||
0x11, 0xff, 0xf6, 0xe2, 0x40, 0xc0, 0x30, 0x1b, 0x7a, 0x01, 0xa9, 0x0d, 0x00, 0xac,
|
||||
0x64,
|
||||
];
|
||||
|
||||
let picture_coding_extension =
|
||||
MPEG2PictureCodingExtension::new(0, 3, 0, 1, 0, 0, 0, 0, 0, 1, 1);
|
||||
let pic_param = PictureParameterBufferMPEG2::new(
|
||||
16,
|
||||
16,
|
||||
0xffffffff,
|
||||
0xffffffff,
|
||||
1,
|
||||
0xffff,
|
||||
&picture_coding_extension,
|
||||
);
|
||||
|
||||
let pic_param = BufferType::PictureParameter(PictureParameter::MPEG2(pic_param));
|
||||
|
||||
let iq_matrix = IQMatrixBufferMPEG2::new(
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
[
|
||||
8, 16, 16, 19, 16, 19, 22, 22, 22, 22, 22, 22, 26, 24, 26, 27, 27, 27, 26, 26, 26,
|
||||
26, 27, 27, 27, 29, 29, 29, 34, 34, 34, 29, 29, 29, 27, 27, 29, 29, 32, 32, 34, 34,
|
||||
37, 38, 37, 35, 35, 34, 35, 38, 38, 40, 40, 40, 48, 48, 46, 46, 56, 56, 58, 69, 69,
|
||||
83,
|
||||
],
|
||||
[
|
||||
16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
],
|
||||
[0; 64],
|
||||
[0; 64],
|
||||
);
|
||||
|
||||
let iq_matrix = BufferType::IQMatrix(IQMatrix::MPEG2(iq_matrix));
|
||||
|
||||
let slice_param = SliceParameterBufferMPEG2::new(150, 0, 0, 38, 0, 0, 2, 0);
|
||||
|
||||
let slice_param = BufferType::SliceParameter(SliceParameter::MPEG2(slice_param));
|
||||
|
||||
let test_data_offset = 47;
|
||||
let slice_data = BufferType::SliceData(mpeg2_clip.drain(test_data_offset..).collect());
|
||||
|
||||
let buffers = vec![
|
||||
context.create_buffer(pic_param).unwrap(),
|
||||
context.create_buffer(slice_param).unwrap(),
|
||||
context.create_buffer(iq_matrix).unwrap(),
|
||||
context.create_buffer(slice_data).unwrap(),
|
||||
];
|
||||
|
||||
let mut picture = Picture::new(0, Rc::clone(&context), surfaces.remove(0));
|
||||
for buffer in buffers {
|
||||
picture.add_buffer(buffer);
|
||||
}
|
||||
|
||||
// Actual client code can just chain the calls.
|
||||
let picture = picture.begin().unwrap();
|
||||
let picture = picture.render().unwrap();
|
||||
let picture = picture.end().unwrap();
|
||||
let mut picture = picture.sync().unwrap();
|
||||
|
||||
// Test whether we can map the resulting surface to obtain the raw yuv
|
||||
// data
|
||||
let image_fmts = display.query_image_formats().unwrap();
|
||||
let image_fmt = image_fmts
|
||||
.into_iter()
|
||||
.find(|f| f.fourcc == bindings::constants::VA_FOURCC_NV12)
|
||||
.expect("No valid VAImageFormat found for NV12");
|
||||
|
||||
let image = Image::new(&mut picture, image_fmt, width, height, false).unwrap();
|
||||
|
||||
assert_eq!(crc_nv12_image(&image), 0xa5713e52);
|
||||
}
|
||||
}
|
229
media/libva/src/picture.rs
Normal file
229
media/libva/src/picture.rs
Normal file
|
@ -0,0 +1,229 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::{marker::PhantomData, rc::Rc};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::{bindings, buffer::Buffer, context::Context, status::Status, surface::Surface};
|
||||
|
||||
// Use the sealed trait pattern to make sure that new states are not created in
|
||||
// caller code. More information about the sealed trait pattern can be found at
|
||||
// <https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed>
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
/// A `Picture` will only have valid YUV data after a sequence of operations are
|
||||
/// performed in a particular order. This order correspond to the following
|
||||
/// VA-API calls: vaBeginPicture, vaRenderPicture, vaEndPicture and
|
||||
/// vaSyncSurface. This trait enforces this ordering by implementing the
|
||||
/// Typestate pattern to constrain what operations are available in what
|
||||
/// particular states.
|
||||
///
|
||||
/// The states for the state machine are:
|
||||
/// PictureNew -> PictureBegin
|
||||
/// PictureBegin -> PictureRender
|
||||
/// PictureRender ->PictureEnd
|
||||
/// PictureEnd -> PictureSync
|
||||
///
|
||||
/// Where the surface can be reclaimed in both PictureNew and PictureSync, as
|
||||
/// either no operation took place (as in PictureNew), or it is guaranteed that
|
||||
/// the operation has already completed (as in PictureSync)
|
||||
///
|
||||
/// More information about the Typestate pattern can be found
|
||||
/// at <http://cliffle.com/blog/rust-typestate/>
|
||||
pub trait PictureState: private::Sealed {}
|
||||
|
||||
/// Represents a `Picture` that has just been created.
|
||||
pub enum PictureNew {}
|
||||
impl PictureState for PictureNew {}
|
||||
impl private::Sealed for PictureNew {}
|
||||
|
||||
/// Represents a `Picture` after `vaBeginPicture` has been called.
|
||||
pub enum PictureBegin {}
|
||||
impl PictureState for PictureBegin {}
|
||||
impl private::Sealed for PictureBegin {}
|
||||
|
||||
/// Represents a `Picture` after `vaRenderPicture` has been called.
|
||||
pub enum PictureRender {}
|
||||
impl PictureState for PictureRender {}
|
||||
impl private::Sealed for PictureRender {}
|
||||
|
||||
/// Represents a `Picture` after `vaEndPicture` has been called.
|
||||
pub enum PictureEnd {}
|
||||
impl PictureState for PictureEnd {}
|
||||
impl private::Sealed for PictureEnd {}
|
||||
|
||||
/// Represents a `Picture` after `vaSyncSurface` has been called on the
|
||||
/// underlying surface.
|
||||
pub enum PictureSync {}
|
||||
impl PictureState for PictureSync {}
|
||||
impl private::Sealed for PictureSync {}
|
||||
|
||||
/// Represents a state where one can reclaim the underlying `Surface` for this
|
||||
/// `Picture`. This is true when either no decoding has been initiated or,
|
||||
/// alternatively, when the decoding operation has completed for the underlying
|
||||
/// `vaSurface`
|
||||
pub trait PictureReclaimableSurface: PictureState + private::Sealed {}
|
||||
impl PictureReclaimableSurface for PictureNew {}
|
||||
impl PictureReclaimableSurface for PictureSync {}
|
||||
|
||||
pub(crate) struct PictureInner {
|
||||
/// Identifies this picture
|
||||
frame_number: u32,
|
||||
/// A context associated with this picture
|
||||
context: Rc<Context>,
|
||||
/// Contains the buffers used to decode the data
|
||||
buffers: Vec<Buffer>,
|
||||
/// Contains the actual decoded data.
|
||||
surface: Surface,
|
||||
}
|
||||
|
||||
impl PictureInner {
|
||||
/// Returns a reference to the Context used by the Picture
|
||||
pub(crate) fn context(&self) -> Rc<Context> {
|
||||
Rc::clone(&self.context)
|
||||
}
|
||||
}
|
||||
|
||||
/// An abstraction over VABuffers and a VASurface suitable for decoding with
|
||||
/// vaBeginPicture, vaRenderPicture, vaEndPicture "surface" will have valid raw
|
||||
/// picture data after "begin", "render", "end" and "sync" are called, in this
|
||||
/// order.
|
||||
pub struct Picture<S: PictureState> {
|
||||
inner: Box<PictureInner>,
|
||||
phantom: std::marker::PhantomData<S>,
|
||||
}
|
||||
|
||||
impl Picture<PictureNew> {
|
||||
/// Creates a new Picture with a given `frame_number` to identify it.
|
||||
/// `surface` is the underlying surface that libva will render to.
|
||||
pub fn new(frame_number: u32, context: Rc<Context>, surface: Surface) -> Self {
|
||||
Self {
|
||||
inner: Box::new(PictureInner {
|
||||
frame_number,
|
||||
context,
|
||||
buffers: Default::default(),
|
||||
surface,
|
||||
}),
|
||||
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add buffers to a picture
|
||||
pub fn add_buffer(&mut self, buffer: Buffer) {
|
||||
self.inner.buffers.push(buffer);
|
||||
}
|
||||
|
||||
/// A wrapper around vaBeginPicture
|
||||
pub fn begin(self) -> Result<Picture<PictureBegin>> {
|
||||
// Safe because `self.inner.context` represents a valid VAContext and
|
||||
// `self.inner.surface` represents a valid VASurface.
|
||||
Status(unsafe {
|
||||
bindings::vaBeginPicture(
|
||||
self.inner.context.display().handle(),
|
||||
self.inner.context.id(),
|
||||
self.inner.surface.id(),
|
||||
)
|
||||
})
|
||||
.check()?;
|
||||
|
||||
Ok(Picture {
|
||||
inner: self.inner,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Picture<PictureBegin> {
|
||||
/// A wrapper around vaRenderPicture
|
||||
pub fn render(self) -> Result<Picture<PictureRender>> {
|
||||
// Safe because `self.inner.context` represents a valid VAContext and
|
||||
// `self.inner.surface` represents a valid VASurface. `buffers` point to
|
||||
// a Rust struct and the vector length is passed to the C function, so
|
||||
// it is impossible to write past the end of the vector's storage by
|
||||
// mistake.
|
||||
Status(unsafe {
|
||||
bindings::vaRenderPicture(
|
||||
self.inner.context.display().handle(),
|
||||
self.inner.context.id(),
|
||||
Buffer::as_id_vec(&self.inner.buffers).as_mut_ptr(),
|
||||
self.inner.buffers.len() as i32,
|
||||
)
|
||||
})
|
||||
.check()?;
|
||||
|
||||
Ok(Picture {
|
||||
inner: self.inner,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Picture<PictureRender> {
|
||||
/// A wrapper around vaEndPicture
|
||||
pub fn end(self) -> Result<Picture<PictureEnd>> {
|
||||
// Safe because `self.inner.context` represents a valid VAContext.
|
||||
Status(unsafe {
|
||||
bindings::vaEndPicture(
|
||||
self.inner.context.display().handle(),
|
||||
self.inner.context.id(),
|
||||
)
|
||||
})
|
||||
.check()?;
|
||||
Ok(Picture {
|
||||
inner: self.inner,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Picture<PictureEnd> {
|
||||
/// Syncs the picture, ensuring that any pending decode operations are
|
||||
/// complete when this call returns
|
||||
pub fn sync(self) -> Result<Picture<PictureSync>> {
|
||||
self.inner.surface.sync()?;
|
||||
|
||||
Ok(Picture {
|
||||
inner: self.inner,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Picture<PictureSync> {
|
||||
/// Returns a reference to the underlying `Surface` for this
|
||||
/// `Picture`
|
||||
pub fn surface(&self) -> &Surface {
|
||||
&self.inner.surface
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the underlying `Surface` for this
|
||||
/// `Picture`
|
||||
pub fn surface_mut(&mut self) -> &mut Surface {
|
||||
&mut self.inner.surface
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: PictureState> Picture<S> {
|
||||
/// Get the frame number for this picture.
|
||||
pub fn frame_number(&self) -> u32 {
|
||||
self.inner.frame_number
|
||||
}
|
||||
|
||||
/// Returns a reference to the `inner` struct
|
||||
pub(crate) fn inner(&self) -> &PictureInner {
|
||||
self.inner.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: PictureReclaimableSurface> Picture<S> {
|
||||
/// Reclaim ownership of the Surface, consuming the picture in the process.
|
||||
/// Useful if the Surface is part of a pool.
|
||||
pub fn take_surface(self) -> Surface {
|
||||
self.inner.surface
|
||||
}
|
||||
}
|
31
media/libva/src/status.rs
Normal file
31
media/libva/src/status.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::ffi::CStr;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
use crate::bindings;
|
||||
|
||||
/// Wrapper over VAStatus, calling check() returns a Error if the status is
|
||||
/// not VA_STATUS_SUCCESS
|
||||
#[must_use = "VAStatus might not be VA_STATUS_SUCCESS."]
|
||||
pub(crate) struct Status(pub bindings::VAStatus);
|
||||
|
||||
impl Status {
|
||||
/// Convenience function to convert from Status to Result
|
||||
pub(crate) fn check(&self) -> Result<()> {
|
||||
if self.0 == bindings::constants::VA_STATUS_SUCCESS as i32 {
|
||||
Ok(())
|
||||
} else {
|
||||
// Safe because vaErrorStr will return a pointer to a statically
|
||||
// allocated, null terminated C String. The pointer is guaranteed to
|
||||
// never be null
|
||||
let err_str = unsafe { CStr::from_ptr(bindings::vaErrorStr(self.0)) }
|
||||
.to_str()
|
||||
.unwrap();
|
||||
Err(anyhow!("VA-API error: {}: {}", self.0, err_str))
|
||||
}
|
||||
}
|
||||
}
|
139
media/libva/src/surface.rs
Normal file
139
media/libva/src/surface.rs
Normal file
|
@ -0,0 +1,139 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::{bindings, display::Display, status::Status, UsageHint};
|
||||
|
||||
/// An owned VASurface that is tied to the lifetime of a particular VADisplay
|
||||
pub struct Surface {
|
||||
display: Rc<Display>,
|
||||
id: bindings::VASurfaceID,
|
||||
}
|
||||
|
||||
impl Surface {
|
||||
/// Create VASurfaces by wrapping around a vaCreateSurfaces call
|
||||
/// `rt_format` is the desired surface format. See VA_RT_FORMAT_*
|
||||
/// `va_fourcc` is the desired pixel format. See VA_FOURCC_*
|
||||
/// `width` is the surface width
|
||||
/// `height` is the surface height
|
||||
/// `usage_hint` gives the driver a hint of intended usage to optimize allocation (e.g. tiling)
|
||||
/// `num_surfaces` is the number of surfaces to create
|
||||
pub(crate) fn new(
|
||||
display: Rc<Display>,
|
||||
rt_format: u32,
|
||||
va_fourcc: Option<u32>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
usage_hint: Option<UsageHint>,
|
||||
num_surfaces: u32,
|
||||
) -> Result<Vec<Self>> {
|
||||
let mut attrs = vec![];
|
||||
|
||||
if let Some(usage_hint) = usage_hint {
|
||||
let attr = bindings::VASurfaceAttrib {
|
||||
type_: bindings::VASurfaceAttribType::VASurfaceAttribUsageHint,
|
||||
flags: bindings::constants::VA_SURFACE_ATTRIB_SETTABLE,
|
||||
value: bindings::VAGenericValue {
|
||||
type_: bindings::VAGenericValueType::VAGenericValueTypeInteger,
|
||||
value: bindings::_VAGenericValue__bindgen_ty_1 {
|
||||
i: usage_hint.bits() as i32,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
attrs.push(attr);
|
||||
}
|
||||
|
||||
if let Some(fourcc) = va_fourcc {
|
||||
let attr = bindings::VASurfaceAttrib {
|
||||
type_: bindings::VASurfaceAttribType::VASurfaceAttribPixelFormat,
|
||||
flags: bindings::constants::VA_DISPLAY_ATTRIB_SETTABLE,
|
||||
value: bindings::VAGenericValue {
|
||||
type_: bindings::VAGenericValueType::VAGenericValueTypeInteger,
|
||||
value: bindings::_VAGenericValue__bindgen_ty_1 { i: fourcc as i32 },
|
||||
},
|
||||
};
|
||||
|
||||
attrs.push(attr);
|
||||
}
|
||||
|
||||
let mut surfaces = Vec::with_capacity(num_surfaces as usize);
|
||||
|
||||
// Safe because `self` represents a valid VADisplay. The "surface" and
|
||||
// "attrs" vectors are properly initialized and valid sizes are passed
|
||||
// to the C function, so it is impossible to write past the end of their
|
||||
// storage by mistake
|
||||
Status(unsafe {
|
||||
bindings::vaCreateSurfaces(
|
||||
display.handle(),
|
||||
rt_format,
|
||||
width,
|
||||
height,
|
||||
surfaces.as_mut_ptr(),
|
||||
num_surfaces,
|
||||
attrs.as_mut_ptr(),
|
||||
attrs.len() as u32,
|
||||
)
|
||||
})
|
||||
.check()?;
|
||||
|
||||
// Safe because the C function will have written to exactly
|
||||
// "num_surface" entries, which is known to be within the vector's
|
||||
// capacity.
|
||||
unsafe {
|
||||
surfaces.set_len(num_surfaces as usize);
|
||||
}
|
||||
|
||||
let va_surfaces = surfaces
|
||||
.iter()
|
||||
.map(|&id| Self {
|
||||
display: Rc::clone(&display),
|
||||
id,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(va_surfaces)
|
||||
}
|
||||
|
||||
/// This function blocks until all pending operations on the render target
|
||||
/// have been completed. Upon return it is safe to use the render target
|
||||
/// for a different picture.
|
||||
pub fn sync(&self) -> Result<()> {
|
||||
// Safe because `self` represents a valid VASurface.
|
||||
Status(unsafe { bindings::vaSyncSurface(self.display.handle(), self.id) }).check()
|
||||
}
|
||||
|
||||
/// Convenience function to return a VASurfaceID vector. Useful to interface
|
||||
/// with the C API where a surface array might be needed.
|
||||
pub fn as_id_vec(surfaces: &[Self]) -> Vec<bindings::VASurfaceID> {
|
||||
surfaces.iter().map(|surface| surface.id).collect()
|
||||
}
|
||||
|
||||
/// A wrapper over vaQuerySurfaceStatus. Finds out any pending ops on the
|
||||
/// render target.
|
||||
pub fn query_status(&self) -> Result<bindings::VASurfaceStatus::Type> {
|
||||
let mut status: bindings::VASurfaceStatus::Type = 0;
|
||||
// Safe because `self` represents a valid VASurface.
|
||||
Status(unsafe {
|
||||
bindings::vaQuerySurfaceStatus(self.display.handle(), self.id, &mut status)
|
||||
})
|
||||
.check()?;
|
||||
Ok(status)
|
||||
}
|
||||
|
||||
/// Return the VASurfaceID for this surface
|
||||
pub fn id(&self) -> bindings::VASurfaceID {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Surface {
|
||||
fn drop(&mut self) {
|
||||
// Safe because `self` represents a valid VASurface.
|
||||
unsafe { bindings::vaDestroySurfaces(self.display.handle(), &mut self.id, 1) };
|
||||
}
|
||||
}
|
27
media/libva/src/usage_hint.rs
Normal file
27
media/libva/src/usage_hint.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use bitflags::bitflags;
|
||||
|
||||
use crate::constants;
|
||||
|
||||
bitflags! {
|
||||
/// Gives the driver a hint of intended usage to optimize allocation (e.g. tiling)
|
||||
pub struct UsageHint: u32 {
|
||||
/// Surface usage not indicated
|
||||
const USAGE_HINT_GENERIC = constants::VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC;
|
||||
/// Surface used by video decoder
|
||||
const USAGE_HINT_DECODER = constants::VA_SURFACE_ATTRIB_USAGE_HINT_DECODER;
|
||||
/// Surface used by video encoder
|
||||
const USAGE_HINT_ENCODER = constants::VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER;
|
||||
/// Surface read by video post-processing
|
||||
const USAGE_HINT_VPP_READ = constants::VA_SURFACE_ATTRIB_USAGE_HINT_VPP_READ;
|
||||
/// Surface written by video post-processing
|
||||
const USAGE_HINT_VPP_WRITE = constants::VA_SURFACE_ATTRIB_USAGE_HINT_VPP_WRITE;
|
||||
/// Surface used for display
|
||||
const USAGE_HINT_DISPLAY = constants::VA_SURFACE_ATTRIB_USAGE_HINT_DISPLAY;
|
||||
/// Surface used for export to third-party APIs, e.g. via vaExportSurfaceHandle()
|
||||
const USAGE_HINT_EXPORT = constants::VA_SURFACE_ATTRIB_USAGE_HINT_EXPORT;
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ dirs=(
|
|||
kernel_loader
|
||||
kvm_sys
|
||||
media/ffmpeg
|
||||
media/libva
|
||||
media/libvda
|
||||
net_sys
|
||||
vfio_sys
|
||||
|
|
|
@ -60,6 +60,7 @@ WIN64_DISABLED_CRATES = [
|
|||
"io_uring",
|
||||
"kvm",
|
||||
"libcras_stub",
|
||||
"libva",
|
||||
"libvda",
|
||||
"minijail-sys",
|
||||
"minijail",
|
||||
|
@ -112,6 +113,15 @@ CRATE_OPTIONS: Dict[str, List[TestOption]] = {
|
|||
TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL,
|
||||
], # b/181674144
|
||||
"libcrosvm_control": [TestOption.DO_NOT_BUILD_ARMHF], # b/210015864
|
||||
"libva": [
|
||||
# Libva only makes sense for x86 Linux platforms, disable building on others.
|
||||
TestOption.DO_NOT_BUILD_AARCH64,
|
||||
TestOption.DO_NOT_BUILD_ARMHF,
|
||||
TestOption.DO_NOT_BUILD_WIN64,
|
||||
# Only run libva on Linux x86. Note that all tests are not enabled, see b/238047780.
|
||||
TestOption.DO_NOT_RUN_AARCH64,
|
||||
TestOption.DO_NOT_RUN_ARMHF,
|
||||
],
|
||||
"libvda": [TestOption.DO_NOT_BUILD], # b/202293971
|
||||
"rutabaga_gfx": [TestOption.DO_NOT_BUILD_ARMHF], # b/210015864
|
||||
"vhost": [TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL],
|
||||
|
|
Loading…
Reference in a new issue