diff --git a/Cargo.lock b/Cargo.lock index dd3a7441fa..117ce5bfa8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 27c5dd97d5..33bd102c12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,7 +72,7 @@ members = [ "media/ffmpeg", "media/libva", "media/libvda", - "media/vp8", + "media/cros-codecs", "net_sys", "net_util", "power_monitor", diff --git a/devices/Cargo.toml b/devices/Cargo.toml index c2bd40074f..4e83f9871c 100644 --- a/devices/Cargo.toml +++ b/devices/Cargo.toml @@ -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" } diff --git a/devices/src/virtio/video/decoder/backend/vaapi.rs b/devices/src/virtio/video/decoder/backend/vaapi.rs index d99830c6dd..52e0ce1c3c 100644 --- a/devices/src/virtio/video/decoder/backend/vaapi.rs +++ b/devices/src/virtio/video/decoder/backend/vaapi.rs @@ -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>>, - current_resolution: Resolution, -} - -impl SurfacePoolHandle { - /// Creates a new pool - pub fn new(surfaces: Vec, 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 { - 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>>>, - /// The bitstream header parsed for this frame - header: Rc, - /// 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>>, - header: Rc, - 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>> { - 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 for Format { + type Error = anyhow::Error; + + fn try_from(value: DecodedFormat) -> Result { + match value { + DecodedFormat::NV12 => Ok(Format::NV12), + DecodedFormat::I420 => Err(anyhow!("Unsupported format")), + } + } +} + +impl TryFrom for DecodedFormat { + type Error = anyhow::Error; + + fn try_from(value: Format) -> Result { + match value { + Format::NV12 => Ok(DecodedFormat::NV12), + _ => Err(anyhow!("Unsupported format")), + } + } +} + impl TryFrom for Profile { type Error = anyhow::Error; @@ -185,52 +99,6 @@ impl TryFrom 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 }, - - /// 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, - /// 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 { - match self { - StreamMetadataState::Unparsed { display } => Rc::clone(display), - StreamMetadataState::Parsed { context, .. } => context.display(), - } - } - - fn context(&self) -> Result> { - match self { - StreamMetadataState::Unparsed { .. } => Err(anyhow!("Stream metadata not parsed yet")), - StreamMetadataState::Parsed { context, .. } => Ok(Rc::clone(context)), - } - } - - fn surface_pool(&self) -> Result { - match self { - StreamMetadataState::Unparsed { .. } => Err(anyhow!("Invalid state")), - StreamMetadataState::Parsed { surface_pool, .. } => Ok(surface_pool.clone()), - } - } - - fn get_surface(&mut self) -> Result { - 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, + codec: Box, /// 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, + ready_queue: VecDeque>, /// The event queue we can use to signal new events. event_queue: EventQueue, /// Whether the decoder is currently flushing. @@ -607,25 +475,6 @@ impl, U: BufferHandle> AsMut<[u8]> for BufferMapping { } impl VaapiDecoderSession { - /// Create the `num_surfaces` surfaces for a combination of `width`, - /// `height` and `rt_format`. - fn create_surfaces( - display: Rc, - width: u32, - height: u32, - rt_format: u32, - num_surfaces: usize, - ) -> Result> { - 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 { + pub fn output_picture(&mut self, decoded_frame: &dyn DynDecodedHandle) -> Result { 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 U, U>( - display: Rc, - picture: Rc>>, - 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 = - 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 = 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 { 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 = 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>; - - /// Flush the decoder i.e. finish processing all queued decode requests and - /// emit frames for them. - fn flush(&mut self) -> Result>; - - /// Returns the current VA image format - fn va_image_fmt(&self) -> &Option; - - /// 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; -} -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. diff --git a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-probability-table-0.bin b/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-probability-table-0.bin deleted file mode 100644 index 46ea618c62..0000000000 --- a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-probability-table-0.bin +++ /dev/null @@ -1,2 +0,0 @@ -€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€òˆþÿäÛ€€€€€½òÿãÕÿÛ€€€j~I3ÖÑÿ€€€bøÿìâÿÿ€€€µ…îþÝêÿš€€€N†Ê Æ´IÛ€€€¹ùÿóÿ€€€€€¸–÷ÿìà€€€€€MnØì怀€€€eûÿñÿ€€€€€ª‹ñüìÑÿÿ€€€%tÄóäÿÿ€€€Ìþÿõÿ€€€€€ úÿ€€€€fg`Ó«€€€€€˜Ë’ðÿ€€€€€8‡«£êက€€€.FÂà€ì€€ÿ€€€€€€€€f€€€€€€€€%€€€€€€€€€€Æ#íßÁ»¢ ‘›>ƒ-Æݬ°ÜüÝD/’Е§Ý¢ÿ߀•ñÿÝàÿÿ€€€¸êýÞÜÿÇ€€€Qcµò°¾ùÊÿÿ€èýÖÅòÄÿÿ€cyÒúÉÆÿÊ€€€[£òª»÷Òÿÿ€Èöÿêÿ€€€€€m²ñÿçõÿÿ€€€,‚ÉýÍÀÿÿ€€€„ïûÛÑÿ¥€€€^ˆáûÚ¾ÿÿ€€€d®õº¡ÿÇ€€€¶ùÿè뀀€€€|ñÿãꀀ€€€#MµûÁÓÿÍ€€€÷ÿìçÿÿ€€€yëÿáãÿÿ€€€-c¼UÃÙà€€€ûÿÕÿ€€€€€Ëøÿÿ€€€€€€‰±ÿàÿ€€€€€ý øûÏÐÿÀ€€€¯ ^+Á¹€Æ3ÿ€I« ¡³=§ê€_÷ýÔ·ÿÿ€€€OZôúÓÑÿÿ€€€M`¼Ãÿ€€ïûÚÛÿÍ€€€%3Ûÿ倀€€€E.¾ïÉÚÿ䀀€¿ûÿÿ€€€€€€/¥ùÿÕÿ€€€€€|øÿÿ€€€€€€nÿ€€€€€¾$æìÿ€€€€€•ÿ€€€€€€€€âÿ€€€€€€€€÷Àÿ€€€€€€€€€€€€€€€€†üÿÿ€€€€€€[‰úÿÿ€€€€€€7]ÿ€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€åÕº¿ ð¯]&_(©¸8®<»€:F—²4ª¨€€p‰KÇ¿EŸ³’€Qm›bÓ×D®€€€ -21:¬´$²šÃ4AÆÇ.ÜBr€AJY·Á$ݨ€G9>šª0sÎsâÕ£XÛðà€€€H––FØÍ(«€€€52Fuz*„ª¦ÿQ\#ÌËÀ€€æ>R2¼ÄP€€Ô$$8¤­;b®€ñ’tØÕ,€æ€€GzëÍ39€€€'=ˆÔŸ´Qðy”g®Ö†õ€ÿ6T}{Ê.fñ€ÿ/>Tƒ¹>{ï€ý—€€€€€€€€E €€€€÷€€:L€€€€ý€€ \ No newline at end of file diff --git a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-probability-table-1.bin b/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-probability-table-1.bin deleted file mode 100644 index 19b4062632..0000000000 --- a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-probability-table-1.bin +++ /dev/null @@ -1,2 +0,0 @@ -€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€òˆþÿäÛ€€€€€½òÿãÕÿÛ€€€j~I3ÖÑÿ€€€bøÿìâÿÿ€€€µ…îþÝêÿš€€€N†Ê Æ´IÛ€€€¹ùÿóÿ€€€€€¸–÷ÿìà€€€€€MnØì怀€€€eûÿñÿ€€€€€ª‹ñüìÑÿÿ€€€%tÄóäÿÿ€€€Ìþÿõÿ€€€€€ úÿ€€€€fg`Ó«€€€€€˜Ë’ðÿ€€€€€8‡«£êက€€€.FÂà€ì€€ÿ€€€€€€€€f€€€€€€€€%€€€€€€€€€€Æ#íßÁ»¢ ‘›>ƒ-Æݬ°ÜüÝD/’Е§Ý¢ÿ߀•ñÿÝàÿÿ€€€¸êýÞÜÿÇ€€€Qcµò°¾ùÊÿÿ€èýÖÅòÄÿÿ€cyÒúÉÆÿÊ€€€[£òª»÷Òÿÿ€Èöÿêÿ€€€€€m²ñÿçõÿÿ€€€,‚ÉýÍÀÿÿ€€€„ïûÛÑÿ¥€€€^ˆáûÚ¾ÿÿ€€€d®õº¡ÿÇ€€€¶ùÿè뀀€€€|ñÿãꀀ€€€#MµûÁÓÿÍ€€€÷ÿìçÿÿ€€€yëÿáãÿÿ€€€-c¼UÃÙà€€€ûÿÕÿ€€€€€Ëøÿÿ€€€€€€‰±ÿàÿ€€€€€ý øûÏÐÿÀ€€€¯ ^+Á¹€Æ3ÿ€I« ¡³=§ê€_÷ýÔ·ÿÿ€€€OZôúÓÑÿÿ€€€M`¼Ãÿ€€ïûÚÛÿÍ€€€%3Ûÿ倀€€€E.¾ïÉÚÿ䀀€¿ûÿÿ€€€€€€/¥ùÿÕÿ€€€€€|øÿÿ€€€€€€nÿ€€€€€¾$æìÿ€€€€€•ÿ€€€€€€€€âÿ€€€€€€€€÷Àÿ€€€€€€€€€€€€€€€€†üÿÿ€€€€€€[‰úÿÿ€€€€€€7]ÿ€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€åÕÿº¿ ð¯]&_(©¸8®<»€:F—²4ª¨€€p‰KÇ¿EŸ³’€Qm›bÓ×D®€€€ -21:¬´$²šÃ4AÆÇ.ÜBr€AJY·Á$ݨ€G9>šª0sÎsâÕ£XÛðà€€€H––FØÍ(«€€€52Fuz*„ª¦ÿQ\#ÌËÀ€€æ>R2¼ÄP€€Ô$$8¤­;b®€ñ’tØÕ,€æ€€GzëÍ39€€€'=ˆÔŸ´Qðyÿg®Ö†õ€ÿ·T}{Ê.fñ€ÿ/>Tƒ¹>{ï€ý—€€€€€€€€E €€€€÷€€:L€€€€ý€€ \ No newline at end of file diff --git a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-probability-table-2.bin b/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-probability-table-2.bin deleted file mode 100644 index 19b4062632..0000000000 --- a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-probability-table-2.bin +++ /dev/null @@ -1,2 +0,0 @@ -€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€òˆþÿäÛ€€€€€½òÿãÕÿÛ€€€j~I3ÖÑÿ€€€bøÿìâÿÿ€€€µ…îþÝêÿš€€€N†Ê Æ´IÛ€€€¹ùÿóÿ€€€€€¸–÷ÿìà€€€€€MnØì怀€€€eûÿñÿ€€€€€ª‹ñüìÑÿÿ€€€%tÄóäÿÿ€€€Ìþÿõÿ€€€€€ úÿ€€€€fg`Ó«€€€€€˜Ë’ðÿ€€€€€8‡«£êက€€€.FÂà€ì€€ÿ€€€€€€€€f€€€€€€€€%€€€€€€€€€€Æ#íßÁ»¢ ‘›>ƒ-Æݬ°ÜüÝD/’Е§Ý¢ÿ߀•ñÿÝàÿÿ€€€¸êýÞÜÿÇ€€€Qcµò°¾ùÊÿÿ€èýÖÅòÄÿÿ€cyÒúÉÆÿÊ€€€[£òª»÷Òÿÿ€Èöÿêÿ€€€€€m²ñÿçõÿÿ€€€,‚ÉýÍÀÿÿ€€€„ïûÛÑÿ¥€€€^ˆáûÚ¾ÿÿ€€€d®õº¡ÿÇ€€€¶ùÿè뀀€€€|ñÿãꀀ€€€#MµûÁÓÿÍ€€€÷ÿìçÿÿ€€€yëÿáãÿÿ€€€-c¼UÃÙà€€€ûÿÕÿ€€€€€Ëøÿÿ€€€€€€‰±ÿàÿ€€€€€ý øûÏÐÿÀ€€€¯ ^+Á¹€Æ3ÿ€I« ¡³=§ê€_÷ýÔ·ÿÿ€€€OZôúÓÑÿÿ€€€M`¼Ãÿ€€ïûÚÛÿÍ€€€%3Ûÿ倀€€€E.¾ïÉÚÿ䀀€¿ûÿÿ€€€€€€/¥ùÿÕÿ€€€€€|øÿÿ€€€€€€nÿ€€€€€¾$æìÿ€€€€€•ÿ€€€€€€€€âÿ€€€€€€€€÷Àÿ€€€€€€€€€€€€€€€€†üÿÿ€€€€€€[‰úÿÿ€€€€€€7]ÿ€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€åÕÿº¿ ð¯]&_(©¸8®<»€:F—²4ª¨€€p‰KÇ¿EŸ³’€Qm›bÓ×D®€€€ -21:¬´$²šÃ4AÆÇ.ÜBr€AJY·Á$ݨ€G9>šª0sÎsâÕ£XÛðà€€€H––FØÍ(«€€€52Fuz*„ª¦ÿQ\#ÌËÀ€€æ>R2¼ÄP€€Ô$$8¤­;b®€ñ’tØÕ,€æ€€GzëÍ39€€€'=ˆÔŸ´Qðyÿg®Ö†õ€ÿ·T}{Ê.fñ€ÿ/>Tƒ¹>{ï€ý—€€€€€€€€E €€€€÷€€:L€€€€ý€€ \ No newline at end of file diff --git a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-slice-data-0.bin b/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-slice-data-0.bin deleted file mode 100644 index bd6a684439..0000000000 Binary files a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-slice-data-0.bin and /dev/null differ diff --git a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-slice-data-1.bin b/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-slice-data-1.bin deleted file mode 100644 index 85ed11a63e..0000000000 Binary files a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-slice-data-1.bin and /dev/null differ diff --git a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-slice-data-2.bin b/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-slice-data-2.bin deleted file mode 100644 index 6391b98d92..0000000000 Binary files a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps-vp8-slice-data-2.bin and /dev/null differ diff --git a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps.vp8 b/devices/src/virtio/video/decoder/backend/vaapi/test-25fps.vp8 deleted file mode 100644 index dc22d43792..0000000000 Binary files a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps.vp8 and /dev/null differ diff --git a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps.vp8.crc b/devices/src/virtio/video/decoder/backend/vaapi/test-25fps.vp8.crc deleted file mode 100644 index 72f1ff6402..0000000000 --- a/devices/src/virtio/video/decoder/backend/vaapi/test-25fps.vp8.crc +++ /dev/null @@ -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 diff --git a/devices/src/virtio/video/decoder/backend/vaapi/vp8.rs b/devices/src/virtio/video/decoder/backend/vaapi/vp8.rs deleted file mode 100644 index 33a181da0b..0000000000 --- a/devices/src/virtio/video/decoder/backend/vaapi/vp8.rs +++ /dev/null @@ -1,1197 +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::cell::RefCell; -use std::convert::TryFrom; -use std::rc::Rc; - -use anyhow::anyhow; -use anyhow::Context; -use anyhow::Result; -use libva::BufferType; -use libva::IQMatrix; -use libva::IQMatrixBufferVP8; -use libva::Picture; -use libva::ProbabilityDataBufferVP8; -use vp8::parser as vp8; - -use crate::virtio::video::decoder::backend::vaapi::BufferMapping; -use crate::virtio::video::decoder::backend::vaapi::DecodedFrameHandle; -use crate::virtio::video::decoder::backend::vaapi::DrcParams; -use crate::virtio::video::decoder::backend::vaapi::Resolution; -use crate::virtio::video::decoder::backend::vaapi::StreamMetadataState; -use crate::virtio::video::decoder::backend::vaapi::SurfacePoolHandle; -use crate::virtio::video::decoder::backend::vaapi::VaapiCodec; -use crate::virtio::video::decoder::backend::vaapi::VaapiDecoderSession; -use crate::virtio::video::error::VideoError; -use crate::virtio::video::format::Format; -use crate::virtio::video::format::Rect; -use crate::virtio::video::resource::GuestResourceHandle; - -/// The number of surfaces to allocate for this codec. Same as GStreamer's vavp8dec. -const NUM_SURFACES: usize = 7; - -#[cfg(test)] -#[derive(Default)] -struct Params { - pic_param: Option, - slice_param: Option, - slice_data: Option, - iq_matrix: Option, - probability_table: Option, - last_pic: Option, -} - -pub struct Vp8Codec { - /// The metadata state. Updated whenever the decoder reads new data from the stream. - metadata_state: StreamMetadataState, - - /// A parser to extract bitstream data and build frame data in turn - parser: vp8::Parser, - - /// The picture used as the last reference picture. - last_picture: Option, - /// The picture used as the golden reference picture. - golden_ref_picture: Option, - /// The picture used as the alternate reference picture. - alt_ref_picture: Option, - - /// The VAImageFormat we will decode into - image_fmt: Option, - /// The current resolution - resolution: Resolution, - - /// Whether we are still waiting for the leading key frame. We skip all - /// frames until then, since decoding can only start from key frames. - wait_keyframe: bool, - - /// Whether the initial setup is done after reading some metadata for the - /// first time. - open: bool, - - /// Whether the codec has identified a dynamic resolution change. Cleared - /// when this information is relayed to the session. - drc: bool, - - #[cfg(test)] - params: Params, -} - -impl Vp8Codec { - /// Create a new codec backend for VP8. - pub fn new(display: Rc) -> Result { - Ok(Self { - metadata_state: StreamMetadataState::Unparsed { display }, - parser: Default::default(), - last_picture: Default::default(), - golden_ref_picture: Default::default(), - alt_ref_picture: Default::default(), - image_fmt: Default::default(), - resolution: Default::default(), - wait_keyframe: true, - open: Default::default(), - drc: Default::default(), - - #[cfg(test)] - params: Default::default(), - }) - } - - /// A clamp such that min <= x <= max - fn clamp(x: T, low: T, high: T) -> T { - if x > high { - high - } else if x < low { - low - } else { - x - } - } - - fn change_resolution(&mut self, resolution: Resolution) -> Result<()> { - self.resolution = resolution; - - let mut pool = self.metadata_state.surface_pool()?; - - // Tell the pool so it can refuse stale surfaces. - pool.set_current_resolution(resolution); - - self.drc = true; - - Ok(()) - } - - /// Initialize the codec state by reading some metadata from the current - /// frame. - fn open(&mut self, frame_hdr: &vp8::Header) -> Result<()> { - let display = self.metadata_state.display(); - - let va_profile = libva::VAProfile::VAProfileVP8Version0_3; - let rt_format = libva::constants::VA_RT_FORMAT_YUV420; - - let frame_w = u32::from(frame_hdr.width()); - let frame_h = u32::from(frame_hdr.height()); - - let attrs = vec![libva::VAConfigAttrib { - type_: libva::VAConfigAttribType::VAConfigAttribRTFormat, - value: rt_format, - }]; - - let config = display.create_config( - Some(attrs), - va_profile, - libva::VAEntrypoint::VAEntrypointVLD, - )?; - - let surfaces = VaapiDecoderSession::create_surfaces( - Rc::clone(&display), - frame_w, - frame_h, - rt_format, - NUM_SURFACES, - )?; - - let context = Rc::new(display.create_context( - &config, - i32::try_from(frame_w)?, - i32::try_from(frame_h)?, - Some(&surfaces), - true, - )?); - - let resolution = Resolution { - width: frame_w, - height: frame_h, - }; - - let surface_pool = SurfacePoolHandle::new(surfaces, resolution); - - self.metadata_state = StreamMetadataState::Parsed { - context, - config, - surface_pool, - }; - - self.change_resolution(resolution)?; - - Ok(()) - } - - /// Check for new stream parameters. This might mean that the surfaces - /// and/or context get recreated. If a new resolution is detected, the - /// decoder will enter a DRC state and it will ask crosvm for new output - /// buffers to write to. - fn check_stream_params(&mut self, frame_hdr: &vp8::Header) -> Result<()> { - let frame_w = u32::from(frame_hdr.width()); - let frame_h = u32::from(frame_hdr.height()); - - assert!(frame_hdr.version() <= 3); - - let rt_format = libva::constants::VA_RT_FORMAT_YUV420; - - let recreate_surfaces = - self.resolution.width != frame_w || self.resolution.height != frame_h; - - if recreate_surfaces { - let display = self.metadata_state.display(); - let surfaces = VaapiDecoderSession::create_surfaces( - display, - frame_w, - frame_h, - rt_format, - NUM_SURFACES, - )?; - - let mut pool = self.metadata_state.surface_pool()?; - - // Drop the old surfaces still in the pool - pool.drop_surfaces(); - - for surface in surfaces { - pool.add_surface(surface) - } - - self.change_resolution(Resolution { - width: frame_w, - height: frame_h, - })?; - } - - Ok(()) - } - - fn build_iq_matrix(frame_hdr: &vp8::Header, parser: &vp8::Parser) -> Result { - let mut quantization_index: [[u16; 6]; 4] = Default::default(); - let seg = parser.segmentation(); - - for (i, quantization_index) in quantization_index.iter_mut().enumerate() { - let mut qi_base: i16; - - if seg.segmentation_enabled { - qi_base = i16::from(seg.quantizer_update_value[i]); - if !seg.segment_feature_mode { - qi_base += i16::from(frame_hdr.quant_indices().y_ac_qi); - } - } else { - qi_base = i16::from(frame_hdr.quant_indices().y_ac_qi); - } - - let mut qi = qi_base; - quantization_index[0] = Vp8Codec::clamp(u16::try_from(qi)?, 0, 127); - qi = qi_base + i16::from(frame_hdr.quant_indices().y_dc_delta); - quantization_index[1] = Vp8Codec::clamp(u16::try_from(qi)?, 0, 127); - qi = qi_base + i16::from(frame_hdr.quant_indices().y2_dc_delta); - quantization_index[2] = Vp8Codec::clamp(u16::try_from(qi)?, 0, 127); - qi = qi_base + i16::from(frame_hdr.quant_indices().y2_ac_delta); - quantization_index[3] = Vp8Codec::clamp(u16::try_from(qi)?, 0, 127); - qi = qi_base + i16::from(frame_hdr.quant_indices().uv_dc_delta); - quantization_index[4] = Vp8Codec::clamp(u16::try_from(qi)?, 0, 127); - qi = qi_base + i16::from(frame_hdr.quant_indices().uv_ac_delta); - quantization_index[5] = Vp8Codec::clamp(u16::try_from(qi)?, 0, 127); - } - - Ok(BufferType::IQMatrix(IQMatrix::VP8(IQMatrixBufferVP8::new( - quantization_index, - )))) - } - - fn build_probability_table(frame_hdr: &vp8::Header) -> libva::BufferType { - BufferType::Probability(ProbabilityDataBufferVP8::new(frame_hdr.coeff_prob())) - } - - fn build_pic_param( - frame_hdr: &vp8::Header, - resolution: &Resolution, - seg: &vp8::Segmentation, - adj: &vp8::MbLfAdjustments, - last: &Option, - golden: &Option, - alt: &Option, - ) -> Result { - let mut loop_filter_level: [u8; 4] = Default::default(); - let mut loop_filter_deltas_ref_frame: [i8; 4] = Default::default(); - let mut loop_filter_deltas_mode: [i8; 4] = Default::default(); - - for i in 0..4 { - let mut level; - if seg.segmentation_enabled { - level = seg.lf_update_value[i]; - if !seg.segment_feature_mode { - level += i8::try_from(frame_hdr.loop_filter_level())?; - } - } else { - level = i8::try_from(frame_hdr.loop_filter_level())?; - } - - loop_filter_level[i] = Vp8Codec::clamp(u8::try_from(level)?, 0, 63); - loop_filter_deltas_ref_frame[i] = adj.ref_frame_delta[i]; - loop_filter_deltas_mode[i] = adj.mb_mode_delta[i]; - } - - let last_surface = if let Some(last_ref) = last { - last_ref.picture().borrow().surface().id() - } else { - libva::constants::VA_INVALID_SURFACE - }; - - let golden_surface = if let Some(golden_ref) = golden { - golden_ref.picture().borrow().surface().id() - } else { - libva::constants::VA_INVALID_SURFACE - }; - - let alt_surface = if let Some(alt_ref) = alt { - alt_ref.picture().borrow().surface().id() - } else { - libva::constants::VA_INVALID_SURFACE - }; - - let pic_fields = libva::VP8PicFields::new( - u32::from(!frame_hdr.key_frame()), - u32::from(frame_hdr.version()), - u32::from(seg.segmentation_enabled), - u32::from(seg.update_mb_segmentation_map), - u32::from(seg.update_segment_feature_data), - u32::from(frame_hdr.filter_type()), - u32::from(frame_hdr.sharpness_level()), - u32::from(adj.loop_filter_adj_enable), - u32::from(adj.mode_ref_lf_delta_update), - u32::from(frame_hdr.sign_bias_golden()), - u32::from(frame_hdr.sign_bias_alternate()), - u32::from(frame_hdr.mb_no_coeff_skip()), - u32::from(frame_hdr.loop_filter_level() == 0), - ); - - let bool_coder_ctx = libva::BoolCoderContextVPX::new( - u8::try_from(frame_hdr.bd_range())?, - u8::try_from(frame_hdr.bd_value())?, - u8::try_from(frame_hdr.bd_count())?, - ); - - let pic_param = libva::PictureParameterBufferVP8::new( - resolution.width, - resolution.height, - last_surface, - golden_surface, - alt_surface, - &pic_fields, - seg.segment_prob, - loop_filter_level, - loop_filter_deltas_ref_frame, - loop_filter_deltas_mode, - frame_hdr.prob_skip_false(), - frame_hdr.prob_intra(), - frame_hdr.prob_last(), - frame_hdr.prob_golden(), - frame_hdr.mode_probs().intra_16x16_prob, - frame_hdr.mode_probs().intra_chroma_prob, - frame_hdr.mv_prob(), - &bool_coder_ctx, - ); - - Ok(libva::BufferType::PictureParameter( - libva::PictureParameter::VP8(pic_param), - )) - } - - fn build_slice_param(frame_hdr: &vp8::Header, slice_size: usize) -> Result { - let mut partition_size: [u32; 9] = Default::default(); - let num_of_partitions = (1 << frame_hdr.log2_nbr_of_dct_partitions()) + 1; - - partition_size[0] = frame_hdr.first_part_size() - ((frame_hdr.header_size() + 7) >> 3); - - partition_size[1..num_of_partitions] - .clone_from_slice(&frame_hdr.partition_size()[..(num_of_partitions - 1)]); - - Ok(libva::BufferType::SliceParameter( - libva::SliceParameter::VP8(libva::SliceParameterBufferVP8::new( - u32::try_from(slice_size)?, - u32::from(frame_hdr.data_chunk_size()), - 0, - frame_hdr.header_size(), - u8::try_from(num_of_partitions)?, - partition_size, - )), - )) - } - - /// Replace a reference frame with `picture`. - fn replace_reference(reference: &mut Option, picture: &DecodedFrameHandle) { - *reference = Some(picture.clone()); - } - - fn update_references( - decoded_frame: &DecodedFrameHandle, - last_picture: &mut Option, - golden_ref_picture: &mut Option, - alt_ref_picture: &mut Option, - ) -> Result<()> { - let header = decoded_frame - .header - .downcast_ref::() - .with_context(|| "decoded frame header is not a VP8 header")?; - - if header.key_frame() { - Vp8Codec::replace_reference(last_picture, decoded_frame); - Vp8Codec::replace_reference(golden_ref_picture, decoded_frame); - Vp8Codec::replace_reference(alt_ref_picture, decoded_frame); - } else { - if header.refresh_alternate_frame() { - Vp8Codec::replace_reference(alt_ref_picture, decoded_frame); - } else { - match header.copy_buffer_to_alternate() { - 0 => { /* do nothing */ } - - 1 => { - if let Some(last_picture) = last_picture { - Vp8Codec::replace_reference(alt_ref_picture, last_picture); - } - } - - 2 => { - if let Some(golden_ref) = golden_ref_picture { - Vp8Codec::replace_reference(alt_ref_picture, golden_ref); - } - } - - other => panic!("Invalid value: {}", other), - } - } - - if header.refresh_golden_frame() { - Vp8Codec::replace_reference(golden_ref_picture, decoded_frame); - } else { - match header.copy_buffer_to_golden() { - 0 => { /* do nothing */ } - - 1 => { - if let Some(last_picture) = last_picture { - Vp8Codec::replace_reference(golden_ref_picture, last_picture); - } - } - - 2 => { - if let Some(alt_ref) = alt_ref_picture { - Vp8Codec::replace_reference(golden_ref_picture, alt_ref); - } - } - - other => panic!("Invalid value: {}", other), - } - } - - if header.refresh_last() { - Vp8Codec::replace_reference(last_picture, decoded_frame); - } - } - - Ok(()) - } - - #[cfg(test)] - fn save_params( - params: &mut Params, - pic_param: BufferType, - slice_param: BufferType, - slice_data: BufferType, - iq_matrix: BufferType, - probability_table: BufferType, - last_pic: DecodedFrameHandle, - ) { - params.pic_param = Some(pic_param); - params.slice_param = Some(slice_param); - params.slice_data = Some(slice_data); - params.iq_matrix = Some(iq_matrix); - params.probability_table = Some(probability_table); - params.last_pic = Some(last_pic); - } - - /// Decode a single frame, copying the decoded data into the output buffer - /// as per the format in `self.image_fmt`. - fn decode_frame>( - &mut self, - frame: vp8::Frame, - timestamp: u64, - ) -> Result { - let context = self.metadata_state.context()?; - - let iq_buffer = - context.create_buffer(Vp8Codec::build_iq_matrix(&frame.header, &self.parser)?)?; - let probs = context.create_buffer(Vp8Codec::build_probability_table(&frame.header))?; - - let pic_param = context.create_buffer(Vp8Codec::build_pic_param( - &frame.header, - &self.resolution, - self.parser.segmentation(), - self.parser.mb_lf_adjust(), - &self.last_picture, - &self.golden_ref_picture, - &self.alt_ref_picture, - )?)?; - - let slice_param = context.create_buffer(Vp8Codec::build_slice_param( - &frame.header, - frame.bitstream.as_ref().len(), - )?)?; - let slice_data = context.create_buffer(libva::BufferType::SliceData(Vec::from( - frame.bitstream.as_ref(), - )))?; - - let context = self.metadata_state.context()?; - let surface = self.metadata_state.get_surface()?; - - let mut picture = Picture::new(timestamp, Rc::clone(&context), surface); - - // Add buffers with the parsed data. - picture.add_buffer(iq_buffer); - picture.add_buffer(probs); - picture.add_buffer(pic_param); - picture.add_buffer(slice_param); - picture.add_buffer(slice_data); - - let picture = picture.begin()?.render()?.end()?.sync()?; - let picture = Rc::new(RefCell::new(picture)); - - #[cfg(test)] - Vp8Codec::save_params( - &mut self.params, - Vp8Codec::build_pic_param( - &frame.header, - &self.resolution, - self.parser.segmentation(), - self.parser.mb_lf_adjust(), - &self.last_picture, - &self.golden_ref_picture, - &self.alt_ref_picture, - )?, - Vp8Codec::build_slice_param(&frame.header, frame.bitstream.as_ref().len())?, - libva::BufferType::SliceData(Vec::from(frame.bitstream.as_ref())), - Vp8Codec::build_iq_matrix(&frame.header, &self.parser)?, - Vp8Codec::build_probability_table(&frame.header), - DecodedFrameHandle::new( - Rc::clone(&picture), - Rc::new(frame.header.clone()), - self.resolution, - self.metadata_state.surface_pool()?, - ), - ); - - let decoded_frame = DecodedFrameHandle::new( - picture, - Rc::new(frame.header), - self.resolution, - self.metadata_state.surface_pool()?, - ); - - // Do DPB management - Vp8Codec::update_references( - &decoded_frame, - &mut self.last_picture, - &mut self.golden_ref_picture, - &mut self.alt_ref_picture, - )?; - - Ok(decoded_frame) - } - - /// Handle a single frame. - fn handle_frame>( - &mut self, - frame: vp8::Frame, - timestamp: u64, - ) -> Result> { - if self.wait_keyframe { - if !frame.header.key_frame() { - return Ok(Vec::new()); - } - } - - if !self.open { - self.open(&frame.header)?; - self.open = true; - } - - self.wait_keyframe = false; - - if frame.header.key_frame() { - // Always check for changes at every key frame - self.check_stream_params(&frame.header)?; - } - - Ok(vec![(self.decode_frame(frame, timestamp)?)]) - } -} - -impl VaapiCodec for Vp8Codec { - fn decode( - &mut self, - timestamp: u64, - resource: &GuestResourceHandle, - offset: u32, - bytes_used: u32, - ) -> Result> { - let bytes_used = - usize::try_from(bytes_used).map_err(|e| VideoError::BackendFailure(anyhow!(e)))?; - - let offset = usize::try_from(offset).map_err(|e| VideoError::BackendFailure(anyhow!(e)))?; - - let bitstream_map: BufferMapping<_, GuestResourceHandle> = - BufferMapping::new(resource, offset, bytes_used)?; - let frame = self - .parser - .parse_frame(bitstream_map.as_ref()) - .map_err(|e| VideoError::BackendFailure(anyhow!(e)))?; - - self.handle_frame(frame, timestamp) - } - - fn flush(&mut self) -> Result> { - self.wait_keyframe = true; - - // VP8 has no internal picture queue, so simply return nothing here. - Ok(vec![]) - } - - fn va_image_fmt(&self) -> &Option { - &self.image_fmt - } - - fn set_raw_fmt(&mut self, format: Format) -> Result<()> { - let image_formats = self.metadata_state.display().query_image_formats()?; - - //TODO: this is hardcoded to NV12 for now. Will change when a proper - //Format is implemented in the libva crate so we can use TryFrom. - let image_fmt = image_formats - .into_iter() - .find(|f| f.fourcc == libva::constants::VA_FOURCC_NV12) - .with_context(|| format!("unsupported format {}", format))?; - - self.image_fmt = Some(image_fmt); - - Ok(()) - } - - fn drc(&mut self) -> Option { - if self.drc { - self.drc = false; - - Some(DrcParams { - min_num_buffers: NUM_SURFACES, - width: self.resolution.width, - height: self.resolution.height, - visible_rect: Rect { - left: 0, - top: 0, - right: self.resolution.width as i32, - bottom: self.resolution.height as i32, - }, - }) - } else { - None - } - } -} - -#[cfg(test)] -mod tests { - use std::io::Cursor; - use std::io::Read; - use std::io::Seek; - - use base::FromRawDescriptor; - use base::SafeDescriptor; - use base::SharedMemory; - use bytes::Buf; - use libva::BufferType; - use libva::IQMatrix; - use libva::PictureParameter; - use libva::SliceParameter; - - use crate::virtio::video::decoder::backend::vaapi::tests::build_resource; - use crate::virtio::video::decoder::backend::vaapi::vp8::Vp8Codec; - use crate::virtio::video::decoder::backend::vaapi::vp8::NUM_SURFACES; - use crate::virtio::video::decoder::backend::vaapi::VaapiDecoder; - use crate::virtio::video::decoder::backend::vaapi::VaapiDecoderSession; - use crate::virtio::video::decoder::backend::DecoderBackend; - use crate::virtio::video::decoder::backend::DecoderEvent; - use crate::virtio::video::decoder::backend::DecoderSession; - use crate::virtio::video::format::Format; - use crate::virtio::video::format::FramePlane; - use crate::virtio::video::format::Rect; - use crate::virtio::video::resource::GuestMemArea; - use crate::virtio::video::resource::GuestMemHandle; - use crate::virtio::video::resource::GuestResource; - use crate::virtio::video::resource::GuestResourceHandle; - - fn get_codec(session: &mut VaapiDecoderSession) -> &mut Vp8Codec { - session.codec.as_mut().downcast_mut::().unwrap() - } - - /// Read and return the data from the next IVF packet. Returns `None` if there is no more data - /// to read. - fn read_ivf_packet(cursor: &mut Cursor<&[u8]>) -> Option> { - if !cursor.has_remaining() { - return None; - } - - let len = cursor.get_u32_le(); - // Skip PTS. - let _ = cursor.get_u64_le(); - - let mut buf = vec![0u8; len as usize]; - cursor.read_exact(&mut buf).unwrap(); - - Some(buf.into_boxed_slice()) - } - - #[test] - // Ignore this test by default as it requires libva-compatible hardware. - #[ignore] - fn test_25fps_vp8() { - // Test video stream and its properties. Compare the parameters for frames - // 0,1, 2, and make sure the rest does not fail by unwraping the result - // of codec.handle_frame() - const TEST_25_FPS_VP8_STREAM: &[u8] = include_bytes!("test-25fps.vp8"); - const TEST_25_FPS_VP8_STREAM_WIDTH: i32 = 320; - const TEST_25_FPS_VP8_STREAM_HEIGHT: i32 = 240; - const NUM_BUFS: u32 = NUM_SURFACES as u32; - - // Extracted using "LIBVA_TRACE=libva LIBVA_TRACE_BUFDATA=1 gst-launch-1.0 - // filesrc location=test-25fps.vp8 ! parsebin ! vavp8dec ! fakevideosink" - // A couple frames worth of data should make it easier spot parser/decoder - // issues in contrast with using only a crc check - const TEST_25_FPS_VP8_STREAM_SLICE_DATA_0: &[u8] = - include_bytes!("test-25fps-vp8-slice-data-0.bin"); - const TEST_25_FPS_VP8_STREAM_SLICE_DATA_1: &[u8] = - include_bytes!("test-25fps-vp8-slice-data-1.bin"); - const TEST_25_FPS_VP8_STREAM_SLICE_DATA_2: &[u8] = - include_bytes!("test-25fps-vp8-slice-data-2.bin"); - - const TEST_25_FPS_VP8_STREAM_PROBABILITY_TABLE_0: &[u8] = - include_bytes!("test-25fps-vp8-probability-table-0.bin"); - const TEST_25_FPS_VP8_STREAM_PROBABILITY_TABLE_1: &[u8] = - include_bytes!("test-25fps-vp8-probability-table-1.bin"); - const TEST_25_FPS_VP8_STREAM_PROBABILITY_TABLE_2: &[u8] = - include_bytes!("test-25fps-vp8-probability-table-2.bin"); - - const VP8_STREAM_CRCS: &str = include_str!("test-25fps.vp8.crc"); - let mut expected_frames_crcs = VP8_STREAM_CRCS.lines(); - - let mut cursor = Cursor::new(TEST_25_FPS_VP8_STREAM); - // Confirm the width and height of the stream. - cursor.seek(std::io::SeekFrom::Start(12)).unwrap(); - let w = cursor.get_u16_le(); - let h = cursor.get_u16_le(); - assert!(w as i32 == TEST_25_FPS_VP8_STREAM_WIDTH); - assert!(h as i32 == TEST_25_FPS_VP8_STREAM_HEIGHT); - - // Skip the IVH header entirely. - cursor.seek(std::io::SeekFrom::Start(32)).unwrap(); - - let mut decoder = VaapiDecoder::new().unwrap(); - let mut session = decoder.new_session(Format::VP8).unwrap(); - - // Output buffers suitable for receiving NV12 frames for our stream. - let output_buffers = (0..NUM_BUFS) - .into_iter() - .map(|_| { - SharedMemory::new( - "", - (TEST_25_FPS_VP8_STREAM_WIDTH * TEST_25_FPS_VP8_STREAM_HEIGHT * 3 / 2) as u64, - ) - .unwrap() - }) - .collect::>(); - - let mut frame_num = 0; - while let Some(packet) = read_ivf_packet(&mut cursor) { - session - .decode( - 0, - frame_num as u64, - build_resource(packet.as_ref()), - 0, - packet.len() as u32, - ) - .unwrap(); - - // After sending the first buffer we should get the initial - // resolution change event and can provide the frames to decode - // into. - if frame_num == 0 { - assert!(session.event_queue.len() == 2); - - // Done with input buffer 0 and Waiting for output buffers. - assert!(matches!( - session.read_event().unwrap(), - DecoderEvent::ProvidePictureBuffers { - min_num_buffers: NUM_BUFS, - width: TEST_25_FPS_VP8_STREAM_WIDTH, - height: TEST_25_FPS_VP8_STREAM_HEIGHT, - visible_rect: Rect { - left: 0, - top: 0, - right: TEST_25_FPS_VP8_STREAM_WIDTH, - bottom: TEST_25_FPS_VP8_STREAM_HEIGHT, - }, - } | DecoderEvent::NotifyEndOfBitstreamBuffer(0) - )); - - assert!(matches!( - session.read_event().unwrap(), - DecoderEvent::ProvidePictureBuffers { - min_num_buffers: NUM_BUFS, - width: TEST_25_FPS_VP8_STREAM_WIDTH, - height: TEST_25_FPS_VP8_STREAM_HEIGHT, - visible_rect: Rect { - left: 0, - top: 0, - right: TEST_25_FPS_VP8_STREAM_WIDTH, - bottom: TEST_25_FPS_VP8_STREAM_HEIGHT, - }, - } | DecoderEvent::NotifyEndOfBitstreamBuffer(0) - )); - - session - .set_output_parameters(NUM_BUFS as usize, Format::NV12) - .unwrap(); - - // Pass the buffers we will decode into. - for (picture_buffer_id, buffer) in output_buffers.iter().enumerate() { - let handle = GuestResourceHandle::GuestPages(GuestMemHandle { - // Safe because we are taking ownership of a just-duplicated FD. - desc: unsafe { - SafeDescriptor::from_raw_descriptor( - base::clone_descriptor(buffer).unwrap(), - ) - }, - mem_areas: vec![GuestMemArea { - offset: 0, - length: buffer.size() as usize, - }], - }); - - session - .use_output_buffer( - picture_buffer_id as i32, - GuestResource { - handle, - planes: vec![ - FramePlane { - offset: 0, - stride: TEST_25_FPS_VP8_STREAM_WIDTH as usize, - size: (TEST_25_FPS_VP8_STREAM_WIDTH - * TEST_25_FPS_VP8_STREAM_HEIGHT) - as usize, - }, - FramePlane { - offset: (TEST_25_FPS_VP8_STREAM_WIDTH - * TEST_25_FPS_VP8_STREAM_HEIGHT) - as usize, - stride: TEST_25_FPS_VP8_STREAM_WIDTH as usize, - size: (TEST_25_FPS_VP8_STREAM_WIDTH - * TEST_25_FPS_VP8_STREAM_HEIGHT - / 2) - as usize, - }, - ], - width: TEST_25_FPS_VP8_STREAM_WIDTH as u32, - height: TEST_25_FPS_VP8_STREAM_HEIGHT as u32, - format: Format::NV12, - }, - ) - .unwrap(); - } - } - - let codec = get_codec(&mut session); - let params = &codec.params; - let pic_param = match params.pic_param { - Some(BufferType::PictureParameter(PictureParameter::VP8(ref pic_param))) => { - pic_param - } - _ => panic!(), - }; - - let slice_param = match params.slice_param { - Some(BufferType::SliceParameter(SliceParameter::VP8(ref slice_param))) => { - slice_param - } - _ => panic!(), - }; - - let slice_data = match params.slice_data { - Some(BufferType::SliceData(ref data)) => data, - _ => panic!(), - }; - - let iq_matrix = match params.iq_matrix { - Some(BufferType::IQMatrix(IQMatrix::VP8(ref iq_matrix))) => iq_matrix, - _ => panic!(), - }; - - let probability_table = match params.probability_table { - Some(BufferType::Probability(ref probability_table)) => probability_table, - _ => panic!(), - }; - - let last_pic = params.last_pic.as_ref().unwrap(); - - // Uncomment to dump the YUV output to /tmp - // VaapiDecoderSession::get_test_nv12( - // codec.metadata_state.display(), - // last_pic.picture(), - // 320, - // 240, - // |nv12| { - // std::fs::write( - // format!("/tmp/{}_frame{}.yuv", "test_25fps.vp8", frame_num), - // nv12, - // ) - // .unwrap(); - // }, - // ); - - let frame_crc = VaapiDecoderSession::get_test_nv12( - codec.metadata_state.display(), - last_pic.picture(), - 320, - 240, - crc32fast::hash, - ); - assert_eq!( - format!("{:08x}", frame_crc), - expected_frames_crcs - .next() - .expect("No CRC for decoded frame") - ); - - if frame_num == 0 { - assert_eq!(iq_matrix.inner().quantization_index, [[4; 6]; 4]); - for i in 0..4 { - for j in 0..8 { - for k in 0..3 { - for l in 0..11 { - const OFF_I: usize = 8 * 3 * 11; - const OFF_J: usize = 3 * 11; - const OFF_K: usize = 11; - // maybe std::transmute? - assert_eq!( - probability_table.inner().dct_coeff_probs[i][j][k][l], - TEST_25_FPS_VP8_STREAM_PROBABILITY_TABLE_0 - [(i * OFF_I) + (j * OFF_J) + (k * OFF_K) + l] - ); - } - } - } - } - - assert_eq!(pic_param.inner().frame_width, 320); - assert_eq!(pic_param.inner().frame_height, 240); - assert_eq!( - pic_param.inner().last_ref_frame, - libva::constants::VA_INVALID_SURFACE - ); - assert_eq!( - pic_param.inner().golden_ref_frame, - libva::constants::VA_INVALID_SURFACE - ); - assert_eq!( - pic_param.inner().alt_ref_frame, - libva::constants::VA_INVALID_SURFACE - ); - assert_eq!( - pic_param.inner().out_of_loop_frame, - libva::constants::VA_INVALID_SURFACE - ); - - // Safe because this bitfield is initialized by the decoder. - assert_eq!(unsafe { pic_param.inner().pic_fields.value }, unsafe { - libva::VP8PicFields::new(0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1) - .inner() - .value - }); - - assert_eq!(pic_param.inner().mb_segment_tree_probs, [0; 3]); - assert_eq!(pic_param.inner().loop_filter_level, [0; 4]); - assert_eq!( - pic_param.inner().loop_filter_deltas_ref_frame, - [2, 0, -2, -2] - ); - assert_eq!(pic_param.inner().loop_filter_deltas_mode, [4, -2, 2, 4]); - assert_eq!(pic_param.inner().prob_skip_false, 0xbe); - assert_eq!(pic_param.inner().prob_intra, 0); - assert_eq!(pic_param.inner().prob_last, 0); - assert_eq!(pic_param.inner().prob_gf, 0); - - assert_eq!(pic_param.inner().y_mode_probs, [0x91, 0x9c, 0xa3, 0x80]); - assert_eq!(pic_param.inner().uv_mode_probs, [0x8e, 0x72, 0xb7]); - assert_eq!( - pic_param.inner().mv_probs[0], - [ - 0xa2, 0x80, 0xe1, 0x92, 0xac, 0x93, 0xd6, 0x27, 0x9c, 0x80, 0x81, 0x84, - 0x4b, 0x91, 0xb2, 0xce, 0xef, 0xfe, 0xfe - ] - ); - assert_eq!( - pic_param.inner().mv_probs[1], - [ - 0xa4, 0x80, 0xcc, 0xaa, 0x77, 0xeb, 0x8c, 0xe6, 0xe4, 0x80, 0x82, 0x82, - 0x4a, 0x94, 0xb4, 0xcb, 0xec, 0xfe, 0xfe, - ] - ); - - assert_eq!(pic_param.inner().bool_coder_ctx.range, 0xfc); - assert_eq!(pic_param.inner().bool_coder_ctx.value, 0x39); - assert_eq!(pic_param.inner().bool_coder_ctx.count, 0x0); - - assert_eq!( - slice_param.inner(), - libva::SliceParameterBufferVP8::new( - 14788, - 10, - 0, - 3040, - 2, - [926, 13472, 0, 0, 0, 0, 0, 0, 0], - ) - .inner(), - ); - - assert_eq!(&slice_data[..], TEST_25_FPS_VP8_STREAM_SLICE_DATA_0); - } else if frame_num == 1 { - assert_eq!(iq_matrix.inner().quantization_index, [[0x7f; 6]; 4]); - for i in 0..4 { - for j in 0..8 { - for k in 0..3 { - for l in 0..11 { - const OFF_I: usize = 8 * 3 * 11; - const OFF_J: usize = 3 * 11; - const OFF_K: usize = 11; - // maybe std::transmute? - assert_eq!( - probability_table.inner().dct_coeff_probs[i][j][k][l], - TEST_25_FPS_VP8_STREAM_PROBABILITY_TABLE_1 - [(i * OFF_I) + (j * OFF_J) + (k * OFF_K) + l] - ); - } - } - } - } - assert_eq!(pic_param.inner().frame_width, 320); - assert_eq!(pic_param.inner().frame_height, 240); - assert_eq!(pic_param.inner().last_ref_frame, 0); - assert_eq!(pic_param.inner().golden_ref_frame, 0); - assert_eq!(pic_param.inner().alt_ref_frame, 0); - assert_eq!( - pic_param.inner().out_of_loop_frame, - libva::constants::VA_INVALID_SURFACE - ); - - // Safe because this bitfield is initialized by the decoder. - assert_eq!(unsafe { pic_param.inner().pic_fields.value }, unsafe { - libva::VP8PicFields::new(1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0) - .inner() - .value - }); - - assert_eq!(pic_param.inner().mb_segment_tree_probs, [0; 3]); - assert_eq!(pic_param.inner().loop_filter_level, [44; 4]); - assert_eq!( - pic_param.inner().loop_filter_deltas_ref_frame, - [2, 0, -2, -2] - ); - assert_eq!(pic_param.inner().loop_filter_deltas_mode, [4, -2, 2, 4]); - assert_eq!(pic_param.inner().prob_skip_false, 0x11); - assert_eq!(pic_param.inner().prob_intra, 0x2a); - assert_eq!(pic_param.inner().prob_last, 0xff); - assert_eq!(pic_param.inner().prob_gf, 0x80); - - assert_eq!(pic_param.inner().y_mode_probs, [0x70, 0x56, 0x8c, 0x25]); - assert_eq!(pic_param.inner().uv_mode_probs, [0xa2, 0x65, 0xcc]); - assert_eq!( - pic_param.inner().mv_probs[0], - [ - 0xa2, 0x80, 0xe1, 0x92, 0xac, 0x93, 0xd6, 0x27, 0x9c, 0x80, 0x81, 0x84, - 0x4b, 0x91, 0xb2, 0xce, 0xef, 0xfe, 0xfe, - ] - ); - assert_eq!( - pic_param.inner().mv_probs[1], - [ - 0xa4, 0x80, 0xcc, 0xaa, 0x77, 0xeb, 0x8c, 0xe6, 0xe4, 0x80, 0x82, 0x82, - 0x4a, 0x94, 0xb4, 0xcb, 0xec, 0xfe, 0xfe, - ] - ); - - assert_eq!(pic_param.inner().bool_coder_ctx.range, 0xde); - assert_eq!(pic_param.inner().bool_coder_ctx.value, 0x39); - assert_eq!(pic_param.inner().bool_coder_ctx.count, 0x7); - - assert_eq!( - slice_param.inner(), - libva::SliceParameterBufferVP8::new( - 257, - 3, - 0, - 129, - 2, - [143, 94, 0, 0, 0, 0, 0, 0, 0], - ) - .inner() - ); - - assert_eq!(&slice_data[..], TEST_25_FPS_VP8_STREAM_SLICE_DATA_1); - } else if frame_num == 2 { - assert_eq!(iq_matrix.inner().quantization_index, [[0x7f; 6]; 4]); - for i in 0..4 { - for j in 0..8 { - for k in 0..3 { - for l in 0..11 { - const OFF_I: usize = 8 * 3 * 11; - const OFF_J: usize = 3 * 11; - const OFF_K: usize = 11; - // maybe std::transmute? - assert_eq!( - probability_table.inner().dct_coeff_probs[i][j][k][l], - TEST_25_FPS_VP8_STREAM_PROBABILITY_TABLE_2 - [(i * OFF_I) + (j * OFF_J) + (k * OFF_K) + l] - ); - } - } - } - } - assert_eq!(pic_param.inner().frame_width, 320); - assert_eq!(pic_param.inner().frame_height, 240); - assert_eq!(pic_param.inner().last_ref_frame, 1); - assert_eq!(pic_param.inner().golden_ref_frame, 0); - assert_eq!(pic_param.inner().alt_ref_frame, 0); - assert_eq!( - pic_param.inner().out_of_loop_frame, - libva::constants::VA_INVALID_SURFACE - ); - - // Safe because this bitfield is initialized by the decoder. - assert_eq!(unsafe { pic_param.inner().pic_fields.value }, unsafe { - libva::VP8PicFields::new(1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0) - .inner() - .value - }); - - assert_eq!(pic_param.inner().mb_segment_tree_probs, [0; 3]); - assert_eq!(pic_param.inner().loop_filter_level, [28; 4]); - assert_eq!( - pic_param.inner().loop_filter_deltas_ref_frame, - [2, 0, -2, -2] - ); - assert_eq!(pic_param.inner().loop_filter_deltas_mode, [4, -2, 2, 4]); - assert_eq!(pic_param.inner().prob_skip_false, 0x6); - assert_eq!(pic_param.inner().prob_intra, 0x1); - assert_eq!(pic_param.inner().prob_last, 0xf8); - assert_eq!(pic_param.inner().prob_gf, 0xff); - - assert_eq!(pic_param.inner().y_mode_probs, [0x70, 0x56, 0x8c, 0x25]); - assert_eq!(pic_param.inner().uv_mode_probs, [0xa2, 0x65, 0xcc]); - assert_eq!( - pic_param.inner().mv_probs[0], - [ - 0xa2, 0x80, 0xe1, 0x92, 0xac, 0x93, 0xd6, 0x27, 0x9c, 0x80, 0x81, 0x84, - 0x4b, 0x91, 0xb2, 0xce, 0xef, 0xfe, 0xfe, - ] - ); - assert_eq!( - pic_param.inner().mv_probs[1], - [ - 0xa4, 0x80, 0xcc, 0xaa, 0x77, 0xeb, 0x8c, 0xe6, 0xe4, 0x80, 0x82, 0x82, - 0x4a, 0x94, 0xb4, 0xcb, 0xec, 0xfe, 0xfe, - ] - ); - - assert_eq!(pic_param.inner().bool_coder_ctx.range, 0xb1); - assert_eq!(pic_param.inner().bool_coder_ctx.value, 0xd); - assert_eq!(pic_param.inner().bool_coder_ctx.count, 0x2); - - assert_eq!( - slice_param.inner(), - libva::SliceParameterBufferVP8::new( - 131, - 3, - 0, - 86, - 2, - [66, 51, 0, 0, 0, 0, 0, 0, 0], - ) - .inner() - ); - - assert_eq!(&slice_data[..], TEST_25_FPS_VP8_STREAM_SLICE_DATA_2); - } - - // Assume for the purposes of this test that the output buffer can - // be reused, otherwise we are going to run out - let _ = session.reuse_output_buffer(frame_num as i32 % NUM_BUFS as i32); - frame_num += 1; - } - } -} diff --git a/media/vp8/Cargo.toml b/media/vp8/Cargo.toml deleted file mode 100644 index efedec11bc..0000000000 --- a/media/vp8/Cargo.toml +++ /dev/null @@ -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"]} diff --git a/media/vp8/src/bool_decoder.rs b/media/vp8/src/bool_decoder.rs deleted file mode 100644 index 424a4be761..0000000000 --- a/media/vp8/src/bool_decoder.rs +++ /dev/null @@ -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::() * 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 { - data: Cursor, - range: usize, - value: usize, - count: isize, -} - -impl> BoolDecoder { - /// 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 { - 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 { - 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 { - 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 { - self.read_bit(probability) - } - - /// Reads an unsigned literal from the coded stream. - pub fn read_uint>(&mut self, nbits: usize) -> Result { - 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>(&mut self, nbits: usize) -> Result { - 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::(1).unwrap() == 0); - assert!(bd.read_sint::(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::(1).unwrap() == -1); - assert!(bd.read_sint::(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); - } - } - } -} diff --git a/media/vp8/src/lib.rs b/media/vp8/src/lib.rs deleted file mode 100644 index 6f6b7c9ced..0000000000 --- a/media/vp8/src/lib.rs +++ /dev/null @@ -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; diff --git a/media/vp8/src/parser.rs b/media/vp8/src/parser.rs deleted file mode 100644 index 4aa5944ff5..0000000000 --- a/media/vp8/src/parser.rs +++ /dev/null @@ -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> { - /// The abstraction for the raw memory for this frame. - pub bitstream: T, - /// The frame header. - pub header: Header, -} - -impl> Frame { - /// Creates a new frame, using the resource as its backing memory. - fn new(bitstream: T) -> Self { - Self { - bitstream, - header: Default::default(), - } - } -} - -impl> AsRef<[u8]> for Frame { - 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>( - &mut self, - reader: &mut Cursor, - 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>( - bd: &mut BoolDecoder, - 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>( - bd: &mut BoolDecoder, - 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>( - bd: &mut BoolDecoder, - 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>( - bd: &mut BoolDecoder, - 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>( - bd: &mut BoolDecoder, - 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::(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>(bd: &BoolDecoder, 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>(&mut self, resource: T) -> Result> { - 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); - } -} diff --git a/media/vp8/src/probs.rs b/media/vp8/src/probs.rs deleted file mode 100644 index d37b18b546..0000000000 --- a/media/vp8/src/probs.rs +++ /dev/null @@ -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], - ], - ], -]; diff --git a/media/vp8/src/vp8-parser-test-0-inter.bin b/media/vp8/src/vp8-parser-test-0-inter.bin deleted file mode 100644 index 6fce364dd8..0000000000 Binary files a/media/vp8/src/vp8-parser-test-0-inter.bin and /dev/null differ diff --git a/media/vp8/src/vp8-parser-test-0-intra.bin b/media/vp8/src/vp8-parser-test-0-intra.bin deleted file mode 100644 index 6bc44d1c69..0000000000 Binary files a/media/vp8/src/vp8-parser-test-0-intra.bin and /dev/null differ