playready/
pssh.rs

1//! PSSH module.
2
3use crate::binary_format::pssh::{PSSHBox, PlayreadyHeader};
4use base64::prelude::*;
5use binrw::BinRead;
6use std::io::Cursor;
7
8#[derive(Debug, Clone)]
9/// Wrm header which is extracted from PSSH box.
10pub struct WrmHeader(String);
11
12impl From<String> for WrmHeader {
13    fn from(value: String) -> Self {
14        WrmHeader(value)
15    }
16}
17
18impl From<WrmHeader> for String {
19    fn from(value: WrmHeader) -> Self {
20        value.0
21    }
22}
23
24/// Wrapper for `PlayreadyObject` binary format.
25#[derive(Debug, Clone)]
26pub struct Pssh {
27    parsed: PlayreadyHeader,
28}
29
30impl Pssh {
31    /// Creates [`Pssh`] from bytes.
32    pub fn from_bytes(b: &[u8]) -> Result<Self, binrw::Error> {
33        let pssh_box = PSSHBox::read(&mut Cursor::new(b));
34
35        match pssh_box {
36            Ok(pssh_box) => Ok(Self {
37                parsed: pssh_box.data,
38            }),
39            Err(_) => Ok(Self {
40                parsed: PlayreadyHeader::read(&mut Cursor::new(b))?,
41            }),
42        }
43    }
44
45    /// Creates [`Pssh`] from Base64 encoded bytes.
46    pub fn from_b64(b64: &[u8]) -> Result<Self, crate::Error> {
47        let bytes = BASE64_STANDARD.decode(b64)?;
48        Self::from_bytes(&bytes).map_err(|e| e.into())
49    }
50
51    /// Returns WRM headers parsed from `PSSHBox` or `PlayreadyObject` format.
52    pub fn wrm_headers(&self) -> Vec<WrmHeader> {
53        self.parsed
54            .records
55            .iter()
56            .filter(|o| o.type_ == 1)
57            .filter_map(|o| {
58                String::from_utf16(&o.data)
59                    .inspect_err(|e| {
60                        log::error!("Failed create uf16 string from wrm header: {e:?}")
61                    })
62                    .map(WrmHeader)
63                    .ok()
64            })
65            .collect()
66    }
67}
68
69impl TryFrom<&[u8]> for Pssh {
70    type Error = binrw::Error;
71
72    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
73        Self::from_bytes(value)
74    }
75}