forked from mirrors/gstreamer-rs
video: Add support for static HDR metadata
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/270
This commit is contained in:
parent
c2a2549b66
commit
4e235b0492
2 changed files with 351 additions and 0 deletions
|
@ -103,6 +103,13 @@ pub mod video_codec_state;
|
|||
pub use crate::video_codec_state::{VideoCodecState, VideoCodecStateContext};
|
||||
mod utils;
|
||||
|
||||
#[cfg(any(feature = "v1_18", feature = "dox"))]
|
||||
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))]
|
||||
mod video_hdr;
|
||||
#[cfg(any(feature = "v1_18", feature = "dox"))]
|
||||
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))]
|
||||
pub use crate::video_hdr::*;
|
||||
|
||||
pub const VIDEO_ENCODER_FLOW_NEED_DATA: gst::FlowSuccess = gst::FlowSuccess::CustomSuccess;
|
||||
pub const VIDEO_DECODER_FLOW_NEED_DATA: gst::FlowSuccess = gst::FlowSuccess::CustomSuccess;
|
||||
|
||||
|
|
344
gstreamer-video/src/video_hdr.rs
Normal file
344
gstreamer-video/src/video_hdr.rs
Normal file
|
@ -0,0 +1,344 @@
|
|||
// Take a look at the license at the top of the repository in the LICENSE file.
|
||||
|
||||
use glib::translate::*;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::str;
|
||||
|
||||
#[doc(alias = "GstVideoContentLightLevel")]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct VideoContentLightLevel(ffi::GstVideoContentLightLevel);
|
||||
|
||||
impl VideoContentLightLevel {
|
||||
pub fn new(max_content_light_level: u16, max_frame_average_light_level: u16) -> Self {
|
||||
assert_initialized_main_thread!();
|
||||
|
||||
VideoContentLightLevel(ffi::GstVideoContentLightLevel {
|
||||
max_content_light_level,
|
||||
max_frame_average_light_level,
|
||||
_gst_reserved: [ptr::null_mut(); 4],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn max_content_light_level(&self) -> u16 {
|
||||
self.0.max_content_light_level
|
||||
}
|
||||
|
||||
pub fn set_max_content_light_level(&mut self, max_content_light_level: u16) {
|
||||
self.0.max_content_light_level = max_content_light_level;
|
||||
}
|
||||
|
||||
pub fn max_frame_average_light_level(&self) -> u16 {
|
||||
self.0.max_frame_average_light_level
|
||||
}
|
||||
|
||||
pub fn set_max_frame_average_light_level(&mut self, max_frame_average_light_level: u16) {
|
||||
self.0.max_frame_average_light_level = max_frame_average_light_level;
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_video_content_light_level_add_to_caps")]
|
||||
pub fn add_to_caps(&self, caps: &mut gst::CapsRef) {
|
||||
unsafe {
|
||||
ffi::gst_video_content_light_level_add_to_caps(&self.0, caps.as_mut_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_video_content_light_level_from_caps")]
|
||||
pub fn from_caps(caps: &gst::CapsRef) -> Result<Self, glib::BoolError> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
unsafe {
|
||||
let mut info = mem::MaybeUninit::zeroed();
|
||||
let res: bool = from_glib(ffi::gst_video_content_light_level_from_caps(
|
||||
info.as_mut_ptr(),
|
||||
caps.as_ptr(),
|
||||
));
|
||||
|
||||
if res {
|
||||
Ok(VideoContentLightLevel(info.assume_init()))
|
||||
} else {
|
||||
Err(glib::bool_error!(
|
||||
"Failed to parse VideoContentLightLevel from caps"
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a gst::CapsRef> for VideoContentLightLevel {
|
||||
type Error = glib::BoolError;
|
||||
|
||||
fn try_from(value: &'a gst::CapsRef) -> Result<Self, Self::Error> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
Self::from_caps(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for VideoContentLightLevel {
|
||||
#[doc(alias = "gst_video_content_light_level_is_equal")]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
#[cfg(feature = "v1_20")]
|
||||
unsafe {
|
||||
from_glib(ffi::gst_video_content_light_level_is_equal(
|
||||
&self.0, &other.0,
|
||||
))
|
||||
}
|
||||
#[cfg(not(feature = "v1_20"))]
|
||||
{
|
||||
self.0.max_content_light_level == other.0.max_content_light_level
|
||||
&& self.0.max_frame_average_light_level == other.0.max_frame_average_light_level
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for VideoContentLightLevel {}
|
||||
|
||||
impl str::FromStr for VideoContentLightLevel {
|
||||
type Err = glib::error::BoolError;
|
||||
|
||||
#[doc(alias = "gst_video_content_light_level_from_string")]
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
assert_initialized_main_thread!();
|
||||
|
||||
unsafe {
|
||||
let mut colorimetry = mem::MaybeUninit::zeroed();
|
||||
let valid: bool = from_glib(ffi::gst_video_content_light_level_from_string(
|
||||
colorimetry.as_mut_ptr(),
|
||||
s.to_glib_none().0,
|
||||
));
|
||||
if valid {
|
||||
Ok(Self(colorimetry.assume_init()))
|
||||
} else {
|
||||
Err(glib::bool_error!("Invalid colorimetry info"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for VideoContentLightLevel {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("VideoContentLightLevel")
|
||||
.field("max_content_light_level", &self.0.max_content_light_level)
|
||||
.field(
|
||||
"max_frame_average_light_level",
|
||||
&self.0.max_frame_average_light_level,
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for VideoContentLightLevel {
|
||||
#[doc(alias = "gst_video_content_light_level_to_string")]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let s = unsafe {
|
||||
glib::GString::from_glib_full(ffi::gst_video_content_light_level_to_string(&self.0))
|
||||
};
|
||||
f.write_str(&s)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "GstVideoMasteringDisplayInfo")]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct VideoMasteringDisplayInfo(ffi::GstVideoMasteringDisplayInfo);
|
||||
|
||||
impl VideoMasteringDisplayInfo {
|
||||
pub fn new(
|
||||
display_primaries: [VideoMasteringDisplayInfoCoordinate; 3],
|
||||
white_point: VideoMasteringDisplayInfoCoordinate,
|
||||
max_display_mastering_luminance: u32,
|
||||
min_display_mastering_luminance: u32,
|
||||
) -> Self {
|
||||
assert_initialized_main_thread!();
|
||||
|
||||
VideoMasteringDisplayInfo(ffi::GstVideoMasteringDisplayInfo {
|
||||
display_primaries: unsafe { mem::transmute(display_primaries) },
|
||||
white_point: unsafe { mem::transmute(white_point) },
|
||||
max_display_mastering_luminance,
|
||||
min_display_mastering_luminance,
|
||||
_gst_reserved: [ptr::null_mut(); 4],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn display_primaries(&self) -> [VideoMasteringDisplayInfoCoordinate; 3] {
|
||||
unsafe { mem::transmute(self.0.display_primaries) }
|
||||
}
|
||||
|
||||
pub fn set_display_primaries(
|
||||
&mut self,
|
||||
display_primaries: [VideoMasteringDisplayInfoCoordinate; 3],
|
||||
) {
|
||||
self.0.display_primaries = unsafe { mem::transmute(display_primaries) };
|
||||
}
|
||||
|
||||
pub fn white_point(&self) -> VideoMasteringDisplayInfoCoordinate {
|
||||
unsafe { mem::transmute(self.0.white_point) }
|
||||
}
|
||||
|
||||
pub fn set_white_point(&mut self, white_point: VideoMasteringDisplayInfoCoordinate) {
|
||||
self.0.white_point = unsafe { mem::transmute(white_point) };
|
||||
}
|
||||
|
||||
pub fn max_display_mastering_luminance(&self) -> u32 {
|
||||
self.0.max_display_mastering_luminance
|
||||
}
|
||||
|
||||
pub fn set_max_display_mastering_luminance(&mut self, max_display_mastering_luminance: u32) {
|
||||
self.0.max_display_mastering_luminance = max_display_mastering_luminance;
|
||||
}
|
||||
|
||||
pub fn min_display_mastering_luminance(&self) -> u32 {
|
||||
self.0.min_display_mastering_luminance
|
||||
}
|
||||
|
||||
pub fn set_min_display_mastering_luminance(&mut self, min_display_mastering_luminance: u32) {
|
||||
self.0.min_display_mastering_luminance = min_display_mastering_luminance;
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_video_mastering_display_info_add_to_caps")]
|
||||
pub fn add_to_caps(&self, caps: &mut gst::CapsRef) {
|
||||
unsafe {
|
||||
ffi::gst_video_mastering_display_info_add_to_caps(&self.0, caps.as_mut_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_video_mastering_display_info_from_caps")]
|
||||
pub fn from_caps(caps: &gst::CapsRef) -> Result<Self, glib::BoolError> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
unsafe {
|
||||
let mut info = mem::MaybeUninit::zeroed();
|
||||
let res: bool = from_glib(ffi::gst_video_mastering_display_info_from_caps(
|
||||
info.as_mut_ptr(),
|
||||
caps.as_ptr(),
|
||||
));
|
||||
|
||||
if res {
|
||||
Ok(VideoMasteringDisplayInfo(info.assume_init()))
|
||||
} else {
|
||||
Err(glib::bool_error!(
|
||||
"Failed to parse VideoMasteringDisplayInfo from caps"
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a gst::CapsRef> for VideoMasteringDisplayInfo {
|
||||
type Error = glib::BoolError;
|
||||
|
||||
fn try_from(value: &'a gst::CapsRef) -> Result<Self, Self::Error> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
Self::from_caps(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for VideoMasteringDisplayInfo {
|
||||
#[doc(alias = "gst_video_mastering_display_info_is_equal")]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
unsafe {
|
||||
from_glib(ffi::gst_video_mastering_display_info_is_equal(
|
||||
&self.0, &other.0,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for VideoMasteringDisplayInfo {}
|
||||
|
||||
impl str::FromStr for VideoMasteringDisplayInfo {
|
||||
type Err = glib::error::BoolError;
|
||||
|
||||
#[doc(alias = "gst_video_mastering_display_info_from_string")]
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
assert_initialized_main_thread!();
|
||||
|
||||
unsafe {
|
||||
let mut colorimetry = mem::MaybeUninit::zeroed();
|
||||
let valid: bool = from_glib(ffi::gst_video_mastering_display_info_from_string(
|
||||
colorimetry.as_mut_ptr(),
|
||||
s.to_glib_none().0,
|
||||
));
|
||||
if valid {
|
||||
Ok(Self(colorimetry.assume_init()))
|
||||
} else {
|
||||
Err(glib::bool_error!("Invalid colorimetry info"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for VideoMasteringDisplayInfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("VideoMasteringDisplayInfo")
|
||||
.field("display_primaries", &self.display_primaries())
|
||||
.field("white_point", &self.white_point())
|
||||
.field(
|
||||
"max_display_mastering_luminance",
|
||||
&self.0.max_display_mastering_luminance,
|
||||
)
|
||||
.field(
|
||||
"min_display_mastering_luminance",
|
||||
&self.0.min_display_mastering_luminance,
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for VideoMasteringDisplayInfo {
|
||||
#[doc(alias = "gst_video_mastering_display_info_to_string")]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let s = unsafe {
|
||||
glib::GString::from_glib_full(ffi::gst_video_mastering_display_info_to_string(&self.0))
|
||||
};
|
||||
f.write_str(&s)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[doc(alias = "GstVideoMasteringDisplayInfoCoordinates")]
|
||||
pub struct VideoMasteringDisplayInfoCoordinate {
|
||||
pub x: u16,
|
||||
pub y: u16,
|
||||
}
|
||||
|
||||
impl VideoMasteringDisplayInfoCoordinate {
|
||||
pub fn new(x: f32, y: f32) -> Self {
|
||||
skip_assert_initialized!();
|
||||
|
||||
Self {
|
||||
x: (x * 50000.0) as u16,
|
||||
y: (y * 50000.0) as u16,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn x(&self) -> f32 {
|
||||
self.x as f32 / 50000.0
|
||||
}
|
||||
|
||||
pub fn y(&self) -> f32 {
|
||||
self.y as f32 / 50000.0
|
||||
}
|
||||
|
||||
pub fn set_x(&mut self, x: f32) {
|
||||
self.x = (x * 50000.0) as u16;
|
||||
}
|
||||
|
||||
pub fn set_y(&mut self, y: f32) {
|
||||
self.y = (y * 50000.0) as u16;
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for VideoMasteringDisplayInfoCoordinate {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("VideoMasteringDisplayInfoCoordinate")
|
||||
.field("x", &self.x())
|
||||
.field("y", &self.y())
|
||||
.finish()
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue