diff --git a/examples/jpeg-decode.rs b/examples/jpeg-decode.rs
index 9fd921a..36235eb 100644
--- a/examples/jpeg-decode.rs
+++ b/examples/jpeg-decode.rs
@@ -2,11 +2,15 @@ use std::{num::NonZeroU32, rc::Rc, time::Instant};
use anyhow::bail;
use fev::{
+ buffer::{Buffer, BufferType},
+ config::Config,
+ context::Context,
display::Display,
image::{Image, ImageFormat},
jpeg::{JpegDecodeSession, JpegInfo},
- surface::ExportSurfaceFlags,
- PixelFormat,
+ surface::{ExportSurfaceFlags, Surface},
+ vpp::{ColorProperties, ColorStandardType, ProcPipelineParameterBuffer, SourceRange},
+ Entrypoint, PixelFormat, Profile,
};
use winit::{
dpi::PhysicalSize,
@@ -53,24 +57,31 @@ fn main() -> anyhow::Result<()> {
let graphics_context = softbuffer::Context::new(win.clone()).unwrap();
let mut surface = softbuffer::Surface::new(&graphics_context, win.clone()).unwrap();
- let PhysicalSize { width, height } = win.inner_size();
- log::info!("window size: {width}x{height}");
+ let s = win.inner_size();
+ log::info!("window size: {}x{}", s.width, s.height);
+
+ let jpeg_info = JpegInfo::new(&jpeg)?;
+ let (width, height) = (jpeg_info.width(), jpeg_info.height());
surface
.resize(
- NonZeroU32::new(info.width.into()).unwrap(),
- NonZeroU32::new(info.height.into()).unwrap(),
+ NonZeroU32::new(width.into()).unwrap(),
+ NonZeroU32::new(height.into()).unwrap(),
)
.unwrap();
let display = Display::new(win.clone())?;
- let jpeg_info = JpegInfo::new(&jpeg)?;
- let mut context = JpegDecodeSession::new(&display, jpeg_info.width(), jpeg_info.height())?;
+ let mut context = JpegDecodeSession::new(&display, width, height)?;
let prime = context
.surface()
.export_prime(ExportSurfaceFlags::SEPARATE_LAYERS | ExportSurfaceFlags::READ)?;
log::debug!("PRIME export: {prime:#?}");
+ let config = Config::new(&display, Profile::None, Entrypoint::VideoProc)?;
+ let mut vpp_context = Context::new(&config, width.into(), height.into())?;
+ let mut vpp_surface =
+ Surface::with_pixel_format(&display, width.into(), height.into(), PixelFormat::RGBA)?;
+
let mut image = Image::new(
&display,
ImageFormat::new(PixelFormat::RGBA),
@@ -80,9 +91,32 @@ fn main() -> anyhow::Result<()> {
log::debug!("");
let start = Instant::now();
- let surf = context.decode_and_convert(&jpeg)?;
+ let surf = context.decode(&jpeg)?;
log::debug!(" took {:?}", start.elapsed());
- surf.copy_to_image(&mut image)?;
+
+ // Use VPP to convert the surface to RGBA.
+ let mut pppbuf = ProcPipelineParameterBuffer::new(surf);
+
+ // The input color space is the JPEG color space
+ let input_props = ColorProperties::new().with_color_range(SourceRange::FULL);
+ pppbuf.set_input_color_properties(input_props);
+ pppbuf.set_input_color_standard(ColorStandardType::BT601);
+ // The output color space is 8-bit non-linear sRGB
+ let output_props = ColorProperties::new().with_color_range(SourceRange::FULL);
+ pppbuf.set_output_color_properties(output_props);
+ pppbuf.set_output_color_standard(ColorStandardType::SRGB);
+ // NB: not all implementations support converting color standards (eg. Mesa).
+ // such implementations will typically output an image that is brighter than the reference data.
+
+ let mut pppbuf = Buffer::new_param(&vpp_context, BufferType::ProcPipelineParameter, pppbuf)?;
+
+ let mut picture = vpp_context.begin_picture(&mut vpp_surface)?;
+ picture.render_picture(&mut pppbuf)?;
+ unsafe { picture.end_picture()? }
+
+ drop(pppbuf);
+
+ vpp_surface.copy_to_image(&mut image)?;
let mapping = image.map()?;
log::debug!("{} byte output", mapping.len());
diff --git a/src/jpeg.rs b/src/jpeg.rs
index 748ce9c..9a4116f 100644
--- a/src/jpeg.rs
+++ b/src/jpeg.rs
@@ -17,8 +17,7 @@ use crate::{
error::Error,
raw::{Rectangle, VA_PADDING_LOW, VA_PADDING_MEDIUM},
surface::{RTFormat, Surface},
- vpp::{ColorProperties, ColorStandardType, ProcPipelineParameterBuffer, SourceRange},
- Entrypoint, PixelFormat, Profile, Result, Rotation, SliceParameterBufferBase,
+ Entrypoint, Profile, Result, Rotation, SliceParameterBufferBase,
};
use self::parser::{JpegParser, SegmentKind, SofMarker};
@@ -420,12 +419,8 @@ impl JpegInfo {
pub struct JpegDecodeSession {
width: u32,
height: u32,
-
jpeg_surface: Surface,
- vpp_surface: Surface,
-
jpeg_context: Context,
- vpp_context: Context,
}
impl JpegDecodeSession {
@@ -444,19 +439,13 @@ impl JpegDecodeSession {
let config = Config::new(&display, Profile::JPEGBaseline, Entrypoint::VLD)?;
let jpeg_context = Context::new(&config, width, height)?;
- let config = Config::new(&display, Profile::None, Entrypoint::VideoProc)?;
- let vpp_context = Context::new(&config, width, height)?;
-
let jpeg_surface = Surface::new(&display, width, height, RTFormat::YUV420)?;
- let vpp_surface = Surface::with_pixel_format(&display, width, height, PixelFormat::RGBA)?;
Ok(Self {
width,
height,
jpeg_surface,
- vpp_surface,
jpeg_context,
- vpp_context,
})
}
@@ -614,29 +603,4 @@ impl JpegDecodeSession {
Ok(&mut self.jpeg_surface)
}
-
- pub fn decode_and_convert(&mut self, jpeg: &[u8]) -> Result<&mut Surface> {
- self.decode(jpeg)?;
-
- let mut pppbuf = ProcPipelineParameterBuffer::new(&self.jpeg_surface);
- // The input color space is the JPEG color space
- let input_props = ColorProperties::new().with_color_range(SourceRange::FULL);
- pppbuf.set_input_color_properties(input_props);
- pppbuf.set_input_color_standard(ColorStandardType::BT601);
- // The output color space is 8-bit non-linear sRGB
- let output_props = ColorProperties::new().with_color_range(SourceRange::FULL);
- pppbuf.set_output_color_properties(output_props);
- pppbuf.set_output_color_standard(ColorStandardType::SRGB);
-
- let mut pppbuf =
- Buffer::new_param(&self.vpp_context, BufferType::ProcPipelineParameter, pppbuf)?;
-
- let mut picture = self.vpp_context.begin_picture(&mut self.vpp_surface)?;
- picture.render_picture(&mut pppbuf)?;
- unsafe { picture.end_picture()? }
-
- drop(pppbuf);
-
- Ok(&mut self.vpp_surface)
- }
}
diff --git a/src/surface.rs b/src/surface.rs
index 79226a1..bce700e 100644
--- a/src/surface.rs
+++ b/src/surface.rs
@@ -485,6 +485,12 @@ impl Surface {
/// [`VAError::ERROR_OPERATION_FAILED`] if it's not supported. In that case, the caller should
/// fall back to creating an [`Image`] manually and using [`Surface::copy_to_image`]. The
/// [`SurfaceWithImage`] type encapsulates that pattern and should be used for this if possible.
+ ///
+ /// # Bugs
+ ///
+ /// - Mesa has a bug in its implementation of `vaDeriveImage` where the resulting [`Image`]
+ /// won't be mapped correctly and appear completely blank if this method is called before a
+ /// decode operation is submitted.
pub fn derive_image(&mut self) -> Result {
unsafe {
let mut image = MaybeUninit::uninit();