///|
/// Parsed optional adaptation fields. Extension bytes are opaque, not semantically validated.
pub struct Adaptation {
discontinuity : Bool
random_access : Bool
pcr : Int64?
opcr : Int64?
splice_countdown : Int?
private_data : Bytes
extension : Bytes
} derive(Eq, Debug)
///|
fn read_clock(
b : Bytes,
i : Int,
offset : Int64,
pid : Int,
) -> Result[Int64, Diagnostic] {
let ext = ((b[i + 4].to_int() & 1) << 8) | b[i + 5].to_int()
if (b[i + 4].to_int() & 0x7e) != 0x7e || ext > 299 {
return Err(fault("pcr_encoding", offset + i.to_int64() + 4L, Some(pid)))
}
let base = (b[i].to_int64() << 25) |
(b[i + 1].to_int64() << 17) |
(b[i + 2].to_int64() << 9) |
(b[i + 3].to_int64() << 1) |
(b[i + 4].to_int64() >> 7)
Ok(base * 300L + ext.to_int64())
}
///|
/// Validate lengths, PCR/OPCR encoding and outer stuffing; extension payload is preserved.
pub fn Packet::adaptation(self : Packet) -> Result[Adaptation?, Diagnostic] {
if (self.adaptation_control & 2) == 0 || self.raw[4] == 0 {
return Ok(None)
}
let b = self.raw
let end = 5 + b[4].to_int()
let flags = b[5].to_int()
let mut pos = 6
let mut pcr = None
let mut opcr = None
for mask in [0x10, 0x08] {
if (flags & mask) != 0 {
if pos + 6 > end {
return Err(
fault(
"adaptation_truncated",
self.offset + pos.to_int64(),
Some(self.pid),
),
)
}
match read_clock(b, pos, self.offset, self.pid) {
Err(e) => return Err(e)
Ok(c) => if mask == 0x10 { pcr = Some(c) } else { opcr = Some(c) }
}
pos = pos + 6
}
}
let mut splice_countdown = None
if (flags & 4) != 0 {
if pos >= end {
return Err(
fault(
"adaptation_truncated",
self.offset + pos.to_int64(),
Some(self.pid),
),
)
}
let value = b[pos].to_int()
splice_countdown = Some(if value >= 128 { value - 256 } else { value })
pos = pos + 1
}
let mut private_data = b""
let mut extension = b""
for mask in [2, 1] {
if (flags & mask) != 0 {
if pos >= end {
return Err(
fault(
"adaptation_truncated",
self.offset + pos.to_int64(),
Some(self.pid),
),
)
}
let n = b[pos].to_int()
pos = pos + 1
if pos + n > end {
return Err(
fault(
"adaptation_truncated",
self.offset + pos.to_int64(),
Some(self.pid),
),
)
}
let bytes = b.view(start=pos, end=pos + n).to_owned()
if mask == 2 {
private_data = bytes
} else {
extension = bytes
}
pos = pos + n
}
}
for i = pos; i < end; i = i + 1 {
if b[i] != 0xff {
return Err(
fault("adaptation_stuffing", self.offset + i.to_int64(), Some(self.pid)),
)
}
}
Ok(
Some({
discontinuity: (flags & 0x80) != 0,
random_access: (flags & 0x40) != 0,
pcr,
opcr,
splice_countdown,
private_data,
extension,
}),
)
}