aboutsummaryrefslogtreecommitdiff
path: root/remuxer/src/lib.rs
blob: ffefcae0b72434d8d6c71fbd535dcae84c272402 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/*
    This file is part of jellything (https://codeberg.org/metamuffin/jellything)
    which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
    Copyright (C) 2024 metamuffin <metamuffin.org>
*/
pub mod extract;
pub mod import;
pub mod remux;
pub mod seek_index;
pub mod segment_extractor;
pub mod snippet;
pub mod trim_writer;

pub use remux::remux_stream_into;
pub use snippet::write_snippet_into;

use jellycommon::{SourceTrack, SourceTrackKind};
use jellymatroska::{Master, MatroskaTag};

pub fn ebml_header(webm: bool) -> MatroskaTag {
    MatroskaTag::Ebml(Master::Collected(vec![
        MatroskaTag::EbmlVersion(1),
        MatroskaTag::EbmlReadVersion(1),
        MatroskaTag::EbmlMaxIdLength(4),
        MatroskaTag::EbmlMaxSizeLength(8),
        MatroskaTag::DocType(if webm {
            "webm".to_string()
        } else {
            "matroska".to_string()
        }),
        MatroskaTag::DocTypeVersion(4),
        MatroskaTag::DocTypeReadVersion(2),
    ]))
}
pub fn ebml_segment_info(title: String, duration: f64) -> MatroskaTag {
    MatroskaTag::Info(Master::Collected(vec![
        MatroskaTag::TimestampScale(1_000_000),
        MatroskaTag::Duration(duration * 1000.0),
        MatroskaTag::Title(title),
        MatroskaTag::MuxingApp("jellyremux".to_string()),
        MatroskaTag::WritingApp("jellything".to_string()),
    ]))
}

pub fn ebml_track_entry(
    number: u64,
    track: &SourceTrack,
    codec_private: Option<Vec<u8>>,
) -> MatroskaTag {
    let mut els = vec![
        MatroskaTag::TrackNumber(number),
        MatroskaTag::TrackUID(number),
        MatroskaTag::FlagLacing(0),
        MatroskaTag::Language(track.language.clone()),
        MatroskaTag::CodecID(track.codec.clone()),
    ];
    if let Some(d) = &track.default_duration {
        els.push(MatroskaTag::DefaultDuration(*d));
    }
    match track.kind {
        SourceTrackKind::Video {
            width,
            height,
            fps: _,
        } => {
            els.push(MatroskaTag::TrackType(1));
            els.push(MatroskaTag::Video(Master::Collected(vec![
                MatroskaTag::PixelWidth(width),
                MatroskaTag::PixelHeight(height),
            ])))
        }
        SourceTrackKind::Audio {
            channels,
            sample_rate,
            bit_depth,
        } => {
            els.push(MatroskaTag::TrackType(2));
            els.push(MatroskaTag::Audio(Master::Collected(vec![
                MatroskaTag::SamplingFrequency(sample_rate),
                MatroskaTag::Channels(channels.try_into().unwrap()),
            ])));
            els.push(MatroskaTag::BitDepth(bit_depth.try_into().unwrap()));
        }
        SourceTrackKind::Subtitles => {
            els.push(MatroskaTag::TrackType(19));
        }
    }
    if let Some(d) = &codec_private {
        els.push(MatroskaTag::CodecPrivate(d.clone()));
    }
    MatroskaTag::TrackEntry(Master::Collected(els))
}