mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-09-03 02:03:48 +00:00
net/hlsmultivariantsink: Drop cros-codecs as a dependency
This copies over the required bits of code from cros-codecs and drops the dependency on cros-codecs. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/2054>
This commit is contained in:
parent
e3049e272c
commit
6911e865c9
15 changed files with 4012 additions and 76 deletions
24
Cargo.lock
generated
24
Cargo.lock
generated
|
@ -1342,23 +1342,6 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cros-codecs"
|
|
||||||
version = "0.0.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4862478feb3de946be3e4b7f316b18957a45d88d1c3695c606bdf6e76a2d2bfb"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"bitreader",
|
|
||||||
"byteorder",
|
|
||||||
"bytes",
|
|
||||||
"crc32fast",
|
|
||||||
"enumn",
|
|
||||||
"log",
|
|
||||||
"nix",
|
|
||||||
"thiserror 1.0.69",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-deque"
|
name = "crossbeam-deque"
|
||||||
version = "0.8.6"
|
version = "0.8.6"
|
||||||
|
@ -2730,8 +2713,11 @@ name = "gst-plugin-hlsmultivariantsink"
|
||||||
version = "0.14.0-alpha.1"
|
version = "0.14.0-alpha.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"bitreader",
|
||||||
|
"byteorder",
|
||||||
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"cros-codecs",
|
"enumn",
|
||||||
"gio",
|
"gio",
|
||||||
"gst-plugin-fmp4",
|
"gst-plugin-fmp4",
|
||||||
"gst-plugin-hlssink3",
|
"gst-plugin-hlssink3",
|
||||||
|
@ -2743,7 +2729,7 @@ dependencies = [
|
||||||
"gstreamer-pbutils",
|
"gstreamer-pbutils",
|
||||||
"gstreamer-video",
|
"gstreamer-video",
|
||||||
"m3u8-rs",
|
"m3u8-rs",
|
||||||
"sprintf",
|
"thiserror 2.0.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -14,10 +14,13 @@ gst-app.workspace = true
|
||||||
gio.workspace = true
|
gio.workspace = true
|
||||||
m3u8-rs = "5.0"
|
m3u8-rs = "5.0"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
sprintf = "0.2"
|
|
||||||
gst-pbutils = { workspace = true, features = ["v1_22"] }
|
gst-pbutils = { workspace = true, features = ["v1_22"] }
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
anyhow = "1"
|
||||||
cros-codecs = { version = "0.0.5", default-features = false }
|
bitreader = "0.3"
|
||||||
|
bytes = "1"
|
||||||
|
byteorder = "1.5"
|
||||||
|
enumn = "0.1"
|
||||||
|
thiserror = "2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
gst-audio.workspace = true
|
gst-audio.workspace = true
|
||||||
|
|
26
net/hlsmultivariantsink/src/cros_codecs/LICENSE
Normal file
26
net/hlsmultivariantsink/src/cros_codecs/LICENSE
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
Copyright 2022 The ChromiumOS Authors
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
1
net/hlsmultivariantsink/src/cros_codecs/README.md
Normal file
1
net/hlsmultivariantsink/src/cros_codecs/README.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
The code here has been taken from [cros-codecs](https://android.googlesource.com/platform/system/cros-codecs/) with the GitHub mirror being [here](https://github.com/chromeos/cros-codecs). Only the required bits for parsing of SPS in H264/H265 has been copied. Copied code is from the released version on crates.io at the time of this writing was v0.0.5.
|
3
net/hlsmultivariantsink/src/cros_codecs/h264/mod.rs
Normal file
3
net/hlsmultivariantsink/src/cros_codecs/h264/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod nalu;
|
||||||
|
pub mod nalu_reader;
|
||||||
|
pub mod parser;
|
107
net/hlsmultivariantsink/src/cros_codecs/h264/nalu.rs
Normal file
107
net/hlsmultivariantsink/src/cros_codecs/h264/nalu.rs
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
// Copyright 2023 The ChromiumOS Authors
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use bytes::Buf;
|
||||||
|
|
||||||
|
#[allow(clippy::len_without_is_empty)]
|
||||||
|
pub trait Header: Sized {
|
||||||
|
/// Parse the NALU header, returning it.
|
||||||
|
fn parse<T: AsRef<[u8]>>(cursor: &Cursor<T>) -> anyhow::Result<Self>;
|
||||||
|
/// Whether this header type indicates EOS.
|
||||||
|
fn is_end(&self) -> bool;
|
||||||
|
/// The length of the header.
|
||||||
|
fn len(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Nalu<'a, U> {
|
||||||
|
pub header: U,
|
||||||
|
/// The mapping that backs this NALU. Possibly shared with the other NALUs
|
||||||
|
/// in the Access Unit.
|
||||||
|
pub data: Cow<'a, [u8]>,
|
||||||
|
|
||||||
|
pub size: usize,
|
||||||
|
pub offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, U> Nalu<'a, U>
|
||||||
|
where
|
||||||
|
U: Debug + Header,
|
||||||
|
{
|
||||||
|
/// Find the next Annex B encoded NAL unit.
|
||||||
|
pub fn next(cursor: &mut Cursor<&'a [u8]>) -> anyhow::Result<Nalu<'a, U>> {
|
||||||
|
let bitstream = cursor.clone().into_inner();
|
||||||
|
let pos = usize::try_from(cursor.position())?;
|
||||||
|
|
||||||
|
// Find the start code for this NALU
|
||||||
|
let current_nalu_offset = match Nalu::<'a, U>::find_start_code(cursor, pos) {
|
||||||
|
Some(offset) => offset,
|
||||||
|
None => return Err(anyhow!("No NAL found")),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut start_code_offset = pos + current_nalu_offset;
|
||||||
|
|
||||||
|
// If the preceding byte is 00, then we actually have a four byte SC,
|
||||||
|
// i.e. 00 00 00 01 Where the first 00 is the "zero_byte()"
|
||||||
|
if start_code_offset > 0 && cursor.get_ref()[start_code_offset - 1] == 00 {
|
||||||
|
start_code_offset -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The NALU offset is its offset + 3 bytes to skip the start code.
|
||||||
|
let nalu_offset = pos + current_nalu_offset + 3;
|
||||||
|
|
||||||
|
// Set the bitstream position to the start of the current NALU
|
||||||
|
cursor.set_position(u64::try_from(nalu_offset)?);
|
||||||
|
|
||||||
|
let hdr = U::parse(cursor)?;
|
||||||
|
|
||||||
|
// Find the start of the subsequent NALU.
|
||||||
|
let mut next_nalu_offset = match Nalu::<'a, U>::find_start_code(cursor, nalu_offset) {
|
||||||
|
Some(offset) => offset,
|
||||||
|
None => cursor.chunk().len(), // Whatever data is left must be part of the current NALU
|
||||||
|
};
|
||||||
|
|
||||||
|
while next_nalu_offset > 0 && cursor.get_ref()[nalu_offset + next_nalu_offset - 1] == 00 {
|
||||||
|
// Discard trailing_zero_8bits
|
||||||
|
next_nalu_offset -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let nal_size = if hdr.is_end() {
|
||||||
|
// the NALU is comprised of only the header
|
||||||
|
hdr.len()
|
||||||
|
} else {
|
||||||
|
next_nalu_offset
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Nalu {
|
||||||
|
header: hdr,
|
||||||
|
data: Cow::from(&bitstream[start_code_offset..nalu_offset + nal_size]),
|
||||||
|
size: nal_size,
|
||||||
|
offset: nalu_offset - start_code_offset,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, U> Nalu<'a, U>
|
||||||
|
where
|
||||||
|
U: Debug,
|
||||||
|
{
|
||||||
|
fn find_start_code(data: &mut Cursor<&'a [u8]>, offset: usize) -> Option<usize> {
|
||||||
|
// discard all zeroes until the start code pattern is found
|
||||||
|
data.get_ref()[offset..]
|
||||||
|
.windows(3)
|
||||||
|
.position(|window| window == [0x00, 0x00, 0x01])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U> AsRef<[u8]> for Nalu<'_, U> {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
&self.data[self.offset..self.offset + self.size]
|
||||||
|
}
|
||||||
|
}
|
180
net/hlsmultivariantsink/src/cros_codecs/h264/nalu_reader.rs
Normal file
180
net/hlsmultivariantsink/src/cros_codecs/h264/nalu_reader.rs
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
// Copyright 2022 The ChromiumOS Authors
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use anyhow::Context;
|
||||||
|
use byteorder::ReadBytesExt;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// A bit reader for h264 bitstreams. It properly handles emulation-prevention
|
||||||
|
/// bytes and stop bits.
|
||||||
|
pub(crate) struct NaluReader<'a> {
|
||||||
|
/// A reference into the next unread byte in the stream.
|
||||||
|
data: Cursor<&'a [u8]>,
|
||||||
|
/// Contents of the current byte. First unread bit starting at position 8 -
|
||||||
|
/// num_remaining_bits_in_curr_bytes.
|
||||||
|
curr_byte: u8,
|
||||||
|
/// Number of bits remaining in `curr_byte`
|
||||||
|
num_remaining_bits_in_curr_byte: usize,
|
||||||
|
/// Used in epb detection.
|
||||||
|
prev_two_bytes: u16,
|
||||||
|
/// Number of epbs (i.e. 0x000003) we found.
|
||||||
|
num_epb: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub(crate) enum GetByteError {
|
||||||
|
#[error("reader ran out of bits")]
|
||||||
|
OutOfBits,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub(crate) enum ReadBitsError {
|
||||||
|
#[error("more than 31 ({0}) bits were requested")]
|
||||||
|
TooManyBytesRequested(usize),
|
||||||
|
#[error("failed to advance the current byte")]
|
||||||
|
GetByte(#[from] GetByteError),
|
||||||
|
#[error("failed to convert read input to target type")]
|
||||||
|
ConversionFailed,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> NaluReader<'a> {
|
||||||
|
pub fn new(data: &'a [u8]) -> Self {
|
||||||
|
Self {
|
||||||
|
data: Cursor::new(data),
|
||||||
|
curr_byte: Default::default(),
|
||||||
|
num_remaining_bits_in_curr_byte: Default::default(),
|
||||||
|
prev_two_bytes: 0xffff,
|
||||||
|
num_epb: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a single bit from the stream.
|
||||||
|
pub fn read_bit(&mut self) -> Result<bool, ReadBitsError> {
|
||||||
|
let bit = self.read_bits::<u32>(1)?;
|
||||||
|
match bit {
|
||||||
|
1 => Ok(true),
|
||||||
|
0 => Ok(false),
|
||||||
|
_ => panic!("Unexpected value {}", bit),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read up to 31 bits from the stream.
|
||||||
|
pub fn read_bits<U: TryFrom<u32>>(&mut self, num_bits: usize) -> Result<U, ReadBitsError> {
|
||||||
|
if num_bits > 31 {
|
||||||
|
return Err(ReadBitsError::TooManyBytesRequested(num_bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut bits_left = num_bits;
|
||||||
|
let mut out = 0u32;
|
||||||
|
|
||||||
|
while self.num_remaining_bits_in_curr_byte < bits_left {
|
||||||
|
out |= (self.curr_byte as u32) << (bits_left - self.num_remaining_bits_in_curr_byte);
|
||||||
|
bits_left -= self.num_remaining_bits_in_curr_byte;
|
||||||
|
self.update_curr_byte()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
out |= (self.curr_byte >> (self.num_remaining_bits_in_curr_byte - bits_left)) as u32;
|
||||||
|
out &= (1 << num_bits) - 1;
|
||||||
|
self.num_remaining_bits_in_curr_byte -= bits_left;
|
||||||
|
|
||||||
|
U::try_from(out).map_err(|_| ReadBitsError::ConversionFailed)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Skip `num_bits` bits from the stream.
|
||||||
|
pub fn skip_bits(&mut self, mut num_bits: usize) -> Result<(), ReadBitsError> {
|
||||||
|
while num_bits > 0 {
|
||||||
|
let n = std::cmp::min(num_bits, 31);
|
||||||
|
self.read_bits::<u32>(n)?;
|
||||||
|
num_bits -= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_ue<U: TryFrom<u32>>(&mut self) -> anyhow::Result<U> {
|
||||||
|
let mut num_bits = 0;
|
||||||
|
|
||||||
|
while self.read_bits::<u32>(1)? == 0 {
|
||||||
|
num_bits += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if num_bits > 31 {
|
||||||
|
return Err(anyhow!("invalid stream"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = ((1u32 << num_bits) - 1)
|
||||||
|
.checked_add(self.read_bits::<u32>(num_bits)?)
|
||||||
|
.context("read number cannot fit in 32 bits")?;
|
||||||
|
|
||||||
|
U::try_from(value).map_err(|_| anyhow!("conversion error"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_ue_bounded<U: TryFrom<u32>>(&mut self, min: u32, max: u32) -> anyhow::Result<U> {
|
||||||
|
let ue = self.read_ue()?;
|
||||||
|
if ue > max || ue < min {
|
||||||
|
Err(anyhow!(
|
||||||
|
"Value out of bounds: expected {} - {}, got {}",
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
ue
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(U::try_from(ue).map_err(|_| anyhow!("Conversion error"))?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_ue_max<U: TryFrom<u32>>(&mut self, max: u32) -> anyhow::Result<U> {
|
||||||
|
self.read_ue_bounded(0, max)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_se<U: TryFrom<i32>>(&mut self) -> anyhow::Result<U> {
|
||||||
|
let ue = self.read_ue::<u32>()? as i32;
|
||||||
|
|
||||||
|
if ue % 2 == 0 {
|
||||||
|
Ok(U::try_from(-ue / 2).map_err(|_| anyhow!("Conversion error"))?)
|
||||||
|
} else {
|
||||||
|
Ok(U::try_from(ue / 2 + 1).map_err(|_| anyhow!("Conversion error"))?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_se_bounded<U: TryFrom<i32>>(&mut self, min: i32, max: i32) -> anyhow::Result<U> {
|
||||||
|
let se = self.read_se()?;
|
||||||
|
if se < min || se > max {
|
||||||
|
Err(anyhow!(
|
||||||
|
"Value out of bounds, expected between {}-{}, got {}",
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
se
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(U::try_from(se).map_err(|_| anyhow!("Conversion error"))?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_byte(&mut self) -> Result<u8, GetByteError> {
|
||||||
|
self.data.read_u8().map_err(|_| GetByteError::OutOfBits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_curr_byte(&mut self) -> Result<(), GetByteError> {
|
||||||
|
let mut byte = self.get_byte()?;
|
||||||
|
|
||||||
|
if self.prev_two_bytes == 0 && byte == 0x03 {
|
||||||
|
// We found an epb
|
||||||
|
self.num_epb += 1;
|
||||||
|
// Read another byte
|
||||||
|
byte = self.get_byte()?;
|
||||||
|
// We need another 3 bytes before another epb can happen.
|
||||||
|
self.prev_two_bytes = 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.num_remaining_bits_in_curr_byte = 8;
|
||||||
|
self.prev_two_bytes = (self.prev_two_bytes << 8) | u16::from(byte);
|
||||||
|
|
||||||
|
self.curr_byte = byte;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
1231
net/hlsmultivariantsink/src/cros_codecs/h264/parser.rs
Normal file
1231
net/hlsmultivariantsink/src/cros_codecs/h264/parser.rs
Normal file
File diff suppressed because it is too large
Load diff
1
net/hlsmultivariantsink/src/cros_codecs/h265/mod.rs
Normal file
1
net/hlsmultivariantsink/src/cros_codecs/h265/mod.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub mod parser;
|
2440
net/hlsmultivariantsink/src/cros_codecs/h265/parser.rs
Normal file
2440
net/hlsmultivariantsink/src/cros_codecs/h265/parser.rs
Normal file
File diff suppressed because it is too large
Load diff
2
net/hlsmultivariantsink/src/cros_codecs/mod.rs
Normal file
2
net/hlsmultivariantsink/src/cros_codecs/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod h264;
|
||||||
|
pub mod h265;
|
|
@ -1308,12 +1308,10 @@ impl HlsMultivariantSink {
|
||||||
drop(state);
|
drop(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
fn parse_h264_sps(&self, buffer: &[u8], group_id: String) {
|
fn parse_h264_sps(&self, buffer: &[u8], group_id: String) {
|
||||||
use cros_codecs::codec::h264::parser as H264Parser;
|
use crate::cros_codecs::h264::parser as H264Parser;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
let mut caps_codec_str: Option<String> = None;
|
|
||||||
let mut cursor = Cursor::new(buffer);
|
let mut cursor = Cursor::new(buffer);
|
||||||
let mut parser = H264Parser::Parser::default();
|
let mut parser = H264Parser::Parser::default();
|
||||||
|
|
||||||
|
@ -1340,34 +1338,19 @@ impl HlsMultivariantSink {
|
||||||
constraint_flags += 2u32.pow(7 - index as u32) * (*bit) as u32;
|
constraint_flags += 2u32.pow(7 - index as u32) * (*bit) as u32;
|
||||||
});
|
});
|
||||||
|
|
||||||
match sprintf::sprintf!("avc1.%02X%02X%02X", profile, constraint_flags, level) {
|
let codec_str = format!("avc1.{profile:02X}{constraint_flags:02X}{level:02X}");
|
||||||
Ok(codec_str) => {
|
|
||||||
caps_codec_str = Some(codec_str);
|
self.build_codec_str_and_write_multivariant_playlist(codec_str, group_id);
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
gst::element_error!(
|
|
||||||
self.obj(),
|
|
||||||
gst::ResourceError::Failed,
|
|
||||||
["Failed to format codec string with error: {:?}", e]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(codec_str) = caps_codec_str {
|
|
||||||
self.build_codec_str_and_write_multivariant_playlist(codec_str, group_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
fn parse_h265_sps(&self, buffer: &[u8], group_id: String) {
|
fn parse_h265_sps(&self, buffer: &[u8], group_id: String) {
|
||||||
use cros_codecs::codec::h265::parser as H265Parser;
|
use crate::cros_codecs::h265::parser as H265Parser;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
let mut caps_codec_str: Option<String> = None;
|
|
||||||
let mut cursor = Cursor::new(buffer);
|
let mut cursor = Cursor::new(buffer);
|
||||||
let mut parser = H265Parser::Parser::default();
|
let mut parser = H265Parser::Parser::default();
|
||||||
|
|
||||||
|
@ -1429,37 +1412,15 @@ impl HlsMultivariantSink {
|
||||||
constraint_indicator_flag += 2u32.pow(7 - index as u32) * (*bit) as u32;
|
constraint_indicator_flag += 2u32.pow(7 - index as u32) * (*bit) as u32;
|
||||||
});
|
});
|
||||||
|
|
||||||
match sprintf::sprintf!(
|
let codec_str = format!("{codec_str}.{profile_idc:X}.{compat_flag_parameter}.{tier_flag}{level_idc}.{constraint_indicator_flag:02X}");
|
||||||
"%s.%X.%hu.%c%d.%02X",
|
|
||||||
codec_str,
|
self.build_codec_str_and_write_multivariant_playlist(codec_str, group_id);
|
||||||
profile_idc,
|
|
||||||
compat_flag_parameter,
|
|
||||||
tier_flag,
|
|
||||||
level_idc,
|
|
||||||
constraint_indicator_flag
|
|
||||||
) {
|
|
||||||
Ok(codec_str) => {
|
|
||||||
caps_codec_str = Some(codec_str);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
gst::element_error!(
|
|
||||||
self.obj(),
|
|
||||||
gst::ResourceError::Failed,
|
|
||||||
["Failed to format codec string with error: {:?}", e]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(codec_str) = caps_codec_str {
|
|
||||||
self.build_codec_str_and_write_multivariant_playlist(codec_str, group_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
fn parse_sps(
|
fn parse_sps(
|
||||||
&self,
|
&self,
|
||||||
caps: &gst::Caps,
|
caps: &gst::Caps,
|
||||||
|
@ -1510,12 +1471,7 @@ impl HlsMultivariantSink {
|
||||||
* with SPS. codec-utils helpers cannot give us codec string
|
* with SPS. codec-utils helpers cannot give us codec string
|
||||||
* without the codec_data. For MPEG-TS, parse SPS and figure
|
* without the codec_data. For MPEG-TS, parse SPS and figure
|
||||||
* out the relevant information to generate codec string.
|
* out the relevant information to generate codec string.
|
||||||
*
|
|
||||||
* parse_sps function relies on cros_codecs which supports
|
|
||||||
* only linux. On other platforms for MPEG-TS, users need to
|
|
||||||
* specify codec string manually.
|
|
||||||
*/
|
*/
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
{
|
{
|
||||||
let settings = self.settings.lock().unwrap();
|
let settings = self.settings.lock().unwrap();
|
||||||
let is_mpegts = settings.muxer_type == HlsMultivariantSinkMuxerType::MpegTs;
|
let is_mpegts = settings.muxer_type == HlsMultivariantSinkMuxerType::MpegTs;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
use gst::glib;
|
use gst::glib;
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
|
|
||||||
|
mod cros_codecs;
|
||||||
mod imp;
|
mod imp;
|
||||||
|
|
||||||
#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, glib::Enum)]
|
#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, glib::Enum)]
|
||||||
|
|
|
@ -812,7 +812,6 @@ low/video.m3u8
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hlsmultivariantsink_multiple_audio_rendition_multiple_video_variant_with_mpegts(
|
fn hlsmultivariantsink_multiple_audio_rendition_multiple_video_variant_with_mpegts(
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
|
@ -988,7 +987,6 @@ low/video.m3u8
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hlsmultivariantsink_multiple_video_variant_with_mpegts_audio_video_muxed() -> Result<(), ()> {
|
fn hlsmultivariantsink_multiple_video_variant_with_mpegts_audio_video_muxed() -> Result<(), ()> {
|
||||||
init();
|
init();
|
||||||
|
|
|
@ -18,6 +18,7 @@ Ines = "Ines"
|
||||||
|
|
||||||
# net/hlsmultivariantsink
|
# net/hlsmultivariantsink
|
||||||
cros = "cros"
|
cros = "cros"
|
||||||
|
ue = "ue"
|
||||||
|
|
||||||
[files]
|
[files]
|
||||||
extend-exclude = [
|
extend-exclude = [
|
||||||
|
|
Loading…
Reference in a new issue