pub mod capabilities {
pub use crate::adapter::AdapterInfo;
pub use crate::device::caps::{
DecodeCapabilities, DecodeH264Capabilities, DecodeH264ProfileCapabilities,
EncodeCapabilities, EncodeH264Capabilities, EncodeH264ProfileCapabilities,
};
pub use ash::vk::PhysicalDeviceType as VulkanDeviceType;
}
pub mod parameters {
pub use crate::adapter::VulkanAdapterDescriptor;
pub use crate::device::{
ColorRange, ColorSpace, DecoderParameters, EncoderOutputParameters, EncoderParameters,
MissedFrameHandling, Rational, VideoParameters, VulkanDeviceDescriptor,
};
pub use crate::vulkan_encoder::RateControl;
#[cfg(feature = "transcoder")]
pub use crate::vulkan_transcoder::{TranscoderOutputParameters, TranscoderParameters};
#[cfg(feature = "wgpu")]
pub use crate::wgpu_helpers::WgpuConverterParameters;
pub use ash::vk::VideoDecodeUsageFlagsKHR as DecoderUsageFlags;
pub use ash::vk::VideoEncodeContentFlagsKHR as EncoderContentFlags;
pub use ash::vk::VideoEncodeTuningModeKHR as EncoderTuningMode;
pub use ash::vk::VideoEncodeUsageFlagsKHR as EncoderUsageFlags;
#[derive(Debug, Clone, Copy, Default)]
#[repr(u32)]
pub enum ScalingAlgorithm {
NearestNeighbor,
#[default]
Bilinear,
Lanczos3,
}
#[derive(Debug, Clone, Copy)]
pub enum H264Profile {
Baseline,
Main,
High,
}
impl H264Profile {
pub(crate) fn to_profile_idc(self) -> ash::vk::native::StdVideoH264ProfileIdc {
match self {
H264Profile::Baseline => {
ash::vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_BASELINE
}
H264Profile::Main => {
ash::vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_MAIN
}
H264Profile::High => {
ash::vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_HIGH
}
}
}
}
}
#[cfg(feature = "wgpu")]
mod wgpu_api;
#[cfg(feature = "wgpu")]
pub use wgpu_api::*;
use crate::device::{ColorRange, ColorSpace};
use crate::parser::h264::AccessUnit;
use crate::vulkan_decoder::{FrameSorter, VulkanDecoder};
use ash::vk;
pub use crate::adapter::VulkanAdapter;
pub use crate::device::VulkanDevice;
pub use crate::instance::VulkanInstance;
pub use crate::parser::{h264::H264ParserError, reference_manager::ReferenceManagementError};
pub use crate::vulkan_decoder::VulkanDecoderError;
pub use crate::vulkan_encoder::VulkanEncoderError;
#[cfg(feature = "transcoder")]
pub use crate::vulkan_transcoder::{Transcoder, TranscoderError};
#[cfg(feature = "wgpu")]
pub use crate::wgpu_helpers::{
WgpuConverterInitError, WgpuNv12ToRgbaConverter, WgpuRgbaToNv12Converter,
};
use crate::parser::{
decoder_instructions::compile_to_decoder_instructions, h264::H264Parser,
reference_manager::ReferenceContext,
};
use crate::vulkan_encoder::VulkanEncoder;
use crate::wrappers::ImageKey;
#[derive(Debug, thiserror::Error)]
pub enum DecoderError {
#[error("Decoder error: {0}")]
VulkanDecoderError(#[from] VulkanDecoderError),
#[error("H264 parser error: {0}")]
ParserError(#[from] H264ParserError),
#[error("Reference management error: {0}")]
ReferenceManagementError(#[from] ReferenceManagementError),
}
#[derive(thiserror::Error, Debug)]
pub enum VulkanInitError {
#[error("Error loading vulkan: {0}")]
LoadingError(#[from] ash::LoadingError),
#[error("Vulkan error: {0}")]
VkError(#[from] vk::Result),
#[cfg(feature = "wgpu")]
#[error(transparent)]
WgpuError(#[from] WgpuInitError),
#[error("Cannot find a suitable physical device")]
NoDevice,
#[error("String conversion error: {0}")]
StringConversionError(#[from] std::ffi::FromBytesUntilNulError),
#[error("Profile does not support NV12 texture format")]
NoNV12ProfileSupport,
}
#[derive(thiserror::Error, Debug)]
pub enum VulkanCommonError {
#[error("Vulkan error: {0}")]
VkError(#[from] vk::Result),
#[error("Cannot find a queue with index {0}")]
NoQueue(usize),
#[error("Memory copy requested to a buffer that is not set up for receiving input")]
UploadToImproperBuffer,
#[error("A slot in the Decoded Pictures Buffer was requested, but all slots are taken")]
NoFreeSlotsInDpb,
#[error("DPB can have at most 32 slots, {0} was requested")]
DpbTooLong(u32),
#[error("Tried to wait for an unsignaled semaphore value")]
SemaphoreWaitOnUnsignaledValue,
#[error("Tried to register {0:x?} as a new image, while it already exists")]
RegisteredNewImageTwice(ImageKey),
#[error("Tried to access state of image {0:x?}, which does not exist")]
TriedToAccessNonexistentImageState(ImageKey),
#[error("Tried to unregister image {0:x?} that was not registered")]
UnregisteredNonexistentImage(ImageKey),
#[error("Unsupported image aspect: {0:?}")]
UnsupportedImageAspect(vk::ImageAspectFlags),
}
pub struct EncodedInputChunk<'a> {
pub data: &'a [u8],
pub pts: Option<u64>,
}
#[non_exhaustive]
pub enum DecoderEvent<'a> {
DecodeChunk(EncodedInputChunk<'a>),
SignalFrameEnd,
SignalDataLoss,
Flush,
}
pub struct EncodedOutputChunk<T> {
pub data: T,
pub pts: Option<u64>,
pub is_keyframe: bool,
}
pub struct InputFrame<T> {
pub data: T,
pub pts: Option<u64>,
}
pub struct FrameMetadata {
pub pts: Option<u64>,
pub color_space: ColorSpace,
pub color_range: ColorRange,
}
pub struct OutputFrame<T> {
pub data: T,
pub metadata: FrameMetadata,
}
pub struct RawFrameData {
pub frame: Vec<u8>,
pub width: u32,
pub height: u32,
}
pub struct BytesDecoder {
pub(crate) vulkan_decoder: VulkanDecoder<'static>,
pub(crate) parser: H264Parser,
pub(crate) reference_ctx: ReferenceContext,
pub(crate) frame_sorter: FrameSorter<RawFrameData>,
}
impl BytesDecoder {
pub fn decode(
&mut self,
frame: EncodedInputChunk<'_>,
) -> Result<Vec<OutputFrame<RawFrameData>>, DecoderError> {
self.process_event(DecoderEvent::DecodeChunk(frame))
}
pub fn flush(&mut self) -> Result<Vec<OutputFrame<RawFrameData>>, DecoderError> {
self.process_event(DecoderEvent::Flush)
}
pub fn process_event(
&mut self,
event: DecoderEvent<'_>,
) -> Result<Vec<OutputFrame<RawFrameData>>, DecoderError> {
match event {
DecoderEvent::DecodeChunk(chunk) => {
let nalus = self.parser.parse(chunk.data, chunk.pts)?;
self.decode_access_units(nalus)
}
DecoderEvent::SignalFrameEnd => {
let access_units = self.parser.flush()?;
self.decode_access_units(access_units)
}
DecoderEvent::SignalDataLoss => {
self.reference_ctx.mark_missed_frames();
Ok(Vec::new())
}
DecoderEvent::Flush => {
let access_units = self.parser.flush()?;
let mut frames = self.decode_access_units(access_units)?;
frames.append(&mut self.frame_sorter.flush());
Ok(frames)
}
}
}
fn decode_access_units(
&mut self,
access_units: Vec<AccessUnit>,
) -> Result<Vec<OutputFrame<RawFrameData>>, DecoderError> {
let instructions = compile_to_decoder_instructions(&mut self.reference_ctx, access_units)?;
let unsorted_frames = self.vulkan_decoder.decode_to_bytes(&instructions)?;
let sorted_frames = self.frame_sorter.put_frames(unsorted_frames);
Ok(sorted_frames)
}
}
pub struct BytesEncoder {
pub(crate) vulkan_encoder: VulkanEncoder<'static>,
}
impl BytesEncoder {
pub fn encode(
&mut self,
frame: &InputFrame<RawFrameData>,
force_keyframe: bool,
) -> Result<EncodedOutputChunk<Vec<u8>>, VulkanEncoderError> {
self.vulkan_encoder.encode_bytes(frame, force_keyframe)
}
pub fn sps(&self) -> Result<Vec<u8>, VulkanEncoderError> {
self.vulkan_encoder.stream_parameters(true, false)
}
pub fn pps(&self) -> Result<Vec<u8>, VulkanEncoderError> {
self.vulkan_encoder.stream_parameters(false, true)
}
}