mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-08 19:33:07 +00:00
video: decoder: vaapi: port the VAAPI backend to cros-codecs
Port the VAAPI backend to the new cros-codecs crate. This crate now contains all codec related code and is independent from the rest of the CrosVM code. BUG=b:214478588 TEST="cargo test --package devices --lib --features video-decoder --features vaapi -- virtio::video::decoder::backend::vaapi::tests::test_get_capabilities --include-ignored" Change-Id: Id207c53c0c4200e03ce8793d7c37cb5fbe808829 Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3875044 Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org> Reviewed-by: Alexandre Courbot <acourbot@chromium.org> Commit-Queue: Alexandre Courbot <acourbot@chromium.org>
This commit is contained in:
parent
42bdf1de57
commit
3399026503
20 changed files with 234 additions and 3430 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -637,6 +637,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"chrono",
|
||||
"crc32fast",
|
||||
"cros-codecs",
|
||||
"cros_async",
|
||||
"cros_tracing",
|
||||
"crosvm_cli",
|
||||
|
@ -690,7 +691,6 @@ dependencies = [
|
|||
"vm_control",
|
||||
"vm_memory",
|
||||
"vmm_vhost",
|
||||
"vp8",
|
||||
"win_util",
|
||||
"winapi",
|
||||
]
|
||||
|
@ -2086,15 +2086,6 @@ dependencies = [
|
|||
"tube_transporter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vp8"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
|
|
|
@ -72,7 +72,7 @@ members = [
|
|||
"media/ffmpeg",
|
||||
"media/libva",
|
||||
"media/libvda",
|
||||
"media/vp8",
|
||||
"media/cros-codecs",
|
||||
"net_sys",
|
||||
"net_util",
|
||||
"power_monitor",
|
||||
|
|
|
@ -15,7 +15,7 @@ gpu = ["gpu_display"]
|
|||
libvda-stub = ["libvda/libvda-stub"]
|
||||
tpm = ["tpm2"]
|
||||
usb = []
|
||||
vaapi = ["libva", "vp8", "downcast-rs", "crc32fast"]
|
||||
vaapi = ["libva", "cros-codecs/vaapi", "downcast-rs", "crc32fast"]
|
||||
video-decoder = []
|
||||
video-encoder = []
|
||||
minigbm = ["rutabaga_gfx/minigbm"]
|
||||
|
@ -41,6 +41,7 @@ cfg-if = "1.0.0"
|
|||
chrono = "*"
|
||||
crc32fast = { version = "1.2.1", optional = true }
|
||||
cros_async = { path = "../cros_async" }
|
||||
cros-codecs = { path = "../media/cros-codecs", optional = true }
|
||||
crosvm_cli = { path = "../crosvm_cli" }
|
||||
data_model = { path = "../common/data_model" }
|
||||
dbus = { version = "0.9", optional = true }
|
||||
|
@ -81,7 +82,6 @@ vmm_vhost = { path = "../third_party/vmm_vhost", features = ["vmm", "device", "v
|
|||
virtio_sys = { path = "../virtio_sys" }
|
||||
vm_control = { path = "../vm_control" }
|
||||
vm_memory = { path = "../vm_memory" }
|
||||
vp8 = { path = "../media/vp8", optional = true }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
fuse = {path = "../fuse" }
|
||||
|
|
|
@ -4,9 +4,7 @@
|
|||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use std::any::Any;
|
||||
use std::borrow::Borrow;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::btree_map::Entry;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::VecDeque;
|
||||
|
@ -17,14 +15,10 @@ use anyhow::anyhow;
|
|||
use anyhow::Result;
|
||||
use base::MappedRegion;
|
||||
use base::MemoryMappingArena;
|
||||
use libva::Config;
|
||||
use libva::Context;
|
||||
use cros_codecs::decoders::DynDecodedHandle;
|
||||
use cros_codecs::decoders::VideoDecoder;
|
||||
use cros_codecs::DecodedFormat;
|
||||
use libva::Display;
|
||||
use libva::Image;
|
||||
use libva::Picture;
|
||||
use libva::PictureSync;
|
||||
use libva::Surface;
|
||||
use libva::UsageHint;
|
||||
|
||||
use crate::virtio::video::decoder::Capability;
|
||||
use crate::virtio::video::decoder::DecoderBackend;
|
||||
|
@ -45,108 +39,6 @@ use crate::virtio::video::resource::GuestResourceHandle;
|
|||
use crate::virtio::video::utils::EventQueue;
|
||||
use crate::virtio::video::utils::OutputQueue;
|
||||
|
||||
mod vp8;
|
||||
|
||||
/// A surface pool handle to reduce the number of costly Surface allocations.
|
||||
#[derive(Clone)]
|
||||
pub struct SurfacePoolHandle {
|
||||
surfaces: Rc<RefCell<VecDeque<Surface>>>,
|
||||
current_resolution: Resolution,
|
||||
}
|
||||
|
||||
impl SurfacePoolHandle {
|
||||
/// Creates a new pool
|
||||
pub fn new(surfaces: Vec<Surface>, resolution: Resolution) -> Self {
|
||||
Self {
|
||||
surfaces: Rc::new(RefCell::new(VecDeque::from(surfaces))),
|
||||
current_resolution: resolution,
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the current resolution for the pool
|
||||
pub fn current_resolution(&self) -> &Resolution {
|
||||
&self.current_resolution
|
||||
}
|
||||
|
||||
/// Sets the current resolution for the pool
|
||||
pub fn set_current_resolution(&mut self, resolution: Resolution) {
|
||||
self.current_resolution = resolution;
|
||||
}
|
||||
|
||||
/// Adds a new surface to the pool
|
||||
pub fn add_surface(&mut self, surface: Surface) {
|
||||
self.surfaces.borrow_mut().push_back(surface)
|
||||
}
|
||||
|
||||
/// Gets a free surface from the pool
|
||||
pub fn get_surface(&mut self) -> Result<Surface> {
|
||||
let mut vec = self.surfaces.borrow_mut();
|
||||
vec.pop_front().ok_or(anyhow!("Out of surfaces"))
|
||||
}
|
||||
|
||||
/// Drops all surfaces from the pool
|
||||
pub fn drop_surfaces(&mut self) {
|
||||
self.surfaces = Default::default();
|
||||
}
|
||||
}
|
||||
|
||||
/// A decoded frame handle.
|
||||
#[derive(Clone)]
|
||||
pub struct DecodedFrameHandle {
|
||||
/// The actual picture backing the handle.
|
||||
picture: Option<Rc<RefCell<Picture<PictureSync>>>>,
|
||||
/// The bitstream header parsed for this frame
|
||||
header: Rc<dyn Any>,
|
||||
/// The decoder resolution when this frame was processed. Not all codecs
|
||||
/// send resolution data in every frame header.
|
||||
resolution: Resolution,
|
||||
/// A handle to the surface pool.
|
||||
surface_pool: SurfacePoolHandle,
|
||||
}
|
||||
|
||||
impl DecodedFrameHandle {
|
||||
/// Creates a new handle
|
||||
pub fn new(
|
||||
picture: Rc<RefCell<Picture<PictureSync>>>,
|
||||
header: Rc<dyn Any>,
|
||||
resolution: Resolution,
|
||||
surface_pool: SurfacePoolHandle,
|
||||
) -> Self {
|
||||
Self {
|
||||
picture: Some(picture),
|
||||
header,
|
||||
resolution,
|
||||
surface_pool,
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves a reference into the picture backing the handle
|
||||
pub fn picture(&self) -> Rc<RefCell<Picture<PictureSync>>> {
|
||||
Rc::clone(self.picture.as_ref().unwrap())
|
||||
}
|
||||
|
||||
// Returns the resolution when this frame was processed
|
||||
pub fn resolution(&self) -> &Resolution {
|
||||
&self.resolution
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DecodedFrameHandle {
|
||||
fn drop(&mut self) {
|
||||
if let Ok(picture) = Rc::try_unwrap(self.picture.take().unwrap()) {
|
||||
let pool = &mut self.surface_pool;
|
||||
|
||||
// Only retrieve if the resolutions match, otherwise let the stale Surface drop.
|
||||
if *pool.current_resolution() == self.resolution {
|
||||
// Retrieve if not currently used by another field.
|
||||
if let Ok(surface) = picture.into_inner().take_surface() {
|
||||
pool.add_surface(surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of params returned when a dynamic resolution change is found in the
|
||||
/// bitstream.
|
||||
pub struct DrcParams {
|
||||
|
@ -160,6 +52,28 @@ pub struct DrcParams {
|
|||
visible_rect: Rect,
|
||||
}
|
||||
|
||||
impl TryFrom<DecodedFormat> for Format {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: DecodedFormat) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
DecodedFormat::NV12 => Ok(Format::NV12),
|
||||
DecodedFormat::I420 => Err(anyhow!("Unsupported format")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Format> for DecodedFormat {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: Format) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Format::NV12 => Ok(DecodedFormat::NV12),
|
||||
_ => Err(anyhow!("Unsupported format")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<libva::VAProfile::Type> for Profile {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
|
@ -185,52 +99,6 @@ impl TryFrom<libva::VAProfile::Type> for Profile {
|
|||
}
|
||||
}
|
||||
|
||||
/// State of the input stream, which can be either unparsed (we don't know the stream properties
|
||||
/// yet) or parsed (we know the stream properties and are ready to decode).
|
||||
pub enum StreamMetadataState {
|
||||
/// The metadata for the current stream has not yet been parsed.
|
||||
Unparsed { display: Rc<Display> },
|
||||
|
||||
/// The metadata for the current stream has been parsed and a suitable
|
||||
/// VAContext has been created to accomodate it.
|
||||
Parsed {
|
||||
/// A VAContext from which we can decode from.
|
||||
context: Rc<Context>,
|
||||
/// The VAConfig that created the context.
|
||||
config: Config,
|
||||
/// A pool of surfaces. We reuse surfaces as they are expensive to allocate.
|
||||
surface_pool: SurfacePoolHandle,
|
||||
},
|
||||
}
|
||||
|
||||
impl StreamMetadataState {
|
||||
fn display(&self) -> Rc<libva::Display> {
|
||||
match self {
|
||||
StreamMetadataState::Unparsed { display } => Rc::clone(display),
|
||||
StreamMetadataState::Parsed { context, .. } => context.display(),
|
||||
}
|
||||
}
|
||||
|
||||
fn context(&self) -> Result<Rc<libva::Context>> {
|
||||
match self {
|
||||
StreamMetadataState::Unparsed { .. } => Err(anyhow!("Stream metadata not parsed yet")),
|
||||
StreamMetadataState::Parsed { context, .. } => Ok(Rc::clone(context)),
|
||||
}
|
||||
}
|
||||
|
||||
fn surface_pool(&self) -> Result<SurfacePoolHandle> {
|
||||
match self {
|
||||
StreamMetadataState::Unparsed { .. } => Err(anyhow!("Invalid state")),
|
||||
StreamMetadataState::Parsed { surface_pool, .. } => Ok(surface_pool.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_surface(&mut self) -> Result<Surface> {
|
||||
let mut surface_pool = self.surface_pool()?;
|
||||
surface_pool.get_surface()
|
||||
}
|
||||
}
|
||||
|
||||
/// The state for the output queue containing the buffers that will receive the
|
||||
/// decoded data.
|
||||
enum OutputQueueState {
|
||||
|
@ -550,12 +418,12 @@ pub struct Resolution {
|
|||
/// A decoder session for the libva backend
|
||||
pub struct VaapiDecoderSession {
|
||||
/// The implementation for the codec specific logic.
|
||||
codec: Box<dyn VaapiCodec>,
|
||||
codec: Box<dyn VideoDecoder>,
|
||||
/// The state for the output queue. Updated when `set_output_buffer_count`
|
||||
/// is called or when we detect a dynamic resolution change.
|
||||
output_queue_state: OutputQueueState,
|
||||
/// Queue containing decoded pictures.
|
||||
ready_queue: VecDeque<DecodedFrameHandle>,
|
||||
ready_queue: VecDeque<Box<dyn DynDecodedHandle>>,
|
||||
/// The event queue we can use to signal new events.
|
||||
event_queue: EventQueue<DecoderEvent>,
|
||||
/// Whether the decoder is currently flushing.
|
||||
|
@ -607,25 +475,6 @@ impl<T: Borrow<U>, U: BufferHandle> AsMut<[u8]> for BufferMapping<T, U> {
|
|||
}
|
||||
|
||||
impl VaapiDecoderSession {
|
||||
/// Create the `num_surfaces` surfaces for a combination of `width`,
|
||||
/// `height` and `rt_format`.
|
||||
fn create_surfaces(
|
||||
display: Rc<Display>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
rt_format: u32,
|
||||
num_surfaces: usize,
|
||||
) -> Result<Vec<Surface>> {
|
||||
display.create_surfaces(
|
||||
rt_format,
|
||||
Some(libva::constants::VA_FOURCC_NV12), // NV12 is hardcoded for now
|
||||
width,
|
||||
height,
|
||||
Some(UsageHint::USAGE_HINT_DECODER),
|
||||
num_surfaces as u32,
|
||||
)
|
||||
}
|
||||
|
||||
fn change_resolution(&mut self, new_params: DrcParams) -> Result<()> {
|
||||
// Ask the client for new buffers.
|
||||
self.event_queue
|
||||
|
@ -647,77 +496,8 @@ impl VaapiDecoderSession {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Copies `src` into `dst` as NV12, removing any extra padding.
|
||||
fn nv12_copy(
|
||||
mut src: &[u8],
|
||||
mut dst: &mut [u8],
|
||||
width: u32,
|
||||
height: u32,
|
||||
strides: [u32; 3],
|
||||
offsets: [u32; 3],
|
||||
) {
|
||||
let width = width.try_into().unwrap();
|
||||
let height = height.try_into().unwrap();
|
||||
let data = src;
|
||||
|
||||
// Copy luma
|
||||
for _ in 0..height {
|
||||
dst[..width].copy_from_slice(&src[..width]);
|
||||
dst = &mut dst[width..];
|
||||
src = &src[strides[0] as usize..];
|
||||
}
|
||||
|
||||
// Advance to the offset of the chroma plane
|
||||
let mut src = &data[offsets[1] as usize..];
|
||||
|
||||
// Copy chroma
|
||||
for _ in 0..height / 2 {
|
||||
dst[..width].copy_from_slice(&src[..width]);
|
||||
dst = &mut dst[width..];
|
||||
src = &src[strides[1_usize] as usize..];
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy the decoded `image` into `output_buffer`, removing any extra
|
||||
/// padding. This is hardcoded to NV12 for now.
|
||||
fn copy_image_to_output(image: &Image, output_buffer: &mut GuestResource) -> Result<()> {
|
||||
let va_img = image.image();
|
||||
|
||||
if va_img.format.fourcc != libva::constants::VA_FOURCC_NV12 {
|
||||
panic!("Unsupported format")
|
||||
}
|
||||
|
||||
// Get a mapping from the start of the buffer to the size of the
|
||||
// underlying decoded data in the Image.
|
||||
let mut output_map: BufferMapping<_, GuestResourceHandle> = BufferMapping::new(
|
||||
&mut output_buffer.handle,
|
||||
0,
|
||||
usize::from(va_img.width) * usize::from(va_img.height) * 3 / 2,
|
||||
)?;
|
||||
|
||||
let output_bytes = output_map.as_mut();
|
||||
|
||||
let decoded_bytes = image.as_ref();
|
||||
|
||||
VaapiDecoderSession::nv12_copy(
|
||||
decoded_bytes,
|
||||
output_bytes,
|
||||
u32::from(va_img.width),
|
||||
u32::from(va_img.height),
|
||||
va_img.pitches,
|
||||
va_img.offsets,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Copy raw decoded data from `image` into the output buffer
|
||||
pub fn output_picture(
|
||||
&mut self,
|
||||
decoded_frame: DecodedFrameHandle,
|
||||
resolution: Resolution,
|
||||
image_format: &libva::VAImageFormat,
|
||||
) -> Result<bool> {
|
||||
pub fn output_picture(&mut self, decoded_frame: &dyn DynDecodedHandle) -> Result<bool> {
|
||||
let output_queue = self.output_queue_state.output_queue_mut()?;
|
||||
|
||||
// Output buffer to be used.
|
||||
|
@ -728,27 +508,29 @@ impl VaapiDecoderSession {
|
|||
}
|
||||
};
|
||||
|
||||
let timestamp = RefCell::borrow(&decoded_frame.picture()).timestamp();
|
||||
let picture = decoded_frame.picture();
|
||||
let mut picture = picture.borrow_mut();
|
||||
let mapped_resolution = decoded_frame
|
||||
.dyn_picture_mut()
|
||||
.dyn_mappable_handle_mut()
|
||||
.mapped_resolution()?;
|
||||
|
||||
// Get the associated VAImage, which will map the
|
||||
// VASurface onto our address space.
|
||||
let image = Image::new(
|
||||
&mut picture,
|
||||
*image_format,
|
||||
resolution.width,
|
||||
resolution.height,
|
||||
false,
|
||||
let display_resolution = decoded_frame.display_resolution();
|
||||
|
||||
// Get a mapping from the start of the buffer to the size of the
|
||||
// underlying decoded data in the Image.
|
||||
let mut output_map: BufferMapping<_, GuestResourceHandle> = BufferMapping::new(
|
||||
&mut output_buffer.handle,
|
||||
0,
|
||||
mapped_resolution.width as usize * mapped_resolution.height as usize * 3 / 2,
|
||||
)?;
|
||||
|
||||
VaapiDecoderSession::copy_image_to_output(&image, output_buffer)?;
|
||||
let output_bytes = output_map.as_mut();
|
||||
|
||||
// The actual width and height. Note that The width and height fields
|
||||
// returned in the VAImage structure may get enlarged for some YUV
|
||||
// formats.
|
||||
let width = i32::from(image.image().width);
|
||||
let height = i32::from(image.image().height);
|
||||
decoded_frame
|
||||
.dyn_picture_mut()
|
||||
.dyn_mappable_handle_mut()
|
||||
.read(output_bytes)?;
|
||||
|
||||
let timestamp = decoded_frame.timestamp();
|
||||
let picture_buffer_id = picture_buffer_id as i32;
|
||||
|
||||
// Say that we are done decoding this picture.
|
||||
|
@ -759,8 +541,8 @@ impl VaapiDecoderSession {
|
|||
visible_rect: Rect {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: width as i32,
|
||||
bottom: height as i32,
|
||||
right: display_resolution.width as i32,
|
||||
bottom: display_resolution.height as i32,
|
||||
},
|
||||
})
|
||||
.map_err(|e| {
|
||||
|
@ -771,17 +553,8 @@ impl VaapiDecoderSession {
|
|||
}
|
||||
|
||||
fn drain_ready_queue(&mut self) -> Result<()> {
|
||||
let image_format = match self.codec.va_image_fmt() {
|
||||
Some(image_fmt) => *image_fmt,
|
||||
// No image format currently set means we have no output to drain.
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
while let Some(decoded_frame) = self.ready_queue.pop_front() {
|
||||
let resolution = *decoded_frame.resolution();
|
||||
|
||||
let outputted =
|
||||
self.output_picture(decoded_frame.clone(), resolution, &image_format)?;
|
||||
let outputted = self.output_picture(decoded_frame.as_ref())?;
|
||||
if !outputted {
|
||||
self.ready_queue.push_front(decoded_frame);
|
||||
break;
|
||||
|
@ -791,45 +564,6 @@ impl VaapiDecoderSession {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Convenience function to get the test NV12 result. This can be used to,
|
||||
/// e.g.: dump it to disk or compute a CRC32
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)]
|
||||
fn get_test_nv12<T: Fn(&[u8]) -> U, U>(
|
||||
display: Rc<Display>,
|
||||
picture: Rc<RefCell<Picture<PictureSync>>>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
action: T,
|
||||
) -> U {
|
||||
let mut picture = picture.borrow_mut();
|
||||
|
||||
let image_fmts = display.query_image_formats().unwrap();
|
||||
let image_fmt = image_fmts
|
||||
.into_iter()
|
||||
.find(|f| f.fourcc == libva::constants::VA_FOURCC_NV12)
|
||||
.expect("No valid VAImageFormat found for NV12");
|
||||
|
||||
// Get the associated VAImage, which will map the
|
||||
// VASurface onto our address space.
|
||||
let image = Image::new(&mut picture, image_fmt, width, height, false).unwrap();
|
||||
|
||||
let va_img = image.image();
|
||||
let mut out: Vec<u8> =
|
||||
vec![0; usize::from(va_img.width) * usize::from(va_img.height) * 3 / 2];
|
||||
|
||||
VaapiDecoderSession::nv12_copy(
|
||||
image.as_ref(),
|
||||
&mut out,
|
||||
u32::from(va_img.width),
|
||||
u32::from(va_img.height),
|
||||
va_img.pitches,
|
||||
va_img.offsets,
|
||||
);
|
||||
|
||||
action(&out)
|
||||
}
|
||||
|
||||
fn try_emit_flush_completed(&mut self) -> Result<()> {
|
||||
let num_remaining = self.ready_queue.len();
|
||||
|
||||
|
@ -848,14 +582,58 @@ impl VaapiDecoderSession {
|
|||
}
|
||||
|
||||
impl DecoderSession for VaapiDecoderSession {
|
||||
fn set_output_parameters(&mut self, buffer_count: usize, format: Format) -> VideoResult<()> {
|
||||
fn set_output_parameters(&mut self, buffer_count: usize, _: Format) -> VideoResult<()> {
|
||||
let output_queue_state = &mut self.output_queue_state;
|
||||
|
||||
// This logic can still be improved, in particular it needs better
|
||||
// support at the virtio-video protocol level.
|
||||
//
|
||||
// We must ensure that set_output_parameters is only called after we are
|
||||
// sure that we have processed some stream metadata, which currently is
|
||||
// not the case. In particular, the {SET|GET}_PARAMS logic currently
|
||||
// takes place *before* we had a chance to parse any stream metadata at
|
||||
// all.
|
||||
//
|
||||
// This can lead to a situation where we accept a format (say, NV12),
|
||||
// but then discover we are unable to decode it after processing some
|
||||
// buffers (because the stream indicates that the bit depth is 10, for
|
||||
// example). Note that there is no way to reject said stream as of right
|
||||
// now unless we hardcode NV12 in cros-codecs itself.
|
||||
//
|
||||
// Nevertheless, the support is already in place in cros-codecs: the
|
||||
// decoders will queue buffers until they read some metadata. At this
|
||||
// point, it will allow for the negotiation of the decoded format until
|
||||
// a new call to decode() is made. At the crosvm level, we can use this
|
||||
// window of time to try different decoded formats with .try_format().
|
||||
//
|
||||
// For now, we accept the default format chosen by cros-codecs instead.
|
||||
// In practice, this means NV12 if it the stream can be decoded into
|
||||
// NV12 and if the hardware can do so.
|
||||
|
||||
match output_queue_state {
|
||||
OutputQueueState::AwaitingBufferCount | OutputQueueState::Drc => {
|
||||
self.codec
|
||||
.set_raw_fmt(format)
|
||||
.map_err(VideoError::BackendFailure)?;
|
||||
// Accept the default format chosen by cros-codecs instead.
|
||||
//
|
||||
// if let Some(backend_format) = self.backend.backend().format() {
|
||||
// let backend_format = Format::try_from(backend_format);
|
||||
|
||||
// let format_matches = match backend_format {
|
||||
// Ok(backend_format) => backend_format != format,
|
||||
// Err(_) => false,
|
||||
// };
|
||||
|
||||
// if !format_matches {
|
||||
// let format =
|
||||
// DecodedFormat::try_from(format).map_err(VideoError::BackendFailure)?;
|
||||
|
||||
// self.backend.backend().try_format(format).map_err(|e| {
|
||||
// VideoError::BackendFailure(anyhow!(
|
||||
// "Failed to set the codec backend format: {}",
|
||||
// e
|
||||
// ))
|
||||
// })?;
|
||||
// }
|
||||
// }
|
||||
|
||||
*output_queue_state = OutputQueueState::Decoding {
|
||||
output_queue: OutputQueue::new(buffer_count),
|
||||
|
@ -877,12 +655,19 @@ impl DecoderSession for VaapiDecoderSession {
|
|||
offset: u32,
|
||||
bytes_used: u32,
|
||||
) -> VideoResult<()> {
|
||||
let frames = self.codec.decode(timestamp, &resource, offset, bytes_used);
|
||||
let bitstream_map: BufferMapping<_, GuestResourceHandle> = BufferMapping::new(
|
||||
resource,
|
||||
offset.try_into().unwrap(),
|
||||
bytes_used.try_into().unwrap(),
|
||||
)
|
||||
.map_err(|e| VideoError::BackendFailure(anyhow!(e)))?;
|
||||
|
||||
let frames = self.codec.decode(timestamp, &bitstream_map);
|
||||
|
||||
match frames {
|
||||
Ok(frames) => {
|
||||
self.event_queue
|
||||
.queue_event(DecoderEvent::NotifyEndOfBitstreamBuffer(resource_id))
|
||||
.queue_event(DecoderEvent::NotifyEndOfBitstreamBuffer(timestamp as u32))
|
||||
.map_err(|e| {
|
||||
VideoError::BackendFailure(anyhow!(
|
||||
"Can't queue the NotifyEndOfBitstream event {}",
|
||||
|
@ -890,8 +675,22 @@ impl DecoderSession for VaapiDecoderSession {
|
|||
))
|
||||
})?;
|
||||
|
||||
if let Some(params) = self.codec.drc() {
|
||||
self.change_resolution(params)
|
||||
if self.codec.negotiation_possible() {
|
||||
let resolution = self.codec.backend().coded_resolution().unwrap();
|
||||
|
||||
let drc_params = DrcParams {
|
||||
min_num_buffers: self.codec.backend().num_resources_total(),
|
||||
width: resolution.width,
|
||||
height: resolution.height,
|
||||
visible_rect: Rect {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: resolution.width as i32,
|
||||
bottom: resolution.height as i32,
|
||||
},
|
||||
};
|
||||
|
||||
self.change_resolution(drc_params)
|
||||
.map_err(VideoError::BackendFailure)?;
|
||||
}
|
||||
|
||||
|
@ -919,7 +718,7 @@ impl DecoderSession for VaapiDecoderSession {
|
|||
))
|
||||
})?;
|
||||
|
||||
Err(VideoError::BackendFailure(e))
|
||||
Err(VideoError::BackendFailure(anyhow!(e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -928,7 +727,11 @@ impl DecoderSession for VaapiDecoderSession {
|
|||
self.flushing = true;
|
||||
|
||||
// Retrieve ready frames from the codec, if any.
|
||||
let pics = self.codec.flush().map_err(VideoError::BackendFailure)?;
|
||||
let pics = self
|
||||
.codec
|
||||
.flush()
|
||||
.map_err(|e| VideoError::BackendFailure(anyhow!(e)))?;
|
||||
|
||||
self.ready_queue.extend(pics);
|
||||
|
||||
self.drain_ready_queue()
|
||||
|
@ -952,10 +755,57 @@ impl DecoderSession for VaapiDecoderSession {
|
|||
})?;
|
||||
|
||||
let display = Rc::new(Display::open().map_err(VideoError::BackendFailure)?);
|
||||
let codec = match self.coded_format {
|
||||
Format::VP8 => Box::new(
|
||||
vp8::Vp8Codec::new(display).map_err(|e| VideoError::BackendFailure(anyhow!(e)))?,
|
||||
),
|
||||
let codec: Box<dyn VideoDecoder> = match self.coded_format {
|
||||
Format::VP8 => {
|
||||
let backend = Box::new(
|
||||
cros_codecs::decoders::vp8::backends::stateless::vaapi::Backend::new(
|
||||
Rc::clone(&display),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
Box::new(
|
||||
cros_codecs::decoders::vp8::decoder::Decoder::new(
|
||||
backend,
|
||||
cros_codecs::decoders::BlockingMode::NonBlocking,
|
||||
)
|
||||
.map_err(|e| VideoError::BackendFailure(anyhow!(e)))?,
|
||||
)
|
||||
}
|
||||
|
||||
Format::VP9 => {
|
||||
let backend = Box::new(
|
||||
cros_codecs::decoders::vp9::backends::stateless::vaapi::Backend::new(
|
||||
Rc::clone(&display),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
Box::new(
|
||||
cros_codecs::decoders::vp9::decoder::Decoder::new(
|
||||
backend,
|
||||
cros_codecs::decoders::BlockingMode::NonBlocking,
|
||||
)
|
||||
.map_err(|e| VideoError::BackendFailure(anyhow!(e)))?,
|
||||
)
|
||||
}
|
||||
|
||||
Format::H264 => {
|
||||
let backend = Box::new(
|
||||
cros_codecs::decoders::h264::backends::stateless::vaapi::Backend::new(
|
||||
Rc::clone(&display),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
Box::new(
|
||||
cros_codecs::decoders::h264::decoder::Decoder::new(
|
||||
backend,
|
||||
cros_codecs::decoders::BlockingMode::NonBlocking,
|
||||
)
|
||||
.map_err(|e| VideoError::BackendFailure(anyhow!(e)))?,
|
||||
)
|
||||
}
|
||||
|
||||
_ => return Err(VideoError::InvalidFormat),
|
||||
};
|
||||
|
||||
|
@ -1062,10 +912,56 @@ impl DecoderBackend for VaapiDecoder {
|
|||
fn new_session(&mut self, format: Format) -> VideoResult<Self::Session> {
|
||||
let display = Rc::new(Display::open().map_err(VideoError::BackendFailure)?);
|
||||
|
||||
let codec = match format {
|
||||
Format::VP8 => Box::new(
|
||||
vp8::Vp8Codec::new(display).map_err(|e| VideoError::BackendFailure(anyhow!(e)))?,
|
||||
),
|
||||
let codec: Box<dyn VideoDecoder> = match format {
|
||||
Format::VP8 => {
|
||||
let backend = Box::new(
|
||||
cros_codecs::decoders::vp8::backends::stateless::vaapi::Backend::new(
|
||||
Rc::clone(&display),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
Box::new(
|
||||
cros_codecs::decoders::vp8::decoder::Decoder::new(
|
||||
backend,
|
||||
cros_codecs::decoders::BlockingMode::NonBlocking,
|
||||
)
|
||||
.map_err(|e| VideoError::BackendFailure(anyhow!(e)))?,
|
||||
)
|
||||
}
|
||||
|
||||
Format::VP9 => {
|
||||
let backend = Box::new(
|
||||
cros_codecs::decoders::vp9::backends::stateless::vaapi::Backend::new(
|
||||
Rc::clone(&display),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
Box::new(
|
||||
cros_codecs::decoders::vp9::decoder::Decoder::new(
|
||||
backend,
|
||||
cros_codecs::decoders::BlockingMode::NonBlocking,
|
||||
)
|
||||
.map_err(|e| VideoError::BackendFailure(anyhow!(e)))?,
|
||||
)
|
||||
}
|
||||
|
||||
Format::H264 => {
|
||||
let backend = Box::new(
|
||||
cros_codecs::decoders::h264::backends::stateless::vaapi::Backend::new(
|
||||
Rc::clone(&display),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
Box::new(
|
||||
cros_codecs::decoders::h264::decoder::Decoder::new(
|
||||
backend,
|
||||
cros_codecs::decoders::BlockingMode::NonBlocking,
|
||||
)
|
||||
.map_err(|e| VideoError::BackendFailure(anyhow!(e)))?,
|
||||
)
|
||||
}
|
||||
_ => return Err(VideoError::InvalidFormat),
|
||||
};
|
||||
|
||||
|
@ -1080,74 +976,9 @@ impl DecoderBackend for VaapiDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait VaapiCodec: downcast_rs::Downcast {
|
||||
/// Decode the compressed stream contained in
|
||||
/// [`offset`..`offset`+`bytes_used`] of the shared memory in `resource`.
|
||||
/// `timestamp` is the timestamp for that part of the stream.
|
||||
/// Returns zero or more decoded pictures depending on the compressed
|
||||
/// stream, which might also be part of the codec's decoded picture buffer
|
||||
/// (DPB).
|
||||
fn decode(
|
||||
&mut self,
|
||||
timestamp: u64,
|
||||
resource: &GuestResourceHandle,
|
||||
offset: u32,
|
||||
bytes_used: u32,
|
||||
) -> Result<Vec<DecodedFrameHandle>>;
|
||||
|
||||
/// Flush the decoder i.e. finish processing all queued decode requests and
|
||||
/// emit frames for them.
|
||||
fn flush(&mut self) -> Result<Vec<DecodedFrameHandle>>;
|
||||
|
||||
/// Returns the current VA image format
|
||||
fn va_image_fmt(&self) -> &Option<libva::VAImageFormat>;
|
||||
|
||||
/// Set the raw picture format.
|
||||
fn set_raw_fmt(&mut self, format: Format) -> Result<()>;
|
||||
|
||||
/// Whether the codec has encountered a dynamic resolution change, i.e.:
|
||||
/// Whether there were changes in coded resolution (OUTPUT width and
|
||||
/// height), in the visible resolution (selection rectangles), in the
|
||||
/// minimum number of buffers needed for decoding or in bit-depth of the
|
||||
/// bitstream. This function will be called at every frame by the session.
|
||||
fn drc(&mut self) -> Option<DrcParams>;
|
||||
}
|
||||
downcast_rs::impl_downcast!(VaapiCodec); // Used in unit tests.
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use base::FromRawDescriptor;
|
||||
use base::MemoryMappingBuilder;
|
||||
use base::SafeDescriptor;
|
||||
use base::SharedMemory;
|
||||
|
||||
use super::*;
|
||||
use crate::virtio::video::resource::GuestMemArea;
|
||||
use crate::virtio::video::resource::GuestMemHandle;
|
||||
|
||||
pub(crate) fn build_resource(slice: &[u8]) -> GuestResourceHandle {
|
||||
let input_shm = SharedMemory::new("", u64::try_from(slice.len()).unwrap()).unwrap();
|
||||
|
||||
let input_mapping = MemoryMappingBuilder::new(input_shm.size() as usize)
|
||||
.from_shared_memory(&input_shm)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
input_mapping
|
||||
.write_slice(slice, 0)
|
||||
.expect("Failed to write stream data into input buffer.");
|
||||
|
||||
GuestResourceHandle::GuestPages(GuestMemHandle {
|
||||
// Safe because we are taking ownership of a just-duplicated FD.
|
||||
desc: unsafe {
|
||||
SafeDescriptor::from_raw_descriptor(base::clone_descriptor(&input_shm).unwrap())
|
||||
},
|
||||
mem_areas: vec![GuestMemArea {
|
||||
offset: 0,
|
||||
length: input_shm.size() as usize,
|
||||
}],
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Ignore this test by default as it requires libva-compatible hardware.
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€עˆ<EFBFBD>ה<EFBFBD>€€€€€½<EFBFBD>ע<EFBFBD>דױ<EFBFBD><EFBFBD>€€€j~I3ײׁ<01>€€€bר<62>לג<D79C><D792>€€€µ…מ<D79E>ך<EFBFBD><D79A>€€€N†ֺ ֶ´I<C2B4>€€€¹ש<C2B9>ף<EFBFBD>€€€€€¸–ק<E28093>לא€€€€€Mn״לז€€€€€e<><65>ס<EFBFBD>€€€€€×‹ס<E280B9>לׁ<D79C><D781>€€€%tִףה<D7A3><01>€€€ּ<D6BC>ץ<EFBFBD>€€€€€ ת<C2A0>מ€€€€€€fg`׃«€€€€€˜ֻ’נ<E28099>€€€€€8‡«£ךב€€€€€.Fֲא€ל€€<01>€€€€€€€€f€€€€€€€€%€€€€€€€€€€ֶ#ם<>ֱ»¢ ‘›>ƒ-ֶ<>¬°<C2AC><C2B0><EFBFBD><EFBFBD>D/’׀•§<E280A2>¢<EFBFBD><C2A2>€•ס<E280A2><D7A1>א<EFBFBD><D790>€€€¸<E282AC>ך<D79A><E2808E><EFBFBD>ַ€€€Qcµע°¾שֺ<D7A9><D6BA>€<01>טײֵעִ<D7A2><D6B4>€cyׂתֶֹ<D6B9>ֺ€€€[£ע×»קׂ<D7A7><D782>€ָצ<D6B8>ך<EFBFBD>€€€€€m²ס<C2B2>חץ<D797><D7A5>€€€,‚ְֹֽ<D6BD><D6B0>€€€„ן<E2809E><D79F>ׁ<EFBFBD>¥€€€^ˆב<CB86><D791>¾<EFBFBD><C2BE>€€€d®ץ÷¡<C3B7>ַ€€€¶ש<C2B6>טכ€€€€€|<7C>ס<EFBFBD>דך€€€€€#Mµ<4D>ֱ׃<D6B1>ֽ€€€<01>ק<EFBFBD>לח<D79C><D797>€€€y<E282AC>כ<EFBFBD>בד<D791><D793>€€€-c¼Uֳ<55>א€€€<01><>ױ<EFBFBD>€€€€€ֻר<><D7A8>€€€€€€‰±<>א<EFBFBD>€€€€€ ר<>ֿ׀<D6BF>ְ€€€¯
^+ֱ¹€ֶ3<D6B6>€I« ¡³=§ך€_קװ·<D7B0><C2B7>€€€OZפת׃ׁ<D783><D781>€€€M`¼ֳ<01>€€ן<><D79F><EFBFBD><EFBFBD>ֽ€€€%3<><33>ִ÷€€€€€E.¾ןֹ<D79F><D6B9>ה€€€¿<><C2BF><EFBFBD>€€€€€€/¥ש<C2A5>ױ<EFBFBD>€€€€€<E282AC>|ר<><D7A8>€€€€€€n<01>€€€€€¾$זל<>€€€€€•<01>€€€€€€€€ג<>€€€€€€€€קְ<D7A7>€€€€€€€€€€€€€€€€†<><E280A0><EFBFBD>€€€€€€[‰ת<E280B0><D7AA>€€€€€€7]<5D>€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€וױ÷¿ נ¯]&_(©¸8®<»€:F—²4ר€€p‰Kַ¿E<C2BF>³’€Qm›b׃׳D®€€€
|
||||
21:¬´$²<>ֳ4<>Aֶַ.<2E>Br€AJ<41>Y·ֱ$<24>¨<EFBFBD>€G9><3E>×0s־sגױ£X<C2A3>נא€€€H––F״ֽ(«€€€52Fuz*„צ<C397>Q\#ְֻּ€€ז>R2¼ִP€€װ$$8₪;b®€ס’<>t״ױ,€ז€€Gz<47>כֽ39€€€'=ˆװ<1B>´Qנy”g®ײ†ץ€<D7A5>6T}{<7B>ֺ.fס€<D7A1>/>Tƒ¹>{ן€—€€€€€€€€E €€€€ק€€:L€€€€€€
|
|
@ -1,2 +0,0 @@
|
|||
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€עˆ<EFBFBD>ה<EFBFBD>€€€€€½<EFBFBD>ע<EFBFBD>דױ<EFBFBD><EFBFBD>€€€j~I3ײׁ<01>€€€bר<62>לג<D79C><D792>€€€µ…מ<D79E>ך<EFBFBD><D79A>€€€N†ֺ ֶ´I<C2B4>€€€¹ש<C2B9>ף<EFBFBD>€€€€€¸–ק<E28093>לא€€€€€Mn״לז€€€€€e<><65>ס<EFBFBD>€€€€€×‹ס<E280B9>לׁ<D79C><D781>€€€%tִףה<D7A3><01>€€€ּ<D6BC>ץ<EFBFBD>€€€€€ ת<C2A0>מ€€€€€€fg`׃«€€€€€˜ֻ’נ<E28099>€€€€€8‡«£ךב€€€€€.Fֲא€ל€€<01>€€€€€€€€f€€€€€€€€%€€€€€€€€€€ֶ#ם<>ֱ»¢ ‘›>ƒ-ֶ<>¬°<C2AC><C2B0><EFBFBD><EFBFBD>D/’׀•§<E280A2>¢<EFBFBD><C2A2>€•ס<E280A2><D7A1>א<EFBFBD><D790>€€€¸<E282AC>ך<D79A><E2808E><EFBFBD>ַ€€€Qcµע°¾שֺ<D7A9><D6BA>€<01>טײֵעִ<D7A2><D6B4>€cyׂתֶֹ<D6B9>ֺ€€€[£ע×»קׂ<D7A7><D782>€ָצ<D6B8>ך<EFBFBD>€€€€€m²ס<C2B2>חץ<D797><D7A5>€€€,‚ְֹֽ<D6BD><D6B0>€€€„ן<E2809E><D79F>ׁ<EFBFBD>¥€€€^ˆב<CB86><D791>¾<EFBFBD><C2BE>€€€d®ץ÷¡<C3B7>ַ€€€¶ש<C2B6>טכ€€€€€|<7C>ס<EFBFBD>דך€€€€€#Mµ<4D>ֱ׃<D6B1>ֽ€€€<01>ק<EFBFBD>לח<D79C><D797>€€€y<E282AC>כ<EFBFBD>בד<D791><D793>€€€-c¼Uֳ<55>א€€€<01><>ױ<EFBFBD>€€€€€ֻר<><D7A8>€€€€€€‰±<>א<EFBFBD>€€€€€ ר<>ֿ׀<D6BF>ְ€€€¯
^+ֱ¹€ֶ3<D6B6>€I« ¡³=§ך€_קװ·<D7B0><C2B7>€€€OZפת׃ׁ<D783><D781>€€€M`¼ֳ<01>€€ן<><D79F><EFBFBD><EFBFBD>ֽ€€€%3<><33>ִ÷€€€€€E.¾ןֹ<D79F><D6B9>ה€€€¿<><C2BF><EFBFBD>€€€€€€/¥ש<C2A5>ױ<EFBFBD>€€€€€<E282AC>|ר<><D7A8>€€€€€€n<01>€€€€€¾$זל<>€€€€€•<01>€€€€€€€€ג<>€€€€€€€€קְ<D7A7>€€€€€€€€€€€€€€€€†<><E280A0><EFBFBD>€€€€€€[‰ת<E280B0><D7AA>€€€€€€7]<5D>€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€וױ<>÷¿ נ¯]&_(©¸8®<»€:F—²4ר€€p‰Kַ¿E<C2BF>³’€Qm›b׃׳D®€€€
|
||||
21:¬´$²<>ֳ4<>Aֶַ.<2E>Br€AJ<41>Y·ֱ$<24>¨<EFBFBD>€G9><3E>×0s־sגױ£X<C2A3>נא€€€H––F״ֽ(«€€€52Fuz*„צ<C397>Q\#ְֻּ€€ז>R2¼ִP€€װ$$8₪;b®€ס’<>t״ױ,€ז€€Gz<47>כֽ39€€€'=ˆװ<1B>´Qנy<>g®ײ†ץ€<D7A5>·T}{<7B>ֺ.fס€<D7A1>/>Tƒ¹>{ן€—€€€€€€€€E €€€€ק€€:L€€€€€€
|
|
@ -1,2 +0,0 @@
|
|||
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€עˆ<EFBFBD>ה<EFBFBD>€€€€€½<EFBFBD>ע<EFBFBD>דױ<EFBFBD><EFBFBD>€€€j~I3ײׁ<01>€€€bר<62>לג<D79C><D792>€€€µ…מ<D79E>ך<EFBFBD><D79A>€€€N†ֺ ֶ´I<C2B4>€€€¹ש<C2B9>ף<EFBFBD>€€€€€¸–ק<E28093>לא€€€€€Mn״לז€€€€€e<><65>ס<EFBFBD>€€€€€×‹ס<E280B9>לׁ<D79C><D781>€€€%tִףה<D7A3><01>€€€ּ<D6BC>ץ<EFBFBD>€€€€€ ת<C2A0>מ€€€€€€fg`׃«€€€€€˜ֻ’נ<E28099>€€€€€8‡«£ךב€€€€€.Fֲא€ל€€<01>€€€€€€€€f€€€€€€€€%€€€€€€€€€€ֶ#ם<>ֱ»¢ ‘›>ƒ-ֶ<>¬°<C2AC><C2B0><EFBFBD><EFBFBD>D/’׀•§<E280A2>¢<EFBFBD><C2A2>€•ס<E280A2><D7A1>א<EFBFBD><D790>€€€¸<E282AC>ך<D79A><E2808E><EFBFBD>ַ€€€Qcµע°¾שֺ<D7A9><D6BA>€<01>טײֵעִ<D7A2><D6B4>€cyׂתֶֹ<D6B9>ֺ€€€[£ע×»קׂ<D7A7><D782>€ָצ<D6B8>ך<EFBFBD>€€€€€m²ס<C2B2>חץ<D797><D7A5>€€€,‚ְֹֽ<D6BD><D6B0>€€€„ן<E2809E><D79F>ׁ<EFBFBD>¥€€€^ˆב<CB86><D791>¾<EFBFBD><C2BE>€€€d®ץ÷¡<C3B7>ַ€€€¶ש<C2B6>טכ€€€€€|<7C>ס<EFBFBD>דך€€€€€#Mµ<4D>ֱ׃<D6B1>ֽ€€€<01>ק<EFBFBD>לח<D79C><D797>€€€y<E282AC>כ<EFBFBD>בד<D791><D793>€€€-c¼Uֳ<55>א€€€<01><>ױ<EFBFBD>€€€€€ֻר<><D7A8>€€€€€€‰±<>א<EFBFBD>€€€€€ ר<>ֿ׀<D6BF>ְ€€€¯
^+ֱ¹€ֶ3<D6B6>€I« ¡³=§ך€_קװ·<D7B0><C2B7>€€€OZפת׃ׁ<D783><D781>€€€M`¼ֳ<01>€€ן<><D79F><EFBFBD><EFBFBD>ֽ€€€%3<><33>ִ÷€€€€€E.¾ןֹ<D79F><D6B9>ה€€€¿<><C2BF><EFBFBD>€€€€€€/¥ש<C2A5>ױ<EFBFBD>€€€€€<E282AC>|ר<><D7A8>€€€€€€n<01>€€€€€¾$זל<>€€€€€•<01>€€€€€€€€ג<>€€€€€€€€קְ<D7A7>€€€€€€€€€€€€€€€€†<><E280A0><EFBFBD>€€€€€€[‰ת<E280B0><D7AA>€€€€€€7]<5D>€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€וױ<>÷¿ נ¯]&_(©¸8®<»€:F—²4ר€€p‰Kַ¿E<C2BF>³’€Qm›b׃׳D®€€€
|
||||
21:¬´$²<>ֳ4<>Aֶַ.<2E>Br€AJ<41>Y·ֱ$<24>¨<EFBFBD>€G9><3E>×0s־sגױ£X<C2A3>נא€€€H––F״ֽ(«€€€52Fuz*„צ<C397>Q\#ְֻּ€€ז>R2¼ִP€€װ$$8₪;b®€ס’<>t״ױ,€ז€€Gz<47>כֽ39€€€'=ˆװ<1B>´Qנy<>g®ײ†ץ€<D7A5>·T}{<7B>ֺ.fס€<D7A1>/>Tƒ¹>{ן€—€€€€€€€€E €€€€ק€€:L€€€€€€
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,250 +0,0 @@
|
|||
23ad177c
|
||||
1b9c8cae
|
||||
233b5afd
|
||||
e23f451d
|
||||
b3e6e470
|
||||
e204fec1
|
||||
36cf5e86
|
||||
fba3f823
|
||||
7b86762f
|
||||
7de7535c
|
||||
0e7a5291
|
||||
a8897d66
|
||||
3e0c1e91
|
||||
d7d29155
|
||||
d7316205
|
||||
810a2ae9
|
||||
92dac65f
|
||||
d323a7b8
|
||||
bca35249
|
||||
1e9ad2a6
|
||||
b6fd4f82
|
||||
6fe8fe2e
|
||||
bf949b74
|
||||
3f59a84b
|
||||
85e1a39b
|
||||
63ac1653
|
||||
ef92b037
|
||||
a775daa2
|
||||
5dc0dd88
|
||||
468bd51f
|
||||
cbb91ea3
|
||||
90b60e7b
|
||||
bf1ae070
|
||||
1c67ce82
|
||||
7ad8c84d
|
||||
6ef5edd2
|
||||
05f75839
|
||||
5ebd62ac
|
||||
d35c657f
|
||||
a1dac6fd
|
||||
0b2f6044
|
||||
734d13bb
|
||||
5679bd57
|
||||
fa199a3e
|
||||
a4a4d6d4
|
||||
6bd56dbe
|
||||
d799a86f
|
||||
227bbf58
|
||||
1541656d
|
||||
c723e6b8
|
||||
e07cc71a
|
||||
04778c4f
|
||||
fdd8b676
|
||||
8c681031
|
||||
e6847162
|
||||
8c7c211d
|
||||
5035e333
|
||||
4c5c8b3a
|
||||
77401793
|
||||
8d15d34c
|
||||
3587624d
|
||||
47307e2b
|
||||
4480cb44
|
||||
fbe55c59
|
||||
6520892e
|
||||
39df34bc
|
||||
8f8754e0
|
||||
3b08b12f
|
||||
bff1799a
|
||||
0034759b
|
||||
68861fbb
|
||||
801befe6
|
||||
c8101440
|
||||
cc5b856d
|
||||
96c1b94c
|
||||
a87e1845
|
||||
18b19080
|
||||
63e158c3
|
||||
96e5974c
|
||||
3faf3f86
|
||||
5947f01f
|
||||
ee3c1a46
|
||||
69f11a00
|
||||
2dff59fe
|
||||
d427bce6
|
||||
6bcee14f
|
||||
04a10cc5
|
||||
e3e12f43
|
||||
873d32ac
|
||||
f986a99f
|
||||
ac98dfc4
|
||||
c08f5c03
|
||||
7649d9f5
|
||||
68b76170
|
||||
7f8c6613
|
||||
433f4970
|
||||
9ec1ba95
|
||||
f7b03143
|
||||
37873456
|
||||
e2da340c
|
||||
c467fd97
|
||||
bf68a9c5
|
||||
dcece5cb
|
||||
5aa3c7d7
|
||||
9027434c
|
||||
5e4690f9
|
||||
79b59499
|
||||
3e6c0f04
|
||||
42853006
|
||||
9b761bc1
|
||||
2f2d290b
|
||||
12595217
|
||||
70482029
|
||||
770bf015
|
||||
f70adb10
|
||||
4189e078
|
||||
a4619a87
|
||||
5b2044f2
|
||||
2d162e58
|
||||
e071f345
|
||||
f845ff1f
|
||||
c41a2258
|
||||
c300cd49
|
||||
b5209b89
|
||||
51490639
|
||||
d5356f60
|
||||
a232fd4b
|
||||
0d98e5bf
|
||||
d34b3e3b
|
||||
9b951312
|
||||
b2cd5ead
|
||||
d9bfb278
|
||||
6018e793
|
||||
e8b2f310
|
||||
a8910a6c
|
||||
accee1d8
|
||||
6e51c606
|
||||
9050757f
|
||||
aa752e7b
|
||||
a4274821
|
||||
a0561066
|
||||
9258c326
|
||||
f6b66d22
|
||||
0e2f7048
|
||||
84d7bd75
|
||||
9a2b13ff
|
||||
7db691f1
|
||||
e0fd2689
|
||||
8fb24bc0
|
||||
89b201e9
|
||||
041dae30
|
||||
c8856390
|
||||
468220e4
|
||||
1371ec57
|
||||
9ddb3769
|
||||
76aa8d4c
|
||||
2e178d45
|
||||
7519b38e
|
||||
23da843f
|
||||
da24380f
|
||||
34e3b146
|
||||
42735634
|
||||
206269cc
|
||||
22ff4630
|
||||
8599f9d0
|
||||
5353b7b9
|
||||
f198b705
|
||||
27a62538
|
||||
2b6309a1
|
||||
bbed8b85
|
||||
c8c605ba
|
||||
23cc23aa
|
||||
a4b7cfab
|
||||
e8adab6b
|
||||
50308549
|
||||
82428aed
|
||||
90e1a158
|
||||
f6177648
|
||||
63f1a6bf
|
||||
53dd22fc
|
||||
e47289f0
|
||||
f0c36a34
|
||||
fcad085d
|
||||
fd925241
|
||||
32a79fc0
|
||||
047d4d80
|
||||
d31235f8
|
||||
5c46386a
|
||||
aaa9ee3c
|
||||
935a352c
|
||||
88df87ae
|
||||
e4dd9b22
|
||||
605f46fb
|
||||
087558c3
|
||||
25461a0f
|
||||
fe564aec
|
||||
1dc99d84
|
||||
7c2b1a2b
|
||||
08c433ce
|
||||
951609cb
|
||||
e69a15ee
|
||||
0be31b4a
|
||||
b0988d03
|
||||
c5c0769c
|
||||
7807a352
|
||||
925e5b37
|
||||
7dc3aaf0
|
||||
d1621353
|
||||
f1c0e356
|
||||
49a5f2d8
|
||||
2a7f52ef
|
||||
f280d5b6
|
||||
4f546dc9
|
||||
af08b467
|
||||
9612c8b7
|
||||
360aebde
|
||||
2311a9fb
|
||||
c175e073
|
||||
966537f0
|
||||
1cd52932
|
||||
cb098673
|
||||
11861fe5
|
||||
b482ec61
|
||||
a3d89823
|
||||
96fe22e6
|
||||
d28c91b1
|
||||
13ff2ba3
|
||||
998e52b7
|
||||
ae6ebd46
|
||||
20381724
|
||||
a0c7113d
|
||||
de28b72d
|
||||
a50f4d0e
|
||||
f6ac0144
|
||||
71679cf2
|
||||
f354c9d1
|
||||
6d84c275
|
||||
ca0b4570
|
||||
95138a3a
|
||||
e943fac5
|
||||
af611c9c
|
||||
d5811d81
|
||||
24fd3da7
|
||||
90ec3b70
|
||||
300659b6
|
||||
1aa57f0f
|
||||
3192b32f
|
||||
34091c37
|
||||
b7bc0a9f
|
||||
ea1f6fa7
|
File diff suppressed because it is too large
Load diff
|
@ -1,10 +0,0 @@
|
|||
[package]
|
||||
name = "vp8"
|
||||
version = "0.1.0"
|
||||
authors = ["The Chromium OS Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "*"
|
||||
bytes = "1.1.0"
|
||||
log = { version = "0", features = ["release_max_level_debug"]}
|
|
@ -1,270 +0,0 @@
|
|||
// Copyright 2022 The ChromiumOS Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/// A VP8 boolean decoder based on the implementation in Chromium and GStreamer.
|
||||
use std::convert::TryFrom;
|
||||
/// A VP8 boolean decoder based on the implementation in Chromium and GStreamer.
|
||||
use std::io::Cursor;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use anyhow::Result;
|
||||
use bytes::Buf;
|
||||
|
||||
const LOTS_OF_BITS: u32 = 0x40000000;
|
||||
const U8_BITS: usize = u8::BITS as usize;
|
||||
const BD_VALUE_SIZE: usize = std::mem::size_of::<usize>() * U8_BITS;
|
||||
|
||||
const NORM: [u8; 256] = [
|
||||
0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
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,
|
||||
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,
|
||||
];
|
||||
|
||||
/// Some bits are "encoded" with a 50/50 probability.
|
||||
const DEFAULT_PROBABILITY: u8 = 128;
|
||||
|
||||
/// The decoder state.
|
||||
#[derive(Default)]
|
||||
pub struct BoolDecoder<T> {
|
||||
data: Cursor<T>,
|
||||
range: usize,
|
||||
value: usize,
|
||||
count: isize,
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> BoolDecoder<T> {
|
||||
/// Creates a new instance.
|
||||
pub fn new(data: T) -> Self {
|
||||
Self {
|
||||
data: Cursor::new(data),
|
||||
range: 255usize,
|
||||
value: 0usize,
|
||||
count: -8,
|
||||
}
|
||||
}
|
||||
|
||||
/// Fills more bits from `data` to `value`. We shall keep at least 8 bits of
|
||||
/// the current `data` in `value`.
|
||||
fn fill(&mut self) -> Result<()> {
|
||||
let mut shift =
|
||||
(BD_VALUE_SIZE as isize - U8_BITS as isize - (self.count + U8_BITS as isize)) as i32;
|
||||
let bits_left = (self.data.remaining() * U8_BITS) as i32;
|
||||
let x = shift + U8_BITS as i32 - bits_left;
|
||||
let mut loop_end = 0;
|
||||
|
||||
if x >= 0 {
|
||||
self.count += LOTS_OF_BITS as isize;
|
||||
loop_end = x;
|
||||
}
|
||||
|
||||
if x < 0 || bits_left != 0 {
|
||||
while shift >= loop_end {
|
||||
self.count += U8_BITS as isize;
|
||||
self.value |= (self.data.get_u8() as usize) << shift;
|
||||
shift -= U8_BITS as i32;
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!("Out of bits"))
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads the next bit from the coded stream. The probability of the bit to
|
||||
/// be one is probability / 256.
|
||||
fn read_bit(&mut self, probability: u8) -> Result<bool> {
|
||||
let split = 1 + (((self.range - 1) * probability as usize) >> 8);
|
||||
|
||||
if self.count < 0 {
|
||||
self.fill()?;
|
||||
}
|
||||
|
||||
let bigsplit = split << (BD_VALUE_SIZE - U8_BITS);
|
||||
|
||||
let bit = if self.value >= bigsplit {
|
||||
self.range -= split;
|
||||
self.value -= bigsplit;
|
||||
true
|
||||
} else {
|
||||
self.range = split;
|
||||
false
|
||||
};
|
||||
|
||||
let shift = NORM[self.range];
|
||||
self.range <<= shift;
|
||||
self.value <<= shift;
|
||||
self.count -= isize::from(shift);
|
||||
|
||||
Ok(bit)
|
||||
}
|
||||
|
||||
/// Reads a "literal", that is, a "num_bits"-wide unsigned value whose bits
|
||||
/// come high- to low-order, with each bit encoded at probability 1/2.
|
||||
fn read_literal(&mut self, mut nbits: usize) -> Result<i32> {
|
||||
let mut ret = 0;
|
||||
|
||||
while nbits > 0 {
|
||||
let bit = self.read_bit(DEFAULT_PROBABILITY)?;
|
||||
ret = (ret << 1) | bit as i32;
|
||||
nbits -= 1;
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Reads a boolean from the coded stream. Returns false if it has reached the
|
||||
/// end of data and failed to read the boolean. The probability of out to
|
||||
/// be true is probability / 256, e.g., when probability is 0x80, the
|
||||
/// chance is 1/2 (i.e., 0x80 / 256).
|
||||
pub fn read_bool(&mut self) -> Result<bool> {
|
||||
self.read_literal(1).map(|bit| bit != 0)
|
||||
}
|
||||
|
||||
/// Reads a boolean from the coded stream. Returns false if it has reached the
|
||||
/// end of data and failed to read the boolean. The probability of out to
|
||||
/// be true is probability / 256, e.g., when probability is 0x80, the
|
||||
/// chance is 1/2 (i.e., 0x80 / 256).
|
||||
pub fn read_bool_with_prob(&mut self, probability: u8) -> Result<bool> {
|
||||
self.read_bit(probability)
|
||||
}
|
||||
|
||||
/// Reads an unsigned literal from the coded stream.
|
||||
pub fn read_uint<U: TryFrom<i32>>(&mut self, nbits: usize) -> Result<U> {
|
||||
let value = self.read_literal(nbits)?;
|
||||
U::try_from(value).map_err(|_| anyhow!("Conversion failed"))
|
||||
}
|
||||
|
||||
/// Reads a literal with sign from the coded stream. This is similar to the
|
||||
/// read_literal(), it first read a "num_bits"-wide unsigned value, and then
|
||||
/// read an extra bit as the sign of the literal.
|
||||
pub fn read_sint<U: TryFrom<i32>>(&mut self, nbits: usize) -> Result<U> {
|
||||
let mut value = self.read_literal(nbits)?;
|
||||
let sign = self.read_bool()?;
|
||||
|
||||
if sign {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
U::try_from(value).map_err(|_| anyhow!("Conversion failed"))
|
||||
}
|
||||
|
||||
/// Returns the current coded value.
|
||||
pub fn value(&self) -> usize {
|
||||
self.value >> (BD_VALUE_SIZE - U8_BITS)
|
||||
}
|
||||
|
||||
/// Returns the number of bytes in the `value` buffer.
|
||||
pub fn count(&self) -> isize {
|
||||
(U8_BITS as isize + self.count) % U8_BITS as isize
|
||||
}
|
||||
|
||||
/// Returns the range of the current coded value.
|
||||
pub fn range(&self) -> usize {
|
||||
self.range
|
||||
}
|
||||
|
||||
/// Returns the current bit position.
|
||||
pub fn pos(&self) -> usize {
|
||||
let mut bit_count = (self.count + 8) as usize;
|
||||
|
||||
if bit_count > BD_VALUE_SIZE {
|
||||
bit_count = std::cmp::max(0, bit_count - LOTS_OF_BITS as usize);
|
||||
}
|
||||
|
||||
let pos = self.data.position() as usize;
|
||||
pos * U8_BITS - bit_count
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const NUM_BITS_TO_TEST: usize = 100;
|
||||
|
||||
/// 100 zeros with probability of 0x80.
|
||||
const DATA_ZEROS_AND_EVEN_PROBABILITIES: [u8; 14] = [
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
/// 100 ones with probability of 0x80.
|
||||
const DATA_ONES_AND_EVEN_PROBABILITIES: [u8; 14] = [
|
||||
0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x20,
|
||||
];
|
||||
|
||||
/// [0, 1, 0, 1, ..., 1] with probability [0, 1, 2, 3, ..., 99].
|
||||
const DATA_PARITIES_AND_INCREASING_PROBABILITIES: [u8; 21] = [
|
||||
0x00, 0x02, 0x08, 0x31, 0x8e, 0xca, 0xab, 0xe2, 0xc8, 0x31, 0x12, 0xb3, 0x2c, 0x19, 0x90,
|
||||
0xc6, 0x6a, 0xeb, 0x17, 0x52, 0x30,
|
||||
];
|
||||
|
||||
// All tests adapted from:
|
||||
// https://chromium.googlesource.com/chromium/src/+/refs/heads/main/media/parsers/vp8_bool_decoder_unittest.cc
|
||||
|
||||
#[test]
|
||||
fn decode_bools_with_zeros_and_even_probabilities() {
|
||||
let mut bd = BoolDecoder::new(&DATA_ZEROS_AND_EVEN_PROBABILITIES[..]);
|
||||
assert!(bd.pos() == 0);
|
||||
|
||||
for i in 0..NUM_BITS_TO_TEST {
|
||||
assert!(!bd.read_bool_with_prob(0x80).unwrap());
|
||||
assert_eq!(i, bd.pos());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_literals_with_zeros_and_even_probabilities() {
|
||||
// Adapted from:
|
||||
// https://chromium.googlesource.com/chromium/src/+/refs/heads/main/media/parsers/vp8_bool_decoder_unittest.cc
|
||||
let mut bd = BoolDecoder::new(&DATA_ZEROS_AND_EVEN_PROBABILITIES[..]);
|
||||
assert!(bd.pos() == 0);
|
||||
|
||||
assert!(bd.read_literal(1).unwrap() == 0);
|
||||
assert!(bd.read_literal(32).unwrap() == 0);
|
||||
assert!(bd.read_sint::<i32>(1).unwrap() == 0);
|
||||
assert!(bd.read_sint::<i32>(31).unwrap() == 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_bools_with_ones_and_even_probabilities() {
|
||||
let mut bd = BoolDecoder::new(&DATA_ONES_AND_EVEN_PROBABILITIES[..]);
|
||||
assert!(bd.pos() == 0);
|
||||
|
||||
for i in 0..NUM_BITS_TO_TEST {
|
||||
assert!(bd.read_bool_with_prob(0x80).unwrap());
|
||||
assert_eq!(i + 1, bd.pos());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_literals_with_ones_and_even_probabilities() {
|
||||
let mut bd = BoolDecoder::new(&DATA_ONES_AND_EVEN_PROBABILITIES[..]);
|
||||
assert!(bd.pos() == 0);
|
||||
|
||||
assert!(bd.read_literal(1).unwrap() == 1);
|
||||
assert!(bd.read_literal(31).unwrap() == 0x7fffffff);
|
||||
assert!(bd.read_sint::<i32>(1).unwrap() == -1);
|
||||
assert!(bd.read_sint::<i32>(31).unwrap() == -0x7fffffff);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_bools_with_parities_and_increasing_probabilities() {
|
||||
let mut bd = BoolDecoder::new(&DATA_PARITIES_AND_INCREASING_PROBABILITIES[..]);
|
||||
assert!(bd.pos() == 0);
|
||||
|
||||
for i in 0..NUM_BITS_TO_TEST {
|
||||
let bit = bd.read_bool_with_prob(i as u8).unwrap();
|
||||
|
||||
if i % 2 == 0 {
|
||||
assert!(!bit);
|
||||
} else {
|
||||
assert!(bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
// Copyright 2022 The ChromiumOS Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
mod bool_decoder;
|
||||
pub mod parser;
|
||||
mod probs;
|
|
@ -1,902 +0,0 @@
|
|||
// Copyright 2022 The ChromiumOS Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::io::Cursor;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use anyhow::Result;
|
||||
use bytes::Buf;
|
||||
use log::debug;
|
||||
|
||||
use crate::bool_decoder::BoolDecoder;
|
||||
use crate::probs::COEFF_DEFAULT_PROBS;
|
||||
use crate::probs::COEFF_UPDATE_PROBS;
|
||||
use crate::probs::KF_UV_MODE_PROBS;
|
||||
use crate::probs::KF_Y_MODE_PROBS;
|
||||
use crate::probs::MV_DEFAULT_PROBS;
|
||||
use crate::probs::MV_UPDATE_PROBS;
|
||||
use crate::probs::NK_UV_MODE_PROBS;
|
||||
use crate::probs::NK_Y_MODE_PROBS;
|
||||
|
||||
/// Dequantization indices as parsed from the quant_indices() syntax.
|
||||
#[derive(Clone, Default)]
|
||||
pub struct QuantIndices {
|
||||
/// The dequantization table index used for the luma AC coefficients (and
|
||||
/// other coefficient groups if no delta value is present).
|
||||
pub y_ac_qi: u8,
|
||||
/// Indicates the delta value that is added to the baseline index to obtain
|
||||
/// the luma DC coefficient dequantization index.
|
||||
pub y_dc_delta: i8,
|
||||
/// Indicates the delta value that is added to the baseline index to obtain
|
||||
/// the Y2 block DC coefficient dequantization index.
|
||||
pub y2_dc_delta: i8,
|
||||
/// Indicates the delta value that is added to the baseline index to obtain
|
||||
/// the Y2 block AC coefficient dequantization index.
|
||||
pub y2_ac_delta: i8,
|
||||
/// Indicates the delta value that is added to the baseline index to obtain
|
||||
/// the chroma DC coefficient dequantization index.
|
||||
pub uv_dc_delta: i8,
|
||||
/// Indicates the delta value that is added to the baseline index to obtain
|
||||
/// the chroma AC coefficient dequantization index.
|
||||
pub uv_ac_delta: i8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct MbLfAdjustments {
|
||||
/// Indicates if the MB-level loop filter adjustment (based on the used
|
||||
/// reference frame and coding mode) is on for the current frame.
|
||||
pub loop_filter_adj_enable: bool,
|
||||
/// Indicates if the delta values used in adjustment are updated in the
|
||||
/// current frame.
|
||||
pub mode_ref_lf_delta_update: bool,
|
||||
|
||||
//if mode_ref_lf_delta_update == 1
|
||||
/// Indicates the adjustment delta value corresponding to a certain used
|
||||
/// reference frame.
|
||||
pub ref_frame_delta: [i8; 4],
|
||||
/// Indicates the adjustment delta value corresponding to a certain MB
|
||||
/// prediction mode
|
||||
pub mb_mode_delta: [i8; 4],
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Segmentation {
|
||||
/// Enables the segmentation feature for the current frame.
|
||||
pub segmentation_enabled: bool,
|
||||
/// Determines if the MB segmentation map is updated in the current frame.
|
||||
pub update_mb_segmentation_map: bool,
|
||||
/// indicates if the segment feature data is updated in the current frame.
|
||||
pub update_segment_feature_data: bool,
|
||||
|
||||
// If update_segment_feature_data == 1
|
||||
/// Indicates the feature data update mode, O for delta and 1 for the
|
||||
/// absolute value.
|
||||
pub segment_feature_mode: bool,
|
||||
/// Indicates if the quantizer value is updated for the izh segment.
|
||||
pub quantizer_update_value: [i8; 4],
|
||||
/// Indicates the update value for the loop filter level.
|
||||
pub lf_update_value: [i8; 4],
|
||||
|
||||
// if update_mb_segmentation_map == 1
|
||||
/// The branch probabilities of the segment id decoding tree.
|
||||
pub segment_prob: [u8; 3],
|
||||
}
|
||||
|
||||
#[derive(Default, Copy, Clone)]
|
||||
pub struct ModeProbs {
|
||||
/// Branch probabilities of the luma intra prediction mode decoding tree,
|
||||
/// kept live between frames.
|
||||
pub intra_16x16_prob: [u8; 4],
|
||||
/// Branch probabilities of the chroma intra prediction mode decoding tree,
|
||||
/// kept live between frames.
|
||||
pub intra_chroma_prob: [u8; 3],
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Header {
|
||||
/// Indicates if the current frame is a key frame or not.
|
||||
key_frame: bool,
|
||||
/// Determines the bitstream version.
|
||||
version: u8,
|
||||
/// Indicates if the current frame is meant to be displayed or not.
|
||||
show_frame: bool,
|
||||
/// The size in bytes of the Uncompressed Data Chunk
|
||||
data_chunk_size: u8,
|
||||
/// Determines the size of the first partition (control partition) excluding
|
||||
/// the size of the Uncompressed Data Chunk
|
||||
first_part_size: u32,
|
||||
|
||||
/// The frame's width, in pixels.
|
||||
width: u16,
|
||||
/// The frame's height, in pixels.
|
||||
height: u16,
|
||||
/// Horizontal scale code value.
|
||||
horiz_scale_code: u8,
|
||||
/// Vertical scale code value.
|
||||
vert_scale_code: u8,
|
||||
/// Defines the YUV color space of the sequence.
|
||||
color_space: bool,
|
||||
/// Specifies if the decoder is required to clamp the reconstructed pixel
|
||||
/// values.
|
||||
clamping_type: bool,
|
||||
/// Determines whether the normal or the simple loop filter is used.
|
||||
filter_type: bool,
|
||||
/// Controls the deblocking filter.
|
||||
loop_filter_level: u8,
|
||||
/// Controls the deblocking filter.
|
||||
sharpness_level: u8,
|
||||
/// Determines the number of separate partitions containing the DCT
|
||||
/// coefficients of the macroblocks.
|
||||
log2_nbr_of_dct_partitions: u8,
|
||||
|
||||
partition_size: [u32; 8],
|
||||
|
||||
/// Dequantizer indices.
|
||||
quant_indices: QuantIndices,
|
||||
|
||||
/// Determines whether updated token probabilities are used only for this
|
||||
/// frame or until further update
|
||||
refresh_entropy_probs: bool,
|
||||
/// Determines if the current decoded frame refreshes the last frame
|
||||
/// reference buffer
|
||||
refresh_last: bool,
|
||||
|
||||
/// Determines if the current decoded frame refreshes the golden frame.
|
||||
refresh_golden_frame: bool,
|
||||
/// Determines if the current decoded frame refreshes the alternate
|
||||
/// reference frame.
|
||||
refresh_alternate_frame: bool,
|
||||
/// Determines if the golden reference is replaced by another reference.
|
||||
copy_buffer_to_golden: u8,
|
||||
/// Determines if the alternate reference is replaced by another reference.
|
||||
copy_buffer_to_alternate: u8,
|
||||
/// Controls the sign of motion vectors when the golden frame is referenced.
|
||||
sign_bias_golden: bool,
|
||||
/// Controls the sign of motion vectors when the alternate frame is
|
||||
/// referenced.
|
||||
sign_bias_alternate: bool,
|
||||
|
||||
/// The new branch probability for the DCT/WHT tree.
|
||||
coeff_prob: [[[[u8; 11]; 3]; 8]; 4],
|
||||
/// MV decoding probability.
|
||||
mv_prob: [[u8; 19]; 2],
|
||||
|
||||
/// Enables or disables the skipping of macroblocks containing no non-zero
|
||||
/// coefficients.
|
||||
mb_no_coeff_skip: bool,
|
||||
/// The probability that the macroblock is not skipped (flag indicating
|
||||
/// skipped macroblock is false).
|
||||
prob_skip_false: u8,
|
||||
/// The probability of an intra macroblock.
|
||||
prob_intra: u8,
|
||||
/// The probability that the last reference frame is used for inter
|
||||
/// prediction.
|
||||
prob_last: u8,
|
||||
/// The probability that the golden reference frame is used for inter
|
||||
/// prediction.
|
||||
prob_golden: u8,
|
||||
/// Branch probabilities kept live across frames.
|
||||
mode_probs: ModeProbs,
|
||||
|
||||
/// Boolean decoder `range` for this frame.
|
||||
bd_range: usize,
|
||||
/// Boolean decoder `value` for this frame.
|
||||
bd_value: usize,
|
||||
/// Boolean decoder `count` for this frame.
|
||||
bd_count: isize,
|
||||
|
||||
/// The size in bits of the Frame Header, thus excluding any Uncompressed
|
||||
/// Data Chunk bytes.
|
||||
header_size: u32,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Header {
|
||||
/// Get a reference to the header's key frame.
|
||||
pub fn key_frame(&self) -> bool {
|
||||
self.key_frame
|
||||
}
|
||||
|
||||
/// Get a reference to the header's version.
|
||||
pub fn version(&self) -> u8 {
|
||||
self.version
|
||||
}
|
||||
|
||||
/// Get a reference to the header's show frame.
|
||||
pub fn show_frame(&self) -> bool {
|
||||
self.show_frame
|
||||
}
|
||||
|
||||
/// Get a reference to the header's data chunk size.
|
||||
pub fn data_chunk_size(&self) -> u8 {
|
||||
self.data_chunk_size
|
||||
}
|
||||
|
||||
/// Get a reference to the header's first part size.
|
||||
pub fn first_part_size(&self) -> u32 {
|
||||
self.first_part_size
|
||||
}
|
||||
|
||||
/// Get a reference to the header's width.
|
||||
pub fn width(&self) -> u16 {
|
||||
self.width
|
||||
}
|
||||
|
||||
/// Get a reference to the header's height.
|
||||
pub fn height(&self) -> u16 {
|
||||
self.height
|
||||
}
|
||||
|
||||
/// Get a reference to the header's horiz scale code.
|
||||
pub fn horiz_scale_code(&self) -> u8 {
|
||||
self.horiz_scale_code
|
||||
}
|
||||
|
||||
/// Get a reference to the header's vert scale code.
|
||||
pub fn vert_scale_code(&self) -> u8 {
|
||||
self.vert_scale_code
|
||||
}
|
||||
|
||||
/// Get a reference to the header's color space.
|
||||
pub fn color_space(&self) -> bool {
|
||||
self.color_space
|
||||
}
|
||||
|
||||
/// Get a reference to the header's clamping type.
|
||||
pub fn clamping_type(&self) -> bool {
|
||||
self.clamping_type
|
||||
}
|
||||
|
||||
/// Get a reference to the header's filter type.
|
||||
pub fn filter_type(&self) -> bool {
|
||||
self.filter_type
|
||||
}
|
||||
|
||||
/// Get a reference to the header's loop filter level.
|
||||
pub fn loop_filter_level(&self) -> u8 {
|
||||
self.loop_filter_level
|
||||
}
|
||||
|
||||
/// Get a reference to the header's sharpness level.
|
||||
pub fn sharpness_level(&self) -> u8 {
|
||||
self.sharpness_level
|
||||
}
|
||||
|
||||
/// Get a reference to the header's log2 nbr of dct partitions.
|
||||
pub fn log2_nbr_of_dct_partitions(&self) -> u8 {
|
||||
self.log2_nbr_of_dct_partitions
|
||||
}
|
||||
|
||||
/// Get a reference to the header's partition size.
|
||||
pub fn partition_size(&self) -> [u32; 8] {
|
||||
self.partition_size
|
||||
}
|
||||
|
||||
/// Get a reference to the header's quant indices.
|
||||
pub fn quant_indices(&self) -> &QuantIndices {
|
||||
&self.quant_indices
|
||||
}
|
||||
|
||||
/// Get a reference to the header's refresh entropy probs.
|
||||
pub fn refresh_entropy_probs(&self) -> bool {
|
||||
self.refresh_entropy_probs
|
||||
}
|
||||
|
||||
/// Get a reference to the header's refresh last.
|
||||
pub fn refresh_last(&self) -> bool {
|
||||
self.refresh_last
|
||||
}
|
||||
|
||||
/// Get a reference to the header's refresh golden frame.
|
||||
pub fn refresh_golden_frame(&self) -> bool {
|
||||
self.refresh_golden_frame
|
||||
}
|
||||
|
||||
/// Get a reference to the header's refresh alternate frame.
|
||||
pub fn refresh_alternate_frame(&self) -> bool {
|
||||
self.refresh_alternate_frame
|
||||
}
|
||||
|
||||
/// Get a reference to the header's copy buffer to golden.
|
||||
pub fn copy_buffer_to_golden(&self) -> u8 {
|
||||
self.copy_buffer_to_golden
|
||||
}
|
||||
|
||||
/// Get a reference to the header's copy buffer to alternate.
|
||||
pub fn copy_buffer_to_alternate(&self) -> u8 {
|
||||
self.copy_buffer_to_alternate
|
||||
}
|
||||
|
||||
/// Get a reference to the header's sign bias golden.
|
||||
pub fn sign_bias_golden(&self) -> bool {
|
||||
self.sign_bias_golden
|
||||
}
|
||||
|
||||
/// Get a reference to the header's sign bias alternate.
|
||||
pub fn sign_bias_alternate(&self) -> bool {
|
||||
self.sign_bias_alternate
|
||||
}
|
||||
|
||||
/// Get a reference to the header's coeff prob.
|
||||
pub fn coeff_prob(&self) -> [[[[u8; 11]; 3]; 8]; 4] {
|
||||
self.coeff_prob
|
||||
}
|
||||
|
||||
/// Get a reference to the header's mv prob.
|
||||
pub fn mv_prob(&self) -> [[u8; 19]; 2] {
|
||||
self.mv_prob
|
||||
}
|
||||
|
||||
/// Get a reference to the header's mb no coeff skip.
|
||||
pub fn mb_no_coeff_skip(&self) -> bool {
|
||||
self.mb_no_coeff_skip
|
||||
}
|
||||
|
||||
/// Get a reference to the header's prob skip false.
|
||||
pub fn prob_skip_false(&self) -> u8 {
|
||||
self.prob_skip_false
|
||||
}
|
||||
|
||||
/// Get a reference to the header's prob intra.
|
||||
pub fn prob_intra(&self) -> u8 {
|
||||
self.prob_intra
|
||||
}
|
||||
|
||||
/// Get a reference to the header's prob last.
|
||||
pub fn prob_last(&self) -> u8 {
|
||||
self.prob_last
|
||||
}
|
||||
|
||||
/// Get a reference to the header's prob golden.
|
||||
pub fn prob_golden(&self) -> u8 {
|
||||
self.prob_golden
|
||||
}
|
||||
|
||||
/// Get a reference to the header's mode probs.
|
||||
pub fn mode_probs(&self) -> ModeProbs {
|
||||
self.mode_probs
|
||||
}
|
||||
|
||||
/// Get a reference to the header's bd range.
|
||||
pub fn bd_range(&self) -> usize {
|
||||
self.bd_range
|
||||
}
|
||||
|
||||
/// Get a reference to the header's bd value.
|
||||
pub fn bd_value(&self) -> usize {
|
||||
self.bd_value
|
||||
}
|
||||
|
||||
/// Get a reference to the header's bd count.
|
||||
pub fn bd_count(&self) -> isize {
|
||||
self.bd_count
|
||||
}
|
||||
|
||||
/// Get a reference to the header's header size.
|
||||
pub fn header_size(&self) -> u32 {
|
||||
self.header_size
|
||||
}
|
||||
}
|
||||
/// A VP8 frame.
|
||||
pub struct Frame<T: AsRef<[u8]>> {
|
||||
/// The abstraction for the raw memory for this frame.
|
||||
pub bitstream: T,
|
||||
/// The frame header.
|
||||
pub header: Header,
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> Frame<T> {
|
||||
/// Creates a new frame, using the resource as its backing memory.
|
||||
fn new(bitstream: T) -> Self {
|
||||
Self {
|
||||
bitstream,
|
||||
header: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> AsRef<[u8]> for Frame<T> {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.bitstream.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// A VP8 parser based on GStreamer's vp8parser and Chromium's VP8 parser.
|
||||
pub struct Parser {
|
||||
/// Segmentation data kept live across frames.
|
||||
segmentation: Segmentation,
|
||||
/// MbLfAdjustments data kept live across frames.
|
||||
mb_lf_adjust: MbLfAdjustments,
|
||||
/// Coeff probabilities data kept live across frames.
|
||||
coeff_prob: [[[[u8; 11]; 3]; 8]; 4],
|
||||
/// Motion vector probabilities data kept live across frames.
|
||||
mv_prob: [[u8; 19]; 2],
|
||||
/// Branch probabilities kept live across frames.
|
||||
mode_probs: ModeProbs,
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
pub fn segmentation(&self) -> &Segmentation {
|
||||
&self.segmentation
|
||||
}
|
||||
|
||||
pub fn mb_lf_adjust(&self) -> &MbLfAdjustments {
|
||||
&self.mb_lf_adjust
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
*self = Default::default();
|
||||
}
|
||||
|
||||
fn mode_probs_init_defaults(mode_probs: &mut ModeProbs, key_frame: bool) {
|
||||
if key_frame {
|
||||
mode_probs.intra_16x16_prob = KF_Y_MODE_PROBS;
|
||||
mode_probs.intra_chroma_prob = KF_UV_MODE_PROBS;
|
||||
} else {
|
||||
mode_probs.intra_16x16_prob = NK_Y_MODE_PROBS;
|
||||
mode_probs.intra_chroma_prob = NK_UV_MODE_PROBS;
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_uncompressed_data_chunk<T: AsRef<[u8]>>(
|
||||
&mut self,
|
||||
reader: &mut Cursor<T>,
|
||||
frame: &mut Header,
|
||||
) -> Result<()> {
|
||||
debug!("Parsing VP8 uncompressed data chunk.");
|
||||
|
||||
let frame_tag = reader.get_uint_le(3) as u32;
|
||||
|
||||
frame.key_frame = (frame_tag & 0x1) == 0;
|
||||
frame.version = ((frame_tag >> 1) & 0x07) as u8;
|
||||
frame.show_frame = ((frame_tag >> 4) & 0x1) != 0;
|
||||
frame.first_part_size = (frame_tag >> 5) & 0x7ffff;
|
||||
|
||||
if frame.key_frame {
|
||||
let start_code = reader.get_uint(3) as u32;
|
||||
|
||||
if start_code != 0x9d012a {
|
||||
return Err(anyhow!("Invalid start code {}", start_code));
|
||||
}
|
||||
|
||||
let size_code = reader.get_uint_le(2) as u16;
|
||||
frame.horiz_scale_code = (size_code >> 14) as u8;
|
||||
frame.width = size_code & 0x3fff;
|
||||
|
||||
let size_code = reader.get_uint_le(2) as u16;
|
||||
frame.vert_scale_code = (size_code >> 14) as u8;
|
||||
frame.height = size_code & 0x3fff;
|
||||
|
||||
// Reset on every key frame.
|
||||
self.reset();
|
||||
}
|
||||
|
||||
frame.data_chunk_size = reader.position() as u8;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_segmentation<T: AsRef<[u8]>>(
|
||||
bd: &mut BoolDecoder<T>,
|
||||
seg: &mut Segmentation,
|
||||
) -> Result<()> {
|
||||
seg.update_mb_segmentation_map = false;
|
||||
seg.update_segment_feature_data = false;
|
||||
|
||||
seg.segmentation_enabled = bd.read_bool()?;
|
||||
if !seg.segmentation_enabled {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
seg.update_mb_segmentation_map = bd.read_bool()?;
|
||||
seg.update_segment_feature_data = bd.read_bool()?;
|
||||
|
||||
if seg.update_segment_feature_data {
|
||||
seg.segment_feature_mode = bd.read_bool()?;
|
||||
|
||||
for value in seg.quantizer_update_value.iter_mut() {
|
||||
let update = bd.read_bool()?;
|
||||
if update {
|
||||
*value = bd.read_sint(7)?;
|
||||
} else {
|
||||
// quantizer_update_value defaults to zero if update flag is
|
||||
// zero (Section 9.3, 4.b)
|
||||
*value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for value in seg.lf_update_value.iter_mut() {
|
||||
let update = bd.read_bool()?;
|
||||
if update {
|
||||
*value = bd.read_sint(6)?;
|
||||
} else {
|
||||
// lf_update_value defaults to zero if update flag is
|
||||
// zero (Section 9.3, 4.b)
|
||||
*value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if seg.update_mb_segmentation_map {
|
||||
for value in seg.segment_prob.iter_mut() {
|
||||
let update = bd.read_bool()?;
|
||||
if update {
|
||||
*value = bd.read_uint(8)?;
|
||||
} else {
|
||||
// segment_prob defaults to 255 if update flag is
|
||||
// zero (Section 9.3, 5)
|
||||
*value = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_mb_lf_adjustments<T: AsRef<[u8]>>(
|
||||
bd: &mut BoolDecoder<T>,
|
||||
adj: &mut MbLfAdjustments,
|
||||
) -> Result<()> {
|
||||
adj.mode_ref_lf_delta_update = false;
|
||||
|
||||
adj.loop_filter_adj_enable = bd.read_bool()?;
|
||||
if !adj.loop_filter_adj_enable {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
adj.mode_ref_lf_delta_update = bd.read_bool()?;
|
||||
if !adj.mode_ref_lf_delta_update {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for value in adj.ref_frame_delta.iter_mut() {
|
||||
let update = bd.read_bool()?;
|
||||
if update {
|
||||
*value = bd.read_sint(6)?;
|
||||
}
|
||||
}
|
||||
|
||||
for value in adj.mb_mode_delta.iter_mut() {
|
||||
let update = bd.read_bool()?;
|
||||
if update {
|
||||
*value = bd.read_sint(6)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_quant_indices<T: AsRef<[u8]>>(
|
||||
bd: &mut BoolDecoder<T>,
|
||||
q: &mut QuantIndices,
|
||||
) -> Result<()> {
|
||||
q.y_ac_qi = bd.read_uint(7)?;
|
||||
|
||||
let y_dc_delta_present = bd.read_bool()?;
|
||||
|
||||
if y_dc_delta_present {
|
||||
q.y_dc_delta = bd.read_sint(4)?;
|
||||
} else {
|
||||
q.y_dc_delta = 0;
|
||||
}
|
||||
|
||||
let y2_dc_delta_present = bd.read_bool()?;
|
||||
if y2_dc_delta_present {
|
||||
q.y2_dc_delta = bd.read_sint(4)?;
|
||||
} else {
|
||||
q.y2_dc_delta = 0;
|
||||
}
|
||||
|
||||
let y2_ac_delta_present = bd.read_bool()?;
|
||||
if y2_ac_delta_present {
|
||||
q.y2_ac_delta = bd.read_sint(4)?;
|
||||
} else {
|
||||
q.y2_ac_delta = 0;
|
||||
}
|
||||
|
||||
let uv_dc_delta_present = bd.read_bool()?;
|
||||
if uv_dc_delta_present {
|
||||
q.uv_dc_delta = bd.read_sint(4)?;
|
||||
} else {
|
||||
q.uv_dc_delta = 0;
|
||||
}
|
||||
|
||||
let uv_ac_delta_present = bd.read_bool()?;
|
||||
if uv_ac_delta_present {
|
||||
q.uv_ac_delta = bd.read_sint(4)?;
|
||||
} else {
|
||||
q.uv_ac_delta = 0;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_token_prob_update<T: AsRef<[u8]>>(
|
||||
bd: &mut BoolDecoder<T>,
|
||||
coeff_probs: &mut [[[[u8; 11]; 3]; 8]; 4],
|
||||
) -> Result<()> {
|
||||
for (i, vi) in coeff_probs.iter_mut().enumerate() {
|
||||
for (j, vj) in vi.iter_mut().enumerate() {
|
||||
for (k, vk) in vj.iter_mut().enumerate() {
|
||||
for (l, prob) in vk.iter_mut().enumerate() {
|
||||
let update = bd.read_bool_with_prob(COEFF_UPDATE_PROBS[i][j][k][l])?;
|
||||
if update {
|
||||
*prob = bd.read_uint(8)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_mv_prob_update<T: AsRef<[u8]>>(
|
||||
bd: &mut BoolDecoder<T>,
|
||||
mv_probs: &mut [[u8; 19]; 2],
|
||||
) -> Result<()> {
|
||||
for (i, vi) in mv_probs.iter_mut().enumerate() {
|
||||
for (j, prob) in vi.iter_mut().enumerate() {
|
||||
let update = bd.read_bool_with_prob(MV_UPDATE_PROBS[i][j])?;
|
||||
if update {
|
||||
let mv_prob_update = bd.read_uint::<u8>(7)?;
|
||||
|
||||
if mv_prob_update > 0 {
|
||||
*prob = mv_prob_update << 1;
|
||||
} else {
|
||||
*prob = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_frame_header(&mut self, data: &[u8], frame: &mut Header) -> Result<()> {
|
||||
debug!("Parsing VP8 frame header.");
|
||||
let mut bd = BoolDecoder::new(data);
|
||||
|
||||
if frame.key_frame {
|
||||
frame.color_space = bd.read_bool()?;
|
||||
frame.clamping_type = bd.read_bool()?;
|
||||
}
|
||||
|
||||
Parser::update_segmentation(&mut bd, &mut self.segmentation)?;
|
||||
|
||||
frame.filter_type = bd.read_bool()?;
|
||||
frame.loop_filter_level = bd.read_uint(6)?;
|
||||
frame.sharpness_level = bd.read_uint(3)?;
|
||||
|
||||
Parser::parse_mb_lf_adjustments(&mut bd, &mut self.mb_lf_adjust)?;
|
||||
|
||||
frame.log2_nbr_of_dct_partitions = bd.read_uint(2)?;
|
||||
|
||||
Parser::parse_quant_indices(&mut bd, &mut frame.quant_indices)?;
|
||||
|
||||
frame.copy_buffer_to_golden = 0;
|
||||
frame.copy_buffer_to_alternate = 0;
|
||||
|
||||
if frame.key_frame {
|
||||
frame.refresh_entropy_probs = bd.read_bool()?;
|
||||
|
||||
frame.refresh_last = true;
|
||||
frame.refresh_golden_frame = true;
|
||||
frame.refresh_alternate_frame = true;
|
||||
|
||||
Parser::mode_probs_init_defaults(&mut frame.mode_probs, true);
|
||||
} else {
|
||||
frame.refresh_golden_frame = bd.read_bool()?;
|
||||
frame.refresh_alternate_frame = bd.read_bool()?;
|
||||
|
||||
if !frame.refresh_golden_frame {
|
||||
frame.copy_buffer_to_golden = bd.read_uint(2)?;
|
||||
}
|
||||
|
||||
if !frame.refresh_alternate_frame {
|
||||
frame.copy_buffer_to_alternate = bd.read_uint(2)?;
|
||||
}
|
||||
|
||||
frame.sign_bias_golden = bd.read_bool()?;
|
||||
frame.sign_bias_alternate = bd.read_bool()?;
|
||||
frame.refresh_entropy_probs = bd.read_bool()?;
|
||||
frame.refresh_last = bd.read_bool()?;
|
||||
|
||||
frame.mode_probs = self.mode_probs;
|
||||
}
|
||||
|
||||
frame.coeff_prob = self.coeff_prob;
|
||||
frame.mv_prob = self.mv_prob;
|
||||
|
||||
Parser::parse_token_prob_update(&mut bd, &mut frame.coeff_prob)?;
|
||||
|
||||
frame.mb_no_coeff_skip = bd.read_bool()?;
|
||||
if frame.mb_no_coeff_skip {
|
||||
frame.prob_skip_false = bd.read_uint(8)?;
|
||||
}
|
||||
|
||||
if !frame.key_frame {
|
||||
frame.prob_intra = bd.read_uint(8)?;
|
||||
frame.prob_last = bd.read_uint(8)?;
|
||||
frame.prob_golden = bd.read_uint(8)?;
|
||||
|
||||
let intra_16x16_prob_update_flag = bd.read_bool()?;
|
||||
if intra_16x16_prob_update_flag {
|
||||
for prob in frame.mode_probs.intra_16x16_prob.iter_mut() {
|
||||
*prob = bd.read_uint(8)?;
|
||||
}
|
||||
}
|
||||
|
||||
let intra_chroma_prob_update_flag = bd.read_bool()?;
|
||||
if intra_chroma_prob_update_flag {
|
||||
for prob in frame.mode_probs.intra_chroma_prob.iter_mut() {
|
||||
*prob = bd.read_uint(8)?;
|
||||
}
|
||||
}
|
||||
|
||||
Parser::parse_mv_prob_update(&mut bd, &mut frame.mv_prob)?;
|
||||
}
|
||||
|
||||
if frame.refresh_entropy_probs {
|
||||
self.coeff_prob = frame.coeff_prob;
|
||||
self.mv_prob = frame.mv_prob;
|
||||
|
||||
if !frame.key_frame {
|
||||
self.mode_probs = frame.mode_probs;
|
||||
}
|
||||
}
|
||||
|
||||
frame.header_size = bd.pos() as u32;
|
||||
Parser::sync_bd_state(&bd, frame);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compute_partition_sizes(frame: &mut Header, data: &[u8]) -> Result<()> {
|
||||
let num_partitions = usize::try_from(1 << frame.log2_nbr_of_dct_partitions)?;
|
||||
let mut part_size_ofs = usize::try_from(frame.first_part_size)?;
|
||||
let mut ofs = part_size_ofs + 3 * (num_partitions - 1);
|
||||
|
||||
if ofs > data.len() {
|
||||
return Err(anyhow!("Not enough bytes left to parse partition sizes.",));
|
||||
}
|
||||
|
||||
for i in 0..num_partitions - 1 {
|
||||
let b0 = u32::from(data[part_size_ofs + 0]);
|
||||
let b1 = u32::from(data[part_size_ofs + 1]) << 8;
|
||||
let b2 = u32::from(data[part_size_ofs + 2]) << 16;
|
||||
|
||||
let part_size = usize::try_from(b0 | b1 | b2)?;
|
||||
part_size_ofs += 3;
|
||||
|
||||
frame.partition_size[i] = u32::try_from(part_size)?;
|
||||
ofs += part_size;
|
||||
}
|
||||
|
||||
if ofs > data.len() {
|
||||
return Err(anyhow!(
|
||||
"Not enough bytes left to determine the last partition size",
|
||||
));
|
||||
}
|
||||
|
||||
frame.partition_size[num_partitions - 1] = u32::try_from(data.len() - ofs)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sync_bd_state<T: AsRef<[u8]>>(bd: &BoolDecoder<T>, frame: &mut Header) {
|
||||
frame.bd_range = bd.range();
|
||||
frame.bd_value = bd.value();
|
||||
frame.bd_count = bd.count();
|
||||
}
|
||||
|
||||
/// Parse a single frame from the chunk in `data`.
|
||||
pub fn parse_frame<T: AsRef<[u8]>>(&mut self, resource: T) -> Result<Frame<T>> {
|
||||
let mut frame = Frame::new(resource);
|
||||
let mut reader = Cursor::new(frame.bitstream.as_ref());
|
||||
|
||||
self.parse_uncompressed_data_chunk(&mut reader, &mut frame.header)?;
|
||||
|
||||
let data = frame.bitstream.as_ref();
|
||||
|
||||
if usize::from(frame.header.data_chunk_size)
|
||||
+ usize::try_from(frame.header.first_part_size)?
|
||||
> data.len()
|
||||
{
|
||||
return Err(anyhow!("Broken data"));
|
||||
}
|
||||
|
||||
let data = &data[frame.header.data_chunk_size as usize..];
|
||||
|
||||
self.parse_frame_header(data, &mut frame.header)?;
|
||||
Parser::compute_partition_sizes(&mut frame.header, data)?;
|
||||
|
||||
Ok(frame)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Parser {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
segmentation: Default::default(),
|
||||
mb_lf_adjust: Default::default(),
|
||||
coeff_prob: COEFF_DEFAULT_PROBS,
|
||||
mv_prob: MV_DEFAULT_PROBS,
|
||||
mode_probs: ModeProbs {
|
||||
intra_16x16_prob: NK_Y_MODE_PROBS,
|
||||
intra_chroma_prob: NK_UV_MODE_PROBS,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Parser;
|
||||
|
||||
// Test and test data extracted from GStreamer
|
||||
// subprojects/gst-plugins-bad/tests/check/libs/vp8parser.c
|
||||
const VP8_TEST_0_INTRA: &[u8] = include_bytes!("vp8-parser-test-0-intra.bin");
|
||||
const VP8_TEST_0_INTER: &[u8] = include_bytes!("vp8-parser-test-0-inter.bin");
|
||||
|
||||
#[test]
|
||||
fn gst_vp8parser_test_intra() {
|
||||
let mut parser = Parser::default();
|
||||
let frame = parser
|
||||
.parse_frame(VP8_TEST_0_INTRA)
|
||||
.expect("Parsing a intra frame failed");
|
||||
|
||||
assert!(frame.header.key_frame);
|
||||
|
||||
assert_eq!(frame.header.first_part_size, 234);
|
||||
assert_eq!(frame.header.width, 176);
|
||||
assert_eq!(frame.header.height, 144);
|
||||
|
||||
assert!(parser.mb_lf_adjust.loop_filter_adj_enable);
|
||||
assert!(parser.mb_lf_adjust.mode_ref_lf_delta_update);
|
||||
|
||||
assert_eq!(parser.mb_lf_adjust.ref_frame_delta[0], 2);
|
||||
assert_eq!(parser.mb_lf_adjust.ref_frame_delta[1], 0);
|
||||
assert_eq!(parser.mb_lf_adjust.ref_frame_delta[2], -2);
|
||||
assert_eq!(parser.mb_lf_adjust.ref_frame_delta[3], -2);
|
||||
|
||||
assert_eq!(parser.mb_lf_adjust.mb_mode_delta[0], 4);
|
||||
assert_eq!(parser.mb_lf_adjust.mb_mode_delta[1], -2);
|
||||
assert_eq!(parser.mb_lf_adjust.mb_mode_delta[2], 2);
|
||||
assert_eq!(parser.mb_lf_adjust.mb_mode_delta[3], 4);
|
||||
|
||||
assert_eq!(frame.header.quant_indices.y_ac_qi, 4);
|
||||
assert!(frame.header.mb_no_coeff_skip);
|
||||
|
||||
assert_eq!(frame.header.bd_range, 0xe8);
|
||||
assert_eq!(frame.header.bd_value, 0x68);
|
||||
assert_eq!(frame.header.bd_count, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gst_vp8parser_test_inter() {
|
||||
let mut parser = Parser::default();
|
||||
let frame = parser
|
||||
.parse_frame(VP8_TEST_0_INTER)
|
||||
.expect("Parsing a inter frame failed");
|
||||
|
||||
assert!(!frame.header.key_frame);
|
||||
|
||||
assert_eq!(frame.header.first_part_size, 98);
|
||||
assert!(parser.mb_lf_adjust.loop_filter_adj_enable);
|
||||
assert_eq!(frame.header.quant_indices.y_ac_qi, 4);
|
||||
|
||||
assert!(frame.header.refresh_entropy_probs);
|
||||
assert!(frame.header.refresh_last);
|
||||
assert!(frame.header.mb_no_coeff_skip);
|
||||
|
||||
assert_eq!(frame.header.prob_skip_false, 131);
|
||||
assert_eq!(frame.header.prob_intra, 224);
|
||||
assert_eq!(frame.header.prob_last, 233);
|
||||
assert_eq!(frame.header.prob_golden, 1);
|
||||
|
||||
assert_eq!(frame.header.bd_range, 0x8e);
|
||||
assert_eq!(frame.header.bd_value, 0x85);
|
||||
assert_eq!(frame.header.bd_count, 5);
|
||||
}
|
||||
}
|
|
@ -1,376 +0,0 @@
|
|||
// Copyright 2022 The ChromiumOS Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/// VP8 probability tables as per the reference software and specification.
|
||||
|
||||
pub const MV_UPDATE_PROBS: [[u8; 19]; 2] = [
|
||||
[
|
||||
237, 246, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 250, 250, 252, 254,
|
||||
254,
|
||||
],
|
||||
[
|
||||
231, 243, 245, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 251, 251, 254, 254,
|
||||
254,
|
||||
],
|
||||
];
|
||||
|
||||
pub const MV_DEFAULT_PROBS: [[u8; 19]; 2] = [
|
||||
[
|
||||
162, 128, 225, 146, 172, 147, 214, 39, 156, 128, 129, 132, 75, 145, 178, 206, 239, 254, 254,
|
||||
],
|
||||
[
|
||||
164, 128, 204, 170, 119, 235, 140, 230, 228, 128, 130, 130, 74, 148, 180, 203, 236, 254,
|
||||
254,
|
||||
],
|
||||
];
|
||||
|
||||
pub const NK_Y_MODE_PROBS: [u8; 4] = [112, 86, 140, 37];
|
||||
|
||||
pub const KF_Y_MODE_PROBS: [u8; 4] = [145, 156, 163, 128];
|
||||
|
||||
pub const NK_UV_MODE_PROBS: [u8; 3] = [162, 101, 204];
|
||||
|
||||
pub const KF_UV_MODE_PROBS: [u8; 3] = [142, 114, 183];
|
||||
|
||||
pub const COEFF_UPDATE_PROBS: [[[[u8; 11]; 3]; 8]; 4] = [
|
||||
[
|
||||
[
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255],
|
||||
[250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255],
|
||||
[254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
[217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255],
|
||||
[234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
[186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255],
|
||||
[251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
[248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255],
|
||||
[248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
[
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
pub const COEFF_DEFAULT_PROBS: [[[[u8; 11]; 3]; 8]; 4] = [
|
||||
[
|
||||
[
|
||||
[128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
[128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
[128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128],
|
||||
[189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128],
|
||||
[106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128],
|
||||
[181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128],
|
||||
[78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128],
|
||||
[184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128],
|
||||
[77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128],
|
||||
[170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128],
|
||||
[37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128],
|
||||
[207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128],
|
||||
[102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128],
|
||||
[177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128],
|
||||
[80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
[246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
[255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
[198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62],
|
||||
[131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1],
|
||||
[68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128],
|
||||
],
|
||||
[
|
||||
[1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128],
|
||||
[184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128],
|
||||
[81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128],
|
||||
],
|
||||
[
|
||||
[1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128],
|
||||
[99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128],
|
||||
[23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128],
|
||||
],
|
||||
[
|
||||
[1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128],
|
||||
[109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128],
|
||||
[44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128],
|
||||
[94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128],
|
||||
[22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128],
|
||||
[124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128],
|
||||
[35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128],
|
||||
[121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128],
|
||||
[45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128],
|
||||
[203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128],
|
||||
[137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128],
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
[253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128],
|
||||
[175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128],
|
||||
[73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128],
|
||||
],
|
||||
[
|
||||
[1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128],
|
||||
[239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128],
|
||||
[155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128],
|
||||
[201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128],
|
||||
[69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128],
|
||||
[223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128],
|
||||
[141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128],
|
||||
[190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128],
|
||||
[149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
[247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
[240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128],
|
||||
[213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128],
|
||||
[55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
[128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
[128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
[202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255],
|
||||
[126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128],
|
||||
[61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128],
|
||||
],
|
||||
[
|
||||
[1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128],
|
||||
[166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128],
|
||||
[39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128],
|
||||
],
|
||||
[
|
||||
[1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128],
|
||||
[124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128],
|
||||
[24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128],
|
||||
],
|
||||
[
|
||||
[1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128],
|
||||
[149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128],
|
||||
[28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128],
|
||||
],
|
||||
[
|
||||
[1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128],
|
||||
[123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128],
|
||||
[20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128],
|
||||
[168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128],
|
||||
[47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128],
|
||||
[141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128],
|
||||
[42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128],
|
||||
],
|
||||
[
|
||||
[1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
[244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
[238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128],
|
||||
],
|
||||
],
|
||||
];
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue