fmp4mux: Fixed logging for unsupported orientation tags

Fmp4mux State and Stream structs now store matrix references instead
of orientation enum.

The TransformMatrix is wrapped into a struct for Default trait which
is needed by struct State.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1975>
This commit is contained in:
Jochen Henneberg 2024-12-10 15:14:55 +01:00 committed by GStreamer Marge Bot
parent aeb37c5ab1
commit 58ee9e2b9f
3 changed files with 62 additions and 49 deletions

View file

@ -12,7 +12,7 @@ use gst::prelude::*;
use anyhow::{anyhow, bail, Context, Error}; use anyhow::{anyhow, bail, Context, Error};
use std::convert::TryFrom; use std::convert::TryFrom;
use super::{transform_matrix, Buffer, IDENTITY_MATRIX}; use super::Buffer;
fn write_box<T, F: FnOnce(&mut Vec<u8>) -> Result<T, Error>>( fn write_box<T, F: FnOnce(&mut Vec<u8>) -> Result<T, Error>>(
vec: &mut Vec<u8>, vec: &mut Vec<u8>,
@ -522,8 +522,7 @@ fn write_mvhd(
v.extend([0u8; 2 + 2 * 4]); v.extend([0u8; 2 + 2 * 4]);
// Matrix // Matrix
let matrix = transform_matrix(&cfg.orientation); v.extend(cfg.orientation.iter().flatten());
v.extend(matrix.iter().flatten());
// Pre defined // Pre defined
v.extend([0u8; 6 * 4]); v.extend([0u8; 6 * 4]);
@ -639,15 +638,8 @@ fn write_tkhd(
// Reserved // Reserved
v.extend([0u8; 2]); v.extend([0u8; 2]);
// Matrix // Per stream orientation matrix.
let matrix = match s.name().as_str() { v.extend(stream.orientation.iter().flatten());
x if x.starts_with("video/") || x.starts_with("image/") => {
transform_matrix(&stream.orientation)
}
_ => &IDENTITY_MATRIX,
};
v.extend(matrix.iter().flatten());
// Width/height // Width/height
match s.name().as_str() { match s.name().as_str() {

View file

@ -20,6 +20,7 @@ use std::ops::Bound::Excluded;
use std::sync::Mutex; use std::sync::Mutex;
use crate::fmp4mux::obu::read_seq_header_obu_bytes; use crate::fmp4mux::obu::read_seq_header_obu_bytes;
use crate::fmp4mux::TransformMatrix;
use std::sync::LazyLock; use std::sync::LazyLock;
use super::boxes; use super::boxes;
@ -257,7 +258,7 @@ struct Stream {
/// Language code from tags /// Language code from tags
language_code: Option<[u8; 3]>, language_code: Option<[u8; 3]>,
/// Orientation from tags /// Orientation from tags
orientation: Option<gst_video::VideoOrientationMethod>, orientation: &'static TransformMatrix,
/// Edit list entries for this stream. /// Edit list entries for this stream.
elst_infos: Vec<super::ElstInfo>, elst_infos: Vec<super::ElstInfo>,
@ -391,7 +392,7 @@ struct State {
/// Start DTS of the whole stream /// Start DTS of the whole stream
start_dts: Option<gst::ClockTime>, start_dts: Option<gst::ClockTime>,
/// Orientation from tags /// Orientation from tags
orientation: Option<gst_video::VideoOrientationMethod>, orientation: &'static TransformMatrix,
/// Start PTS of the current fragment /// Start PTS of the current fragment
fragment_start_pts: Option<gst::ClockTime>, fragment_start_pts: Option<gst::ClockTime>,
@ -2980,7 +2981,7 @@ impl FMP4Mux {
// Check if language or orientation tags have already been // Check if language or orientation tags have already been
// received // received
let mut orientation = None; let mut orientation = Default::default();
let mut language_code = None; let mut language_code = None;
pad.sticky_events_foreach(|ev| { pad.sticky_events_foreach(|ev| {
if let gst::EventView::Tag(ev) = ev.view() { if let gst::EventView::Tag(ev) = ev.view() {
@ -3000,9 +3001,9 @@ impl FMP4Mux {
language_code = Stream::parse_language_code(l.get()); language_code = Stream::parse_language_code(l.get());
} else if tag.get::<gst::tags::ImageOrientation>().is_some() { } else if tag.get::<gst::tags::ImageOrientation>().is_some() {
if tag.scope() == gst::TagScope::Global { if tag.scope() == gst::TagScope::Global {
state.orientation = gst_video::VideoOrientationMethod::from_tag(tag); state.orientation = TransformMatrix::from_tag(self, ev);
} else { } else {
orientation = gst_video::VideoOrientationMethod::from_tag(tag); orientation = TransformMatrix::from_tag(self, ev);
} }
} }
} }
@ -3168,9 +3169,7 @@ impl FMP4Mux {
caps: s.caps.clone(), caps: s.caps.clone(),
extra_header_data: s.extra_header_data.clone(), extra_header_data: s.extra_header_data.clone(),
language_code: s.language_code, language_code: s.language_code,
orientation: s orientation: s.orientation,
.orientation
.unwrap_or(gst_video::VideoOrientationMethod::Identity),
elst_infos: s.get_elst_infos().unwrap_or_else(|e| { elst_infos: s.get_elst_infos().unwrap_or_else(|e| {
gst::error!(CAT, "Could not prepare edit lists: {e:?}"); gst::error!(CAT, "Could not prepare edit lists: {e:?}");
@ -3193,9 +3192,7 @@ impl FMP4Mux {
streams, streams,
write_mehd: settings.write_mehd, write_mehd: settings.write_mehd,
duration: if at_eos { duration } else { None }, duration: if at_eos { duration } else { None },
orientation: state orientation: state.orientation,
.orientation
.unwrap_or(gst_video::VideoOrientationMethod::Identity),
write_edts, write_edts,
start_utc_time: if variant == super::Variant::ONVIF { start_utc_time: if variant == super::Variant::ONVIF {
state state
@ -3772,10 +3769,10 @@ impl AggregatorImpl for FMP4Mux {
state.need_new_header = true; state.need_new_header = true;
if tag.scope() == gst::TagScope::Stream { if tag.scope() == gst::TagScope::Stream {
let stream = state.mut_stream_from_pad(aggregator_pad).unwrap(); let stream = state.mut_stream_from_pad(aggregator_pad).unwrap();
stream.orientation = gst_video::VideoOrientationMethod::from_tag(tag); stream.orientation = TransformMatrix::from_tag(self, ev);
stream.tag_changed = true; stream.tag_changed = true;
} else { } else {
state.orientation = gst_video::VideoOrientationMethod::from_tag(tag); state.orientation = TransformMatrix::from_tag(self, ev);
// Global orientation change implies tag // Global orientation change implies tag
// change on all streams // change on all streams
for stream in &mut state.streams { for stream in &mut state.streams {

View file

@ -9,6 +9,7 @@
use crate::fmp4mux::imp::CAT; use crate::fmp4mux::imp::CAT;
use gst::glib; use gst::glib;
use gst::prelude::*; use gst::prelude::*;
use gst::subclass::prelude::*;
mod boxes; mod boxes;
mod imp; mod imp;
@ -75,14 +76,56 @@ pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
Ok(()) Ok(())
} }
type TransformMatrix = [[u8; 4]; 9]; #[derive(Debug)]
pub(crate) struct TransformMatrix([[u8; 4]; 9]);
impl std::ops::Deref for TransformMatrix {
type Target = [[u8; 4]; 9];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Default for &TransformMatrix {
fn default() -> &'static TransformMatrix {
&IDENTITY_MATRIX
}
}
impl TransformMatrix {
fn from_tag(obj: &impl ObjectSubclass, tag: &gst::event::Tag) -> &'static TransformMatrix {
gst_video::VideoOrientationMethod::from_tag(tag.tag()).map_or(Default::default(), {
|orientation| match orientation {
gst_video::VideoOrientationMethod::Identity => &IDENTITY_MATRIX,
gst_video::VideoOrientationMethod::_90r => &ROTATE_90R_MATRIX,
gst_video::VideoOrientationMethod::_180 => &ROTATE_180_MATRIX,
gst_video::VideoOrientationMethod::_90l => &ROTATE_90L_MATRIX,
gst_video::VideoOrientationMethod::Horiz => &FLIP_HORZ_MATRIX,
gst_video::VideoOrientationMethod::Vert => &FLIP_VERT_MATRIX,
gst_video::VideoOrientationMethod::UrLl => &FLIP_ROTATE_90R_MATRIX,
gst_video::VideoOrientationMethod::UlLr => &FLIP_ROTATE_90L_MATRIX,
_ => {
gst::info!(
CAT,
imp = obj,
"Orientation {:?} not yet supported",
orientation
);
&IDENTITY_MATRIX
}
}
})
}
}
macro_rules! tm { macro_rules! tm {
( $($v:expr),* ) => { ( $($v:expr),* ) => {
[ TransformMatrix([
$( $(
(($v << 16) as i32).to_be_bytes(), (($v << 16) as i32).to_be_bytes(),
)* )*
] ])
} }
} }
@ -129,25 +172,6 @@ const FLIP_ROTATE_90L_MATRIX: TransformMatrix = tm!(0, 1, 0,
1, 0, 0, 1, 0, 0,
0, 0, (1 << 14)); 0, 0, (1 << 14));
pub(crate) fn transform_matrix(
orientation: &gst_video::VideoOrientationMethod,
) -> &'static TransformMatrix {
match orientation {
gst_video::VideoOrientationMethod::Identity => &IDENTITY_MATRIX,
gst_video::VideoOrientationMethod::_90r => &ROTATE_90R_MATRIX,
gst_video::VideoOrientationMethod::_180 => &ROTATE_180_MATRIX,
gst_video::VideoOrientationMethod::_90l => &ROTATE_90L_MATRIX,
gst_video::VideoOrientationMethod::Horiz => &FLIP_HORZ_MATRIX,
gst_video::VideoOrientationMethod::Vert => &FLIP_VERT_MATRIX,
gst_video::VideoOrientationMethod::UrLl => &FLIP_ROTATE_90R_MATRIX,
gst_video::VideoOrientationMethod::UlLr => &FLIP_ROTATE_90L_MATRIX,
_ => {
gst::info!(CAT, "Orientation {:?} not yet supported", orientation);
&IDENTITY_MATRIX
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct HeaderConfiguration { pub(crate) struct HeaderConfiguration {
variant: Variant, variant: Variant,
@ -162,7 +186,7 @@ pub(crate) struct HeaderConfiguration {
write_mehd: bool, write_mehd: bool,
duration: Option<gst::ClockTime>, duration: Option<gst::ClockTime>,
orientation: gst_video::VideoOrientationMethod, orientation: &'static TransformMatrix,
/// Start UTC time in ONVIF mode. /// Start UTC time in ONVIF mode.
/// Since Jan 1 1601 in 100ns units. /// Since Jan 1 1601 in 100ns units.
@ -194,7 +218,7 @@ pub(crate) struct HeaderStream {
// Tags meta for audio language and video orientation // Tags meta for audio language and video orientation
language_code: Option<[u8; 3]>, language_code: Option<[u8; 3]>,
orientation: gst_video::VideoOrientationMethod, orientation: &'static TransformMatrix,
/// Edit list clipping information /// Edit list clipping information
elst_infos: Vec<ElstInfo>, elst_infos: Vec<ElstInfo>,