blob: 01c74c6146d9012e25c93c0815f66fdbd30b2989 [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::fs::File;
use std::io::Read;
use std::marker::PhantomData;
use std::mem;
use std::os::raw::c_void;
use std::os::unix::io::FromRawFd;
use super::bindings;
use super::event::*;
use super::vda_instance::VdaInstance;
use crate::error::*;
use crate::format::{BufferFd, FramePlane, PixelFormat, Profile};
/// Represents a decode session.
pub struct Session<'a> {
// Pipe file to be notified decode session events.
pipe: File,
vda_ptr: *mut c_void,
raw_ptr: *mut bindings::vda_session_info_t,
// `phantom` gurantees that `Session` won't outlive the lifetime of `VdaInstance` that owns
// `vda_ptr`.
phantom: PhantomData<&'a VdaInstance>,
}
impl<'a> Session<'a> {
/// Creates a new `Session`.
///
/// This function is safe if `vda_ptr` is a non-NULL pointer obtained from
/// `bindings::initialize`.
pub(crate) unsafe fn new(vda_ptr: *mut c_void, profile: Profile) -> Option<Self> {
// `init_decode_session` is safe if `vda_ptr` is a non-NULL pointer from
// `bindings::initialize`.
let raw_ptr: *mut bindings::vda_session_info_t =
bindings::init_decode_session(vda_ptr, profile.to_raw_profile());
if raw_ptr.is_null() {
return None;
}
// Dereferencing `raw_ptr` is safe because it is a valid pointer to a FD provided by libvda.
// We need to dup() the `event_pipe_fd` because File object close() the FD while libvda also
// close() it when `close_decode_session` is called.
let pipe = File::from_raw_fd(libc::dup((*raw_ptr).event_pipe_fd));
Some(Session {
pipe,
vda_ptr,
raw_ptr,
phantom: PhantomData,
})
}
/// Gets a reference of pipe that notifies events from VDA session.
pub fn pipe(&self) -> &File {
&self.pipe
}
/// Reads an `Event` object from a pipe provided a decode session.
pub fn read_event(&mut self) -> Result<Event> {
const BUF_SIZE: usize = mem::size_of::<bindings::vda_event_t>();
let mut buf = [0u8; BUF_SIZE];
self.pipe
.read_exact(&mut buf)
.map_err(Error::ReadEventFailure)?;
// Safe because libvda must have written vda_event_t to the pipe.
let vda_event = unsafe { mem::transmute::<[u8; BUF_SIZE], bindings::vda_event_t>(buf) };
// Safe because `vda_event` is a value read from `self.pipe`.
unsafe { Event::new(vda_event) }
}
/// Sends a decode request for a bitstream buffer given as `fd`.
///
/// `fd` will be closed by Chrome after decoding has occurred.
pub fn decode(
&self,
bitstream_id: i32,
fd: BufferFd,
offset: u32,
bytes_used: u32,
) -> Result<()> {
// Safe because `raw_ptr` is valid and a libvda's API is called properly.
let r = unsafe {
bindings::vda_decode((*self.raw_ptr).ctx, bitstream_id, fd, offset, bytes_used)
};
Response::new(r).into()
}
/// Sets the number of expected output buffers.
///
/// This function must be called after `Event::ProvidePictureBuffers` are notified.
/// After calling this function, `user_output_buffer` must be called `num_output_buffers` times.
pub fn set_output_buffer_count(&self, num_output_buffers: usize) -> Result<()> {
// Safe because `raw_ptr` is valid and a libvda's API is called properly.
let r = unsafe {
bindings::vda_set_output_buffer_count((*self.raw_ptr).ctx, num_output_buffers)
};
Response::new(r).into()
}
/// Provides an output buffer that will be filled with decoded frames.
///
/// Users calls this function after `set_output_buffer_count`. Then, libvda
/// will fill next frames in the buffer and noitify `Event::PictureReady`.
///
/// This function is also used to notify that they consumed decoded frames
/// in the output buffer.
///
/// This function takes ownership of `output_buffer`.
pub fn use_output_buffer(
&self,
picture_buffer_id: i32,
format: PixelFormat,
output_buffer: BufferFd,
planes: &[FramePlane],
) -> Result<()> {
let mut planes: Vec<_> = planes.iter().map(FramePlane::to_raw_frame_plane).collect();
// Safe because `raw_ptr` is valid and a libvda's API is called properly.
let r = unsafe {
bindings::vda_use_output_buffer(
(*self.raw_ptr).ctx,
picture_buffer_id,
format.to_raw_pixel_format(),
output_buffer,
planes.len(),
planes.as_mut_ptr(),
)
};
Response::new(r).into()
}
/// Returns an output buffer for reuse.
///
/// `picture_buffer_id` must be a value for which `use_output_buffer` has been called already.
pub fn reuse_output_buffer(&self, picture_buffer_id: i32) -> Result<()> {
// Safe because `raw_ptr` is valid and a libvda's API is called properly.
let r =
unsafe { bindings::vda_reuse_output_buffer((*self.raw_ptr).ctx, picture_buffer_id) };
Response::new(r).into()
}
/// Flushes the decode session.
///
/// When this operation has completed, `Event::FlushResponse` will be notified.
pub fn flush(&self) -> Result<()> {
// Safe because `raw_ptr` is valid and a libvda's API is called properly.
let r = unsafe { bindings::vda_flush((*self.raw_ptr).ctx) };
Response::new(r).into()
}
/// Resets the decode session.
///
/// When this operation has completed, Event::ResetResponse will be notified.
pub fn reset(&self) -> Result<()> {
// Safe because `raw_ptr` is valid and a libvda's API is called properly.
let r = unsafe { bindings::vda_reset((*self.raw_ptr).ctx) };
Response::new(r).into()
}
}
impl<'a> Drop for Session<'a> {
fn drop(&mut self) {
// Safe because `vda_ptr` and `raw_ptr` are unchanged from the time `new` was called.
// Also, `vda_ptr` is valid because `phantom` guranteed that `VdaInstance` owning `vda_ptr`
// is not dropped yet.
unsafe {
bindings::close_decode_session(self.vda_ptr, self.raw_ptr);
}
}
}