aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-01-28 03:21:03 +0100
committermetamuffin <metamuffin@disroot.org>2024-01-28 03:21:03 +0100
commitce9eb140ab9243d1c87ace4727a82b7fa50f964b (patch)
treeb64da94ba58f72a2371cdd8644dc48a178b7d260
parentb514ec8cea2c2143e0bd7a0eb377c96a6f091d0d (diff)
downloadjellything-ce9eb140ab9243d1c87ace4727a82b7fa50f964b.tar
jellything-ce9eb140ab9243d1c87ace4727a82b7fa50f964b.tar.bz2
jellything-ce9eb140ab9243d1c87ace4727a82b7fa50f964b.tar.zst
fix yet another fundamental issue in the ebml reader and seekindex.
-rw-r--r--common/src/seek_index.rs2
-rw-r--r--ebml_derive/src/lib.rs2
-rw-r--r--matroska/src/bin/experiment.rs33
-rw-r--r--matroska/src/bin/mkvdump.rs8
-rw-r--r--matroska/src/read.rs62
-rw-r--r--matroska/src/unflatten.rs24
-rw-r--r--remuxer/src/extract.rs24
-rw-r--r--remuxer/src/import/mod.rs4
-rw-r--r--remuxer/src/remux.rs6
-rw-r--r--remuxer/src/seek_index.rs44
-rw-r--r--remuxer/src/segment_extractor.rs4
-rw-r--r--stream/src/webvtt.rs15
-rw-r--r--transcoder/src/subtitles.rs12
13 files changed, 119 insertions, 121 deletions
diff --git a/common/src/seek_index.rs b/common/src/seek_index.rs
index fb41b40..d58cd15 100644
--- a/common/src/seek_index.rs
+++ b/common/src/seek_index.rs
@@ -18,7 +18,7 @@ pub struct SeekIndex {
pub struct BlockIndex {
pub pts: u64,
// pub duration: Option<u64>,
- pub source_off: usize,
+ pub source_off: u64, // points to start of SimpleBlock or BlockGroup (not the Block inside it)
pub size: usize,
}
diff --git a/ebml_derive/src/lib.rs b/ebml_derive/src/lib.rs
index 6b650f1..ab6cff8 100644
--- a/ebml_derive/src/lib.rs
+++ b/ebml_derive/src/lib.rs
@@ -116,7 +116,7 @@ pub fn define_ebml(ts: TokenStream) -> TokenStream {
#(#enum_variants),*
}
impl MatroskaTag {
- /// returns path in **reverse** order or None if global.
+ /// returns path in order top-to-immediate-parent order or None if global.
pub fn path(&self) -> Option<&'static [u64]> {
match self { #(#path_match),* }
}
diff --git a/matroska/src/bin/experiment.rs b/matroska/src/bin/experiment.rs
deleted file mode 100644
index e185787..0000000
--- a/matroska/src/bin/experiment.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- 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>
-*/
-use jellymatroska::{
- matroska::MatroskaTag, read::EbmlReader, unflatten::IterWithPos, write::EbmlWriter,
-};
-use std::{
- fs::File,
- io::{stdout, BufReader, BufWriter},
-};
-
-fn main() {
- env_logger::init_from_env("LOG");
- let path = std::env::args().nth(1).unwrap();
- let mut r = EbmlReader::new(BufReader::new(File::open(path).unwrap()));
- let mut w = EbmlWriter::new(BufWriter::new(stdout()), 0);
-
- // r.seek(
- // 631147167 + 52,
- // ebml::matroska::MatroskaTag::Cues(Master::Start),
- // )
- // .unwrap();
-
- while let Some(tag) = r.next() {
- let tag = tag.unwrap();
- if MatroskaTag::is_master(tag.id()).unwrap() {
- eprintln!("{tag:?}");
- }
- w.write_tag(&tag).unwrap();
- }
-}
diff --git a/matroska/src/bin/mkvdump.rs b/matroska/src/bin/mkvdump.rs
index 9e35716..27b4849 100644
--- a/matroska/src/bin/mkvdump.rs
+++ b/matroska/src/bin/mkvdump.rs
@@ -3,9 +3,7 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2024 metamuffin <metamuffin.org>
*/
-use jellymatroska::{
- block::Block, matroska::MatroskaTag, read::EbmlReader, unflatten::IterWithPos,
-};
+use jellymatroska::{block::Block, matroska::MatroskaTag, read::EbmlReader};
use std::{fs::File, io::BufReader};
fn main() {
@@ -14,13 +12,13 @@ fn main() {
let mut r = EbmlReader::new(BufReader::new(File::open(path).unwrap()));
while let Some(tag) = r.next() {
- let tag = tag.unwrap();
+ let (position, tag) = tag.unwrap();
match tag {
MatroskaTag::SimpleBlock(b) | MatroskaTag::Block(b) => {
let b = Block::parse(&b).unwrap();
println!("block kf={} ts_off={}", b.keyframe, b.timestamp_off)
}
- _ => println!("{} {tag:?}", r.position),
+ _ => println!("{} {tag:?}", position.unwrap_or(0)),
}
}
}
diff --git a/matroska/src/read.rs b/matroska/src/read.rs
index 3e858f7..68a8efa 100644
--- a/matroska/src/read.rs
+++ b/matroska/src/read.rs
@@ -5,7 +5,7 @@
*/
use crate::error::Error;
use crate::Result;
-use crate::{matroska::MatroskaTag, size::EbmlSize, unflatten::IterWithPos, Master};
+use crate::{matroska::MatroskaTag, size::EbmlSize, Master};
use log::{debug, warn};
use std::{
collections::VecDeque,
@@ -17,21 +17,21 @@ impl<T: Read + Seek> ReadAndSeek for T {}
#[derive(Debug, Clone, Copy)]
pub struct StackTag {
- end: Option<usize>,
+ end: Option<u64>,
id: u64,
}
pub struct EbmlReader {
inner: Box<dyn ReadAndSeek>,
stack: Vec<StackTag>,
- queue: VecDeque<MatroskaTag>,
- pub position: usize,
+ queue: VecDeque<(Option<u64>, MatroskaTag)>,
+ position: u64,
}
impl Read for EbmlReader {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let r = self.inner.read(buf)?;
- self.position += r;
+ self.position += r as u64;
Ok(r)
}
}
@@ -53,15 +53,15 @@ impl EbmlReader {
self.position += 1;
Ok(b[0])
}
-
+
pub fn read_buf(&mut self, size: impl Into<usize>) -> Result<Vec<u8>> {
let size = size.into();
let mut b = vec![0u8; size];
self.inner.read_exact(&mut b).map_err(Error::Io)?;
- self.position += size;
+ self.position += size as u64;
Ok(b)
}
-
+
pub fn read_vint_len(&mut self) -> Result<(u64, usize)> {
let s = self.read_byte()?;
let len = s.leading_zeros() + 1;
@@ -76,24 +76,24 @@ impl EbmlReader {
}
Ok((value, len as usize))
}
-
+
#[inline]
pub fn read_vint(&mut self) -> Result<u64> {
Ok(self.read_vint_len()?.0)
}
-
+
#[inline]
pub fn read_utf8(&mut self, size: impl Into<usize>) -> Result<String> {
let b = self.read_buf(size)?;
Ok(String::from_utf8(b).map_err(|_| Error::InvalidUTF8)?)
}
-
+
#[inline]
pub fn read_tag_id(&mut self) -> Result<u64> {
let (value, len) = self.read_vint_len()?;
Ok(value + (1 << (7 * len)))
}
-
+
#[inline]
pub fn read_tag_size(&mut self) -> Result<EbmlSize> {
Ok(EbmlSize::from_vint(self.read_vint_len()?))
@@ -109,7 +109,7 @@ impl EbmlReader {
}
self.stack.pop();
self.queue
- .push_back(MatroskaTag::construct_master(e.id, Master::End)?);
+ .push_back((None, MatroskaTag::construct_master(e.id, Master::End)?));
} else {
break;
}
@@ -118,6 +118,7 @@ impl EbmlReader {
}
}
+ let start_position = self.position;
let id = self.read_tag_id()?;
let size = self.read_tag_size()?;
let is_master = MatroskaTag::is_master(id)?;
@@ -131,30 +132,29 @@ impl EbmlReader {
if let Some(path) = tag.path() {
// we have slightly different rules for closing tags implicitly
// this closes as many tags as needed to make the next tag a valid child
- while let Some(tag @ StackTag { end: None, .. }) = self.stack.last() {
- if path.last() == Some(&tag.id) {
+ while let Some(stag @ StackTag { end: None, .. }) = self.stack.last() {
+ if path.last() == Some(&stag.id) {
break;
} else {
- self.queue.push_back(MatroskaTag::construct_master(
- self.stack.pop().unwrap().id,
- Master::End,
- )?);
+ let end =
+ MatroskaTag::construct_master(self.stack.pop().unwrap().id, Master::End)?;
+ self.queue.push_back((None, end));
}
}
}
if is_master {
self.stack.push(StackTag {
- end: size.some().map(|s| s + self.position),
+ end: size.some().map(|s| s as u64 + self.position),
id,
});
}
- self.queue.push_back(tag);
+ self.queue.push_back((Some(start_position), tag));
Ok(())
}
/// context should be the next expected tag, such that the stack can be derived from its path.
- pub fn seek(&mut self, position: usize, context: MatroskaTag) -> Result<()> {
+ pub fn seek(&mut self, position: u64, context: MatroskaTag) -> Result<()> {
let path = context.path().ok_or(Error::GlobalTagsAsContext)?;
debug!(
"seeking to {position} with a context restored from path {:x?}",
@@ -162,9 +162,7 @@ impl EbmlReader {
);
self.queue.clear();
self.position = position;
- self.inner
- .seek(SeekFrom::Start(position as u64))
- .map_err(Error::Io)?;
+ self.inner.seek(SeekFrom::Start(position as u64))?;
self.stack = path
.iter()
.map(|id| StackTag { id: *id, end: None })
@@ -173,13 +171,8 @@ impl EbmlReader {
}
}
-impl IterWithPos for EbmlReader {
- type Item = Result<MatroskaTag>;
-
- fn position(&self) -> usize {
- self.position
- }
-
+impl Iterator for EbmlReader {
+ type Item = Result<(Option<u64>, MatroskaTag)>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(t) = self.queue.pop_front() {
// match t {
@@ -198,7 +191,10 @@ impl IterWithPos for EbmlReader {
match self.queue.pop_front() {
Some(q) => Some(Ok(q)),
None => match self.stack.pop() {
- Some(q) => Some(MatroskaTag::construct_master(q.id, Master::End)),
+ Some(q) => Some(Ok((
+ None,
+ MatroskaTag::construct_master(q.id, Master::End).unwrap(),
+ ))),
None => Some(Err(e)),
},
}
diff --git a/matroska/src/unflatten.rs b/matroska/src/unflatten.rs
index 71089f4..944d2c7 100644
--- a/matroska/src/unflatten.rs
+++ b/matroska/src/unflatten.rs
@@ -3,30 +3,23 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2024 metamuffin <metamuffin.org>
*/
-use crate::{matroska::MatroskaTag, Master};
use crate::Result;
-
-
-pub trait IterWithPos {
- type Item;
- fn next(&mut self) -> Option<Self::Item>;
- fn position(&self) -> usize;
-}
+use crate::{matroska::MatroskaTag, Master};
pub struct Unflat<'a> {
pub item: MatroskaTag,
pub children: Option<Unflatten<'a>>,
- pub position: usize,
+ pub position: Option<u64>,
}
pub struct Unflatten<'a> {
- inner: &'a mut dyn IterWithPos<Item = Result<MatroskaTag>>,
+ inner: &'a mut dyn Iterator<Item = Result<(Option<u64>, MatroskaTag)>>,
stop: bool,
end: Option<MatroskaTag>,
}
impl<'a> Unflatten<'a> {
- pub fn new(inner: &'a mut dyn IterWithPos<Item = Result<MatroskaTag>>) -> Self {
+ pub fn new(inner: &'a mut dyn Iterator<Item = Result<(Option<u64>, MatroskaTag)>>) -> Self {
Self {
inner,
stop: false,
@@ -34,7 +27,7 @@ impl<'a> Unflatten<'a> {
}
}
pub fn new_with_end(
- inner: &'a mut dyn IterWithPos<Item = Result<MatroskaTag>>,
+ inner: &'a mut dyn Iterator<Item = Result<(Option<u64>, MatroskaTag)>>,
start: MatroskaTag,
) -> Self {
Self {
@@ -47,19 +40,14 @@ impl<'a> Unflatten<'a> {
self.stop = true;
}
- pub fn position(&self) -> usize {
- self.inner.position()
- }
-
pub fn n(&mut self) -> Option<Result<Unflat>> {
if self.stop {
return None;
}
- let position = self.inner.position();
match self.inner.next() {
None => None,
Some(Err(e)) => Some(Err(e)),
- Some(Ok(item)) => {
+ Some(Ok((position, item))) => {
let master = MatroskaTag::is_master(item.id()).unwrap();
if Some(&item) == self.end.as_ref() {
self.stop = true;
diff --git a/remuxer/src/extract.rs b/remuxer/src/extract.rs
index 108b76c..1b2b50c 100644
--- a/remuxer/src/extract.rs
+++ b/remuxer/src/extract.rs
@@ -6,8 +6,8 @@
use crate::seek_index::get_seek_index;
use anyhow::{anyhow, bail};
use jellycommon::LocalTrack;
-use jellymatroska::{block::Block, read::EbmlReader, unflatten::IterWithPos, Master, MatroskaTag};
-use log::{debug, info};
+use jellymatroska::{block::Block, read::EbmlReader, Master, MatroskaTag};
+use log::debug;
use std::{fs::File, io::BufReader, path::PathBuf};
pub fn extract_track(
@@ -20,12 +20,16 @@ pub fn extract_track(
let index = get_seek_index(&source_path)?;
let index = index
.get(&(track_info.track as u64))
- .ok_or(anyhow!("track missing 4"))?;
+ .ok_or(anyhow!("track missing"))?;
let mut out = Vec::new();
for b in &index.blocks {
- reader.seek(b.source_off, MatroskaTag::Cluster(Master::Start))?;
+ reader.seek(b.source_off, MatroskaTag::BlockGroup(Master::Start))?;
let (duration, block) = read_group(&mut reader)?;
+ assert_eq!(
+ track_info.track, block.track as usize,
+ "seek index is wrong"
+ );
out.push((b.pts, duration, block.data))
}
Ok(out)
@@ -33,23 +37,25 @@ pub fn extract_track(
pub fn read_group(segment: &mut EbmlReader) -> anyhow::Result<(u64, Block)> {
let (mut dur, mut block) = (None, None);
- loop {
- let item = segment.next().ok_or(anyhow!("eof"))??;
+ for _ in 0..10 {
+ let (_, item) = segment.next().ok_or(anyhow!("eof"))??;
match item {
MatroskaTag::Void(_) => (),
MatroskaTag::Crc32(_) => (),
- MatroskaTag::Cluster(_) => (),
+ MatroskaTag::Cluster(_) => bail!("unexpected cluster"),
MatroskaTag::Timestamp(_) => (),
MatroskaTag::SimpleBlock(_buf) => {
- // bail!("unexpected simpleblock, where a group was expected")
+ let block = Block::parse(&_buf)?;
+ return Ok((1000, block)); // HDMV/PGS does not use duration?!
}
MatroskaTag::BlockGroup(Master::Start) => (),
MatroskaTag::BlockGroup(Master::End) => return Ok((dur.unwrap(), block.unwrap())),
MatroskaTag::BlockDuration(duration) => dur = Some(duration),
MatroskaTag::Block(buf) => block = Some(Block::parse(&buf)?),
MatroskaTag::Cues(_) => bail!("reached cues, this is the end"),
- MatroskaTag::Segment(Master::End) => info!("extractor reached segment end"),
+ MatroskaTag::Segment(Master::End) => bail!("extractor reached segment end"),
_ => debug!("(rs) tag ignored: {item:?}"),
}
}
+ bail!(".")
}
diff --git a/remuxer/src/import/mod.rs b/remuxer/src/import/mod.rs
index 2981cea..d6fa2d0 100644
--- a/remuxer/src/import/mod.rs
+++ b/remuxer/src/import/mod.rs
@@ -9,7 +9,7 @@ use jellycommon::{Chapter, LocalTrack, SourceTrack, SourceTrackKind};
use jellymatroska::{
matroska::MatroskaTag,
read::EbmlReader,
- unflatten::{IterWithPos, Unflat, Unflatten},
+ unflatten::{Unflat, Unflatten},
};
use log::{debug, error, info, warn};
use std::{path::PathBuf, time::Instant};
@@ -30,7 +30,7 @@ pub struct MatroskaMetadata {
pub fn import_metadata(input: &mut EbmlReader) -> Result<MatroskaMetadata> {
while let Some(item) = input.next() {
let item = match item {
- Ok(item) => item,
+ Ok((_, item)) => item,
Err(e) => {
if !matches!(e, jellymatroska::error::Error::Io(_)) {
warn!("{e}");
diff --git a/remuxer/src/remux.rs b/remuxer/src/remux.rs
index 8273c9e..851b43d 100644
--- a/remuxer/src/remux.rs
+++ b/remuxer/src/remux.rs
@@ -31,7 +31,7 @@ use std::{
struct ClusterLayout {
position: usize,
timestamp: u64,
- source_offsets: Vec<Option<usize>>,
+ source_offsets: Vec<Option<u64>>,
blocks: Vec<(usize, BlockIndex)>,
}
@@ -277,7 +277,7 @@ pub fn remux_stream_into(
// this should be fine since tracks are only read according to segment_layout
find_first_cluster_with_off(&segment_layout, skip, i)
.ok_or(anyhow!("cluster hole at eof"))?,
- MatroskaTag::Cluster(Master::Start),
+ MatroskaTag::Cluster(Master::Start), // TODO shouldn't this be a child of cluster?
)
.context("seeking in input")?;
let mut stream =
@@ -333,7 +333,7 @@ fn find_first_cluster_with_off(
segment_layout: &[ClusterLayout],
skip: usize,
track: usize,
-) -> Option<usize> {
+) -> Option<u64> {
for skip in skip..segment_layout.len() {
if let Some(off) = segment_layout[skip].source_offsets[track] {
return Some(off);
diff --git a/remuxer/src/seek_index.rs b/remuxer/src/seek_index.rs
index eba7344..7e9cee1 100644
--- a/remuxer/src/seek_index.rs
+++ b/remuxer/src/seek_index.rs
@@ -9,7 +9,7 @@ use jellycommon::seek_index::{BlockIndex, SeekIndex};
use jellymatroska::{
block::Block,
read::EbmlReader,
- unflatten::{IterWithPos, Unflat, Unflatten},
+ unflatten::{Unflat, Unflatten},
MatroskaTag,
};
use log::{debug, info, trace, warn};
@@ -30,7 +30,7 @@ pub fn import_seek_index(input: &mut EbmlReader) -> Result<BTreeMap<u64, SeekInd
let mut seek_index = BTreeMap::new();
while let Some(item) = input.next() {
let item = match item {
- Ok(item) => item,
+ Ok((_, item)) => item,
Err(e) => {
if !matches!(e, jellymatroska::error::Error::Io(_)) {
warn!("{e}");
@@ -67,20 +67,20 @@ fn import_seek_index_segment(
MatroskaTag::Cluster(_) => {
let mut children = children.unwrap();
let mut pts = 0;
- let mut position = children.position();
-
loop {
- if let Some(Ok(Unflat { children, item, .. })) = children.n() {
+ if let Some(Ok(Unflat {
+ children,
+ item,
+ position,
+ })) = children.n()
+ {
match item {
MatroskaTag::Timestamp(ts) => pts = ts,
MatroskaTag::BlockGroup(_) => {
trace!("group");
let mut children = children.unwrap();
- // let position = children.position(); //? TODO where should this point to? cluster or block? // probably block
while let Some(Ok(Unflat {
- children: _,
- item,
- position: _block_position,
+ children: _, item, ..
})) = children.n()
{
match item {
@@ -90,7 +90,12 @@ fn import_seek_index_segment(
"block: track={} tso={}",
block.track, block.timestamp_off
);
- seek_index_add(seek_index, &block, position, pts);
+ seek_index_add(
+ seek_index,
+ &block,
+ position.unwrap(),
+ pts,
+ );
}
_ => trace!("{item:?}"),
}
@@ -104,14 +109,13 @@ fn import_seek_index_segment(
block.timestamp_off
);
trace!("{pts} {}", block.timestamp_off);
- seek_index_add(seek_index, &block, position, pts);
+ seek_index_add(seek_index, &block, position.unwrap(), pts);
}
_ => trace!("(rsc) tag ignored: {item:?}"),
}
} else {
break;
}
- position = children.position();
}
}
_ => debug!("(rs) tag ignored: {item:?}"),
@@ -123,9 +127,23 @@ fn import_seek_index_segment(
fn seek_index_add(
seek_index: &mut BTreeMap<u64, SeekIndex>,
block: &Block,
- position: usize,
+ position: u64,
pts_base: u64,
) {
+ //* I heard this helped debugging once.
+ // {
+ // let mut f = File::open("/home/muffin/videos/itte-yorushika.mkv").unwrap();
+ // f.seek(std::io::SeekFrom::Start(position.try_into().unwrap()))
+ // .unwrap();
+ // let mut buf = [0u8];
+ // f.read_exact(&mut buf).unwrap();
+
+ // eprintln!("{}", buf[0]);
+ // if buf[0] != 0xa0 && buf[0] != 0xa3 {
+ // warn!("invalid position {position}")
+ // }
+ // }
+
let trs = seek_index
.entry(block.track)
.or_insert(SeekIndex::default());
diff --git a/remuxer/src/segment_extractor.rs b/remuxer/src/segment_extractor.rs
index 89d5784..ec645c3 100644
--- a/remuxer/src/segment_extractor.rs
+++ b/remuxer/src/segment_extractor.rs
@@ -4,7 +4,7 @@
Copyright (C) 2024 metamuffin <metamuffin.org>
*/
use anyhow::{anyhow, bail, Result};
-use jellymatroska::{block::Block, read::EbmlReader, unflatten::IterWithPos, Master, MatroskaTag};
+use jellymatroska::{block::Block, read::EbmlReader, Master, MatroskaTag};
use log::{debug, info, trace};
pub struct SegmentExtractIter<'a> {
@@ -23,7 +23,7 @@ impl<'a> SegmentExtractIter<'a> {
let mut group = false;
let mut saved_block = None;
loop {
- let item = self.segment.next().ok_or(anyhow!("eof"))??;
+ let (_, item) = self.segment.next().ok_or(anyhow!("eof"))??;
match item {
MatroskaTag::Void(_) => (),
MatroskaTag::Crc32(_) => (),
diff --git a/stream/src/webvtt.rs b/stream/src/webvtt.rs
index 2de9835..e720800 100644
--- a/stream/src/webvtt.rs
+++ b/stream/src/webvtt.rs
@@ -7,7 +7,9 @@ use anyhow::{anyhow, bail, Context, Result};
use jellybase::CONF;
use jellycommon::{jhls::SubtitleCue, stream::StreamSpec, LocalTrack, Node};
use jellyremuxer::extract::extract_track;
-use jellytranscoder::subtitles::{parse_ass_blocks, parse_webvtt_blocks, write_webvtt};
+use jellytranscoder::subtitles::{
+ parse_ass_blocks, parse_pgs_blocks, parse_webvtt_blocks, write_webvtt,
+};
use tokio::io::{AsyncWriteExt, DuplexStream};
pub async fn vtt_stream(
@@ -48,6 +50,17 @@ pub async fn vtt_stream(
let subtitles = parse_webvtt_blocks(webvtt_blocks).context("parsing subtitles")?;
write(subtitles)?;
}
+ "S_HDMV/PGS" => {
+ let webvtt_blocks = tokio::task::spawn_blocking(move || {
+ extract_track(CONF.media_path.clone(), local_track)
+ })
+ .await??;
+
+ let subtitles = parse_pgs_blocks(webvtt_blocks).context("parsing subtitles")?;
+ write(subtitles)?;
+ }
+ "S_HDMV/TEXTST" => bail!("no HDMV/PGSs yet"),
+ "S_ARISUB" => bail!("no arisub yet"),
"S_TEXT/UTF8" => bail!("no subrip yet"),
"S_VOBSUB" => bail!("no vobsub yet"),
"S_TEXT/ASS" => {
diff --git a/transcoder/src/subtitles.rs b/transcoder/src/subtitles.rs
index 1fea3cf..84db5a9 100644
--- a/transcoder/src/subtitles.rs
+++ b/transcoder/src/subtitles.rs
@@ -39,6 +39,18 @@ pub fn parse_webvtt_blocks(blocks: Vec<(u64, u64, Vec<u8>)>) -> anyhow::Result<V
}
Ok(out)
}
+pub fn parse_pgs_blocks(blocks: Vec<(u64, u64, Vec<u8>)>) -> anyhow::Result<Vec<SubtitleCue>> {
+ let mut out = Vec::new();
+ for (pts, dur, block) in blocks {
+ let _content = String::from_utf8_lossy(&block).trim().to_string();
+ out.push(SubtitleCue {
+ content: "PGS stub".to_string(),
+ start: pts as f64 / 1000.,
+ end: (pts + dur) as f64 / 1000.,
+ });
+ }
+ Ok(out)
+}
pub fn parse_ass_blocks(
_codec_private: Vec<u8>,