mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-09-02 09:43:48 +00:00
fmp4mux: Only allow caps-related header updates if header-update-mode=caps
In none mode nothing is expecting updated headers, in the other existing modes the goal is to get an updated header at the end with the duration. So add a new mode specifically for caps changes. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/2193>
This commit is contained in:
parent
f86e7e6c33
commit
c5e4181613
4 changed files with 108 additions and 9 deletions
|
@ -3598,6 +3598,11 @@
|
||||||
"desc": "Update",
|
"desc": "Update",
|
||||||
"name": "update",
|
"name": "update",
|
||||||
"value": "2"
|
"value": "2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"desc": "Caps",
|
||||||
|
"name": "caps",
|
||||||
|
"value": "3"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -921,14 +921,14 @@ impl FMP4Mux {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Caps/tag changes are allowed only in case that the
|
// Caps/tag changes are allowed only in case that the
|
||||||
// header-update-mode is None.
|
// header-update-mode is Caps.
|
||||||
//
|
//
|
||||||
// CAUTION: This function logs an error if operation is not
|
// CAUTION: This function logs an error if operation is not
|
||||||
// allowed so it should be evaluated only in case the caps/tags
|
// allowed so it should be evaluated only in case the caps/tags
|
||||||
// would change otherwise (e. g. right-most operand in boolean
|
// would change otherwise (e. g. right-most operand in boolean
|
||||||
// expressions).
|
// expressions).
|
||||||
fn header_update_allowed(&self, reason: &str) -> bool {
|
fn header_update_allowed(&self, reason: &str) -> bool {
|
||||||
if self.settings.lock().unwrap().header_update_mode == super::HeaderUpdateMode::None {
|
if self.settings.lock().unwrap().header_update_mode == super::HeaderUpdateMode::Caps {
|
||||||
gst::debug!(
|
gst::debug!(
|
||||||
CAT,
|
CAT,
|
||||||
imp = self,
|
imp = self,
|
||||||
|
@ -3643,17 +3643,30 @@ impl FMP4Mux {
|
||||||
let class = aggregator.class();
|
let class = aggregator.class();
|
||||||
let variant = class.as_ref().variant;
|
let variant = class.as_ref().variant;
|
||||||
|
|
||||||
if settings.header_update_mode == super::HeaderUpdateMode::None && at_eos {
|
if [super::HeaderUpdateMode::None, super::HeaderUpdateMode::Caps]
|
||||||
|
.contains(&settings.header_update_mode)
|
||||||
|
&& at_eos
|
||||||
|
{
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(!at_eos || state.streams.iter().all(|s| s.queued_gops.is_empty()));
|
assert!(!at_eos || state.streams.iter().all(|s| s.queued_gops.is_empty()));
|
||||||
|
|
||||||
let duration = state
|
let duration = if at_eos
|
||||||
.end_pts
|
&& [
|
||||||
.opt_checked_sub(state.earliest_pts)
|
super::HeaderUpdateMode::Update,
|
||||||
.ok()
|
super::HeaderUpdateMode::Rewrite,
|
||||||
.flatten();
|
]
|
||||||
|
.contains(&settings.header_update_mode)
|
||||||
|
{
|
||||||
|
state
|
||||||
|
.end_pts
|
||||||
|
.opt_checked_sub(state.earliest_pts)
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let streams = state
|
let streams = state
|
||||||
.streams
|
.streams
|
||||||
|
@ -3750,7 +3763,7 @@ impl FMP4Mux {
|
||||||
match updated_header {
|
match updated_header {
|
||||||
Ok(Some((buffer_list, caps))) => {
|
Ok(Some((buffer_list, caps))) => {
|
||||||
match settings.header_update_mode {
|
match settings.header_update_mode {
|
||||||
super::HeaderUpdateMode::None => unreachable!(),
|
super::HeaderUpdateMode::None | super::HeaderUpdateMode::Caps => unreachable!(),
|
||||||
super::HeaderUpdateMode::Rewrite => {
|
super::HeaderUpdateMode::Rewrite => {
|
||||||
let mut q = gst::query::Seeking::new(gst::Format::Bytes);
|
let mut q = gst::query::Seeking::new(gst::Format::Bytes);
|
||||||
if self.obj().src_pad().peer_query(&mut q) && q.result().0 {
|
if self.obj().src_pad().peer_query(&mut q) && q.result().0 {
|
||||||
|
|
|
@ -326,14 +326,51 @@ pub(crate) struct FragmentOffset {
|
||||||
offset: u64,
|
offset: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstFMP4MuxHeaderUpdateMode:
|
||||||
|
*
|
||||||
|
* How and when updating of the header (`moov`, initialization segment) is allowed.
|
||||||
|
*/
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, glib::Enum)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, glib::Enum)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
#[enum_type(name = "GstFMP4MuxHeaderUpdateMode")]
|
#[enum_type(name = "GstFMP4MuxHeaderUpdateMode")]
|
||||||
pub(crate) enum HeaderUpdateMode {
|
pub(crate) enum HeaderUpdateMode {
|
||||||
|
/**
|
||||||
|
* GstFMP4MuxHeaderUpdateMode:none:
|
||||||
|
*
|
||||||
|
* Don't allow and do any header updates at all.
|
||||||
|
*
|
||||||
|
* Caps changes are not allowed in this mode.
|
||||||
|
*/
|
||||||
None,
|
None,
|
||||||
|
/**
|
||||||
|
* GstFMP4MuxHeaderUpdateMode:rewrite:
|
||||||
|
*
|
||||||
|
* Try rewriting the initial header with the overall duration at the very end.
|
||||||
|
*
|
||||||
|
* Caps changes are not allowed in this mode.
|
||||||
|
*/
|
||||||
Rewrite,
|
Rewrite,
|
||||||
|
/**
|
||||||
|
* GstFMP4MuxHeaderUpdateMode:update:
|
||||||
|
*
|
||||||
|
* Send an updated version of the initial header with the overall duration at
|
||||||
|
* the very end.
|
||||||
|
*
|
||||||
|
* Caps changes are not allowed in this mode.
|
||||||
|
*/
|
||||||
Update,
|
Update,
|
||||||
|
/**
|
||||||
|
* GstFMP4MuxHeaderUpdateMode:caps:
|
||||||
|
*
|
||||||
|
* Send an updated header whenever caps or tag changes are pending that affect the initial
|
||||||
|
* header. The updated header does not have the duration set and will always be followed by a
|
||||||
|
* new fragment.
|
||||||
|
*
|
||||||
|
* Since: plugins-rs-0.14.0
|
||||||
|
*/
|
||||||
|
Caps,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, glib::Enum, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, glib::Enum, Default)]
|
||||||
|
|
|
@ -2501,6 +2501,10 @@ fn test_caps_change_at_gop_boundary() {
|
||||||
|
|
||||||
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
||||||
|
|
||||||
|
h.element()
|
||||||
|
.unwrap()
|
||||||
|
.set_property_from_str("header-update-mode", "caps");
|
||||||
|
|
||||||
let caps = gst::Caps::builder("video/x-h264")
|
let caps = gst::Caps::builder("video/x-h264")
|
||||||
.field("width", 1920i32)
|
.field("width", 1920i32)
|
||||||
.field("height", 1080i32)
|
.field("height", 1080i32)
|
||||||
|
@ -2541,6 +2545,10 @@ fn test_language_change_at_gop_boundary() {
|
||||||
|
|
||||||
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
||||||
|
|
||||||
|
h.element()
|
||||||
|
.unwrap()
|
||||||
|
.set_property_from_str("header-update-mode", "caps");
|
||||||
|
|
||||||
let caps = gst::Caps::builder("video/x-h264")
|
let caps = gst::Caps::builder("video/x-h264")
|
||||||
.field("width", 1920i32)
|
.field("width", 1920i32)
|
||||||
.field("height", 1080i32)
|
.field("height", 1080i32)
|
||||||
|
@ -2603,6 +2611,10 @@ fn test_caps_change_at_gop_boundary_multi_stream() {
|
||||||
let mut h1 = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
let mut h1 = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
||||||
let mut h2 = gst_check::Harness::with_element(&h1.element().unwrap(), Some("sink_1"), None);
|
let mut h2 = gst_check::Harness::with_element(&h1.element().unwrap(), Some("sink_1"), None);
|
||||||
|
|
||||||
|
h1.element()
|
||||||
|
.unwrap()
|
||||||
|
.set_property_from_str("header-update-mode", "caps");
|
||||||
|
|
||||||
let caps1 = gst::Caps::builder("video/x-h264")
|
let caps1 = gst::Caps::builder("video/x-h264")
|
||||||
.field("width", 1920i32)
|
.field("width", 1920i32)
|
||||||
.field("height", 1080i32)
|
.field("height", 1080i32)
|
||||||
|
@ -2770,6 +2782,10 @@ fn test_caps_change_at_gop_boundary_chunked_multi_stream() {
|
||||||
let mut h1 = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
let mut h1 = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
||||||
let mut h2 = gst_check::Harness::with_element(&h1.element().unwrap(), Some("sink_1"), None);
|
let mut h2 = gst_check::Harness::with_element(&h1.element().unwrap(), Some("sink_1"), None);
|
||||||
|
|
||||||
|
h1.element()
|
||||||
|
.unwrap()
|
||||||
|
.set_property_from_str("header-update-mode", "caps");
|
||||||
|
|
||||||
let caps1 = gst::Caps::builder("video/x-h264")
|
let caps1 = gst::Caps::builder("video/x-h264")
|
||||||
.field("width", 1920i32)
|
.field("width", 1920i32)
|
||||||
.field("height", 1080i32)
|
.field("height", 1080i32)
|
||||||
|
@ -2918,6 +2934,10 @@ fn test_caps_change_at_gop_boundary_compatible() {
|
||||||
|
|
||||||
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
||||||
|
|
||||||
|
h.element()
|
||||||
|
.unwrap()
|
||||||
|
.set_property_from_str("header-update-mode", "caps");
|
||||||
|
|
||||||
let caps = gst::Caps::builder("video/x-h264")
|
let caps = gst::Caps::builder("video/x-h264")
|
||||||
.field("width", 1280i32)
|
.field("width", 1280i32)
|
||||||
.field("height", 720i32)
|
.field("height", 720i32)
|
||||||
|
@ -2959,6 +2979,10 @@ fn test_caps_change_at_gop_boundary_not_allowed() {
|
||||||
|
|
||||||
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
||||||
|
|
||||||
|
h.element()
|
||||||
|
.unwrap()
|
||||||
|
.set_property_from_str("header-update-mode", "caps");
|
||||||
|
|
||||||
let caps = gst::Caps::builder("video/x-h264")
|
let caps = gst::Caps::builder("video/x-h264")
|
||||||
.field("width", 1920i32)
|
.field("width", 1920i32)
|
||||||
.field("height", 1080i32)
|
.field("height", 1080i32)
|
||||||
|
@ -3004,6 +3028,10 @@ fn test_caps_change_within_gop() {
|
||||||
|
|
||||||
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
||||||
|
|
||||||
|
h.element()
|
||||||
|
.unwrap()
|
||||||
|
.set_property_from_str("header-update-mode", "caps");
|
||||||
|
|
||||||
let caps = gst::Caps::builder("video/x-h264")
|
let caps = gst::Caps::builder("video/x-h264")
|
||||||
.field("width", 1920i32)
|
.field("width", 1920i32)
|
||||||
.field("height", 1080i32)
|
.field("height", 1080i32)
|
||||||
|
@ -3044,6 +3072,10 @@ fn test_caps_change_within_gop_start_without_key() {
|
||||||
|
|
||||||
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
||||||
|
|
||||||
|
h.element()
|
||||||
|
.unwrap()
|
||||||
|
.set_property_from_str("header-update-mode", "caps");
|
||||||
|
|
||||||
let caps = gst::Caps::builder("video/x-h264")
|
let caps = gst::Caps::builder("video/x-h264")
|
||||||
.field("width", 1920i32)
|
.field("width", 1920i32)
|
||||||
.field("height", 1080i32)
|
.field("height", 1080i32)
|
||||||
|
@ -3083,6 +3115,10 @@ fn test_caps_change_within_gop_chunked() {
|
||||||
|
|
||||||
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
||||||
|
|
||||||
|
h.element()
|
||||||
|
.unwrap()
|
||||||
|
.set_property_from_str("header-update-mode", "caps");
|
||||||
|
|
||||||
let caps = gst::Caps::builder("video/x-h264")
|
let caps = gst::Caps::builder("video/x-h264")
|
||||||
.field("width", 1920i32)
|
.field("width", 1920i32)
|
||||||
.field("height", 1080i32)
|
.field("height", 1080i32)
|
||||||
|
@ -3130,6 +3166,10 @@ fn test_caps_change_within_gop_no_key() {
|
||||||
|
|
||||||
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
||||||
|
|
||||||
|
h.element()
|
||||||
|
.unwrap()
|
||||||
|
.set_property_from_str("header-update-mode", "caps");
|
||||||
|
|
||||||
let caps = gst::Caps::builder("video/x-h264")
|
let caps = gst::Caps::builder("video/x-h264")
|
||||||
.field("width", 1920i32)
|
.field("width", 1920i32)
|
||||||
.field("height", 1080i32)
|
.field("height", 1080i32)
|
||||||
|
@ -3171,6 +3211,10 @@ fn test_caps_change_before_first_frame() {
|
||||||
|
|
||||||
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
let mut h = gst_check::Harness::with_padnames("isofmp4mux", Some("sink_0"), Some("src"));
|
||||||
|
|
||||||
|
h.element()
|
||||||
|
.unwrap()
|
||||||
|
.set_property_from_str("header-update-mode", "caps");
|
||||||
|
|
||||||
let caps = gst::Caps::builder("video/x-h264")
|
let caps = gst::Caps::builder("video/x-h264")
|
||||||
.field("width", 1920i32)
|
.field("width", 1920i32)
|
||||||
.field("height", 1080i32)
|
.field("height", 1080i32)
|
||||||
|
|
Loading…
Reference in a new issue