mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-09-01 17:23:48 +00:00
hlssink3/hlscmafsink: Add byte range tag information to hls-segment-added message
While at it, for tests, replace unreachable!() with panic!() and print the error message contents. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/2439>
This commit is contained in:
parent
efbfab76bc
commit
a8684853d0
4 changed files with 70 additions and 60 deletions
|
@ -545,6 +545,8 @@ impl HlsBaseSink {
|
|||
}
|
||||
}
|
||||
|
||||
let (init_segment_br, segment_br) = self.byte_ranges(context, &segment);
|
||||
|
||||
context.playlist.add_segment(segment);
|
||||
|
||||
if context.playlist.is_type_undefined() {
|
||||
|
@ -559,6 +561,12 @@ impl HlsBaseSink {
|
|||
if let Some(ts) = timestamp {
|
||||
s = s.field("timestamp", ts.timestamp());
|
||||
};
|
||||
if let Some(br) = init_segment_br {
|
||||
s = s.field("initialization-segment-byte-range", br);
|
||||
}
|
||||
if let Some(br) = segment_br {
|
||||
s = s.field("segment-byte-range", br);
|
||||
}
|
||||
self.post_message(
|
||||
gst::message::Element::builder(s.build())
|
||||
.src(&*self.obj())
|
||||
|
@ -690,4 +698,33 @@ impl HlsBaseSink {
|
|||
let settings = self.settings.lock().unwrap();
|
||||
settings.single_media_file.is_some()
|
||||
}
|
||||
|
||||
fn byte_ranges(
|
||||
&self,
|
||||
context: &PlaylistContext,
|
||||
segment: &MediaSegment,
|
||||
) -> (Option<gst::Structure>, Option<gst::Structure>) {
|
||||
let mut init_segment_br = None;
|
||||
let mut segment_br = None;
|
||||
|
||||
if context.single_media_file {
|
||||
if let Some(ref map) = segment.map {
|
||||
if let Some(br) = &map.byte_range {
|
||||
let mut s = gst::Structure::new_empty("byte-range");
|
||||
s.set("length", br.length);
|
||||
s.set("offset", br.offset.unwrap());
|
||||
init_segment_br = Some(s);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref br) = segment.byte_range {
|
||||
let mut s = gst::Structure::new_empty("byte-range");
|
||||
s.set("length", br.length);
|
||||
s.set("offset", br.offset.unwrap());
|
||||
segment_br = Some(s)
|
||||
}
|
||||
}
|
||||
|
||||
(init_segment_br, segment_br)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,57 +6,30 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ByteRange {
|
||||
length: u64,
|
||||
offset: u64,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn extract_map_byterange(input: &str) -> Option<ByteRange> {
|
||||
input
|
||||
.lines()
|
||||
.find(|line| line.starts_with("#EXT-X-MAP:"))
|
||||
.and_then(|line| {
|
||||
line.find("BYTERANGE=\"")
|
||||
.and_then(|start| {
|
||||
let content_start = start + "BYTERANGE=\"".len();
|
||||
line[content_start..]
|
||||
.find('"')
|
||||
.map(|end| &line[content_start..content_start + end])
|
||||
})
|
||||
.and_then(|byterange_str| {
|
||||
let mut parts = byterange_str.split('@');
|
||||
match (parts.next(), parts.next()) {
|
||||
(Some(len_str), Some(off_str)) => {
|
||||
let length = len_str.parse::<u64>().ok()?;
|
||||
let offset = off_str.parse::<u64>().ok()?;
|
||||
Some(ByteRange { length, offset })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
pub fn get_byte_ranges(s: &gst::StructureRef) -> Vec<ByteRange> {
|
||||
let mut ranges = Vec::new();
|
||||
|
||||
pub fn extract_byteranges(input: &str) -> Vec<ByteRange> {
|
||||
input
|
||||
.split('\n')
|
||||
.filter(|line| line.starts_with("#EXT-X-BYTERANGE:"))
|
||||
.filter_map(|line| {
|
||||
line.strip_prefix("#EXT-X-BYTERANGE:").and_then(|content| {
|
||||
let mut parts = content.split('@');
|
||||
match (parts.next(), parts.next()) {
|
||||
(Some(len_str), Some(off_str)) => {
|
||||
let length = len_str.parse::<u64>().ok()?;
|
||||
let offset = off_str.parse::<u64>().ok()?;
|
||||
Some(ByteRange { length, offset })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
if let Ok(br) = s.get::<gst::Structure>("initialization-segment-byte-range") {
|
||||
let length = br.get::<u64>("length").unwrap();
|
||||
let offset = br.get::<u64>("offset").unwrap();
|
||||
assert!(length != 0);
|
||||
ranges.push(ByteRange { length, offset })
|
||||
}
|
||||
|
||||
if let Ok(br) = s.get::<gst::Structure>("segment-byte-range") {
|
||||
let length = br.get::<u64>("length").unwrap();
|
||||
let offset = br.get::<u64>("offset").unwrap();
|
||||
assert!(length != 0);
|
||||
ranges.push(ByteRange { length, offset })
|
||||
}
|
||||
|
||||
ranges
|
||||
}
|
||||
|
||||
pub fn validate_byterange_sequence(ranges: &[ByteRange]) -> bool {
|
||||
|
|
|
@ -159,6 +159,7 @@ fn test_hlscmafsink_video_with_single_media_file() -> Result<(), ()> {
|
|||
|
||||
pipeline.set_state(gst::State::Playing).unwrap();
|
||||
|
||||
let mut byte_ranges: Vec<ByteRange> = Vec::new();
|
||||
let mut eos = false;
|
||||
let bus = pipeline.bus().unwrap();
|
||||
while let Some(msg) = bus.timed_pop(gst::ClockTime::NONE) {
|
||||
|
@ -172,13 +173,16 @@ fn test_hlscmafsink_video_with_single_media_file() -> Result<(), ()> {
|
|||
if let Some(structure) = msg.structure() {
|
||||
if structure.has_name("hls-segment-added") {
|
||||
let location = structure.get::<String>("location").unwrap();
|
||||
let byte_range = get_byte_ranges(structure);
|
||||
byte_ranges.extend(byte_range);
|
||||
|
||||
hls_messages_sender
|
||||
.try_send(HlsSinkEvent::SegmentAddedMessage(location))
|
||||
.expect("Send segment added event");
|
||||
}
|
||||
}
|
||||
}
|
||||
MessageView::Error(..) => unreachable!(),
|
||||
MessageView::Error(err) => panic!("{err}"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@ -196,17 +200,11 @@ fn test_hlscmafsink_video_with_single_media_file() -> Result<(), ()> {
|
|||
actual_messages.push(event);
|
||||
}
|
||||
|
||||
let contents = playlist_content.lock().unwrap();
|
||||
|
||||
let mut map_byte_range = Vec::new();
|
||||
map_byte_range.push(extract_map_byterange(contents.as_str()).unwrap());
|
||||
let byte_ranges = extract_byteranges(contents.as_str());
|
||||
map_byte_range.extend(byte_ranges);
|
||||
|
||||
eprintln!("Playlist byte ranges: {byte_ranges:?}");
|
||||
// We only validate the byte range and map tag. The actual value of
|
||||
// byte range can differ from each run and hence we do not validate
|
||||
// the entire playlist.
|
||||
assert!(validate_byterange_sequence(&map_byte_range));
|
||||
assert!(validate_byterange_sequence(&byte_ranges));
|
||||
|
||||
let expected_messages = {
|
||||
use self::HlsSinkEvent::*;
|
||||
|
|
|
@ -14,7 +14,7 @@ use std::sync::LazyLock;
|
|||
use std::sync::{mpsc, Arc, Mutex};
|
||||
|
||||
mod common;
|
||||
use crate::common::{extract_byteranges, validate_byterange_sequence};
|
||||
use crate::common::{get_byte_ranges, validate_byterange_sequence, ByteRange};
|
||||
|
||||
static CAT: LazyLock<gst::DebugCategory> = LazyLock::new(|| {
|
||||
gst::DebugCategory::new(
|
||||
|
@ -213,7 +213,7 @@ fn test_hlssink3_element_with_video_content() -> Result<(), ()> {
|
|||
}
|
||||
}
|
||||
}
|
||||
MessageView::Error(..) => unreachable!(),
|
||||
MessageView::Error(err) => panic!("{err}"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@ -611,6 +611,7 @@ fn test_hlssink3_video_with_single_media_file() -> Result<(), ()> {
|
|||
BUFFER_NB
|
||||
);
|
||||
|
||||
let mut byte_ranges: Vec<ByteRange> = Vec::new();
|
||||
let mut eos = false;
|
||||
let bus = pipeline.bus().unwrap();
|
||||
while let Some(msg) = bus.timed_pop(gst::ClockTime::NONE) {
|
||||
|
@ -624,13 +625,16 @@ fn test_hlssink3_video_with_single_media_file() -> Result<(), ()> {
|
|||
if let Some(structure) = msg.structure() {
|
||||
if structure.has_name("hls-segment-added") {
|
||||
let location = structure.get::<String>("location").unwrap();
|
||||
let byte_range = get_byte_ranges(structure);
|
||||
byte_ranges.extend(byte_range);
|
||||
|
||||
hls_messages_sender
|
||||
.try_send(HlsSinkEvent::SegmentAddedMessage(location))
|
||||
.expect("Send segment added event");
|
||||
}
|
||||
}
|
||||
}
|
||||
MessageView::Error(..) => unreachable!(),
|
||||
MessageView::Error(err) => panic!("{err}"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@ -648,9 +652,7 @@ fn test_hlssink3_video_with_single_media_file() -> Result<(), ()> {
|
|||
actual_messages.push(event);
|
||||
}
|
||||
|
||||
let contents = playlist_content.lock().unwrap();
|
||||
|
||||
let byte_ranges = extract_byteranges(contents.as_str());
|
||||
eprintln!("Playlist byte ranges: {byte_ranges:?}");
|
||||
// We only validate the byte range tag. The actual value of byte
|
||||
// range can differ from each run and hence we do not validate
|
||||
// the entire playlist.
|
||||
|
|
Loading…
Reference in a new issue