Move codec_privates onto DiscTitle, eliminate duplicate methods
Design fix: codec_privates are now a field on DiscTitle, not a separate parameter passed through the pipeline. This eliminates the root cause of the network codec_private bug (forgot to pass the separate param). API changes: - output() takes (url, &DiscTitle) — no separate codec_privates param - MkvOutputStream::create, M2tsOutputStream::create, NetworkOutputStream::connect all read codec_privates from title.codec_privates - M2tsMeta::from_title() takes only &DiscTitle — reads privates from title - Deleted from_title_with_privates (was the wrong-name duplicate) - Merged read_header + read_header_from_stream into one read_header(impl Read) - Deleted finish(self) from TsMuxer, keep only finish(&mut self) Rule: ONE public method per action. No _with_X, _from_Y, _ref variants.
This commit is contained in:
@@ -187,6 +187,7 @@ impl Disc {
|
|||||||
chapters,
|
chapters,
|
||||||
extents,
|
extents,
|
||||||
content_format: ContentFormat::BdTs,
|
content_format: ContentFormat::BdTs,
|
||||||
|
codec_privates: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ impl Disc {
|
|||||||
chapters: Vec::new(),
|
chapters: Vec::new(),
|
||||||
extents,
|
extents,
|
||||||
content_format: ContentFormat::MpegPs,
|
content_format: ContentFormat::MpegPs,
|
||||||
|
codec_privates: Vec::new(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,6 +116,9 @@ pub struct DiscTitle {
|
|||||||
pub extents: Vec<Extent>,
|
pub extents: Vec<Extent>,
|
||||||
/// Content format for this title
|
/// Content format for this title
|
||||||
pub content_format: ContentFormat,
|
pub content_format: ContentFormat,
|
||||||
|
/// Codec initialization data per stream (SPS/PPS, etc).
|
||||||
|
/// Index matches `streams`. None for streams without codec init data.
|
||||||
|
pub codec_privates: Vec<Option<Vec<u8>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A clip reference within a title.
|
/// A clip reference within a title.
|
||||||
@@ -797,6 +800,7 @@ impl DiscTitle {
|
|||||||
chapters: Vec::new(),
|
chapters: Vec::new(),
|
||||||
extents: Vec::new(),
|
extents: Vec::new(),
|
||||||
content_format: ContentFormat::BdTs,
|
content_format: ContentFormat::BdTs,
|
||||||
|
codec_privates: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1502,6 +1506,7 @@ mod tests {
|
|||||||
chapters: Vec::new(),
|
chapters: Vec::new(),
|
||||||
extents: Vec::new(),
|
extents: Vec::new(),
|
||||||
content_format: ContentFormat::BdTs,
|
content_format: ContentFormat::BdTs,
|
||||||
|
codec_privates: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -90,7 +90,8 @@ impl M2tsStream {
|
|||||||
let file_size = reader.seek(SeekFrom::End(0))?;
|
let file_size = reader.seek(SeekFrom::End(0))?;
|
||||||
reader.seek(SeekFrom::Start(0))?;
|
reader.seek(SeekFrom::Start(0))?;
|
||||||
|
|
||||||
// Try FMKV metadata header
|
// Try FMKV metadata header — save position so we can seek back on failure
|
||||||
|
let start = reader.stream_position()?;
|
||||||
if let Ok(Some(m)) = meta::read_header(&mut reader) {
|
if let Ok(Some(m)) = meta::read_header(&mut reader) {
|
||||||
let header_end = reader.stream_position()?;
|
let header_end = reader.stream_position()?;
|
||||||
let content_size = file_size.saturating_sub(header_end);
|
let content_size = file_size.saturating_sub(header_end);
|
||||||
@@ -113,8 +114,8 @@ impl M2tsStream {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback: scan PMT for streams, PTS for duration
|
// No FMKV header — seek back and try PMT scan
|
||||||
reader.seek(SeekFrom::Start(0))?;
|
reader.seek(SeekFrom::Start(start))?;
|
||||||
let mut buf = vec![0u8; SCAN_SIZE];
|
let mut buf = vec![0u8; SCAN_SIZE];
|
||||||
let n = reader.read(&mut buf)?;
|
let n = reader.read(&mut buf)?;
|
||||||
|
|
||||||
|
|||||||
+14
-65
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
use crate::disc::{AudioStream, ColorSpace, DiscTitle, Stream, SubtitleStream, VideoStream};
|
use crate::disc::{AudioStream, ColorSpace, DiscTitle, Stream, SubtitleStream, VideoStream};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::io::{self, Read, Seek, SeekFrom, Write};
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
/// Magic bytes: "FMKV" + version 1 + 2 reserved bytes.
|
/// Magic bytes: "FMKV" + version 1 + 2 reserved bytes.
|
||||||
const MAGIC: [u8; 8] = [b'F', b'M', b'K', b'V', 0x00, 0x01, 0x00, 0x00];
|
const MAGIC: [u8; 8] = [b'F', b'M', b'K', b'V', 0x00, 0x01, 0x00, 0x00];
|
||||||
@@ -77,26 +77,14 @@ pub enum MetaStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl M2tsMeta {
|
impl M2tsMeta {
|
||||||
/// Build metadata from a disc Title with optional codec_private per stream.
|
/// Build metadata from a DiscTitle. Codec privates come from title.codec_privates.
|
||||||
pub fn from_title_with_privates(title: &DiscTitle, codec_privates: &[Option<Vec<u8>>]) -> Self {
|
|
||||||
let mut meta = Self::from_title(title);
|
|
||||||
for (i, s) in meta.streams.iter_mut().enumerate() {
|
|
||||||
if let MetaStream::Video { codec_private, .. } = s {
|
|
||||||
if let Some(Some(cp)) = codec_privates.get(i) {
|
|
||||||
use base64::Engine;
|
|
||||||
*codec_private = Some(base64::engine::general_purpose::STANDARD.encode(cp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
meta
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build metadata from a disc Title.
|
|
||||||
pub fn from_title(title: &DiscTitle) -> Self {
|
pub fn from_title(title: &DiscTitle) -> Self {
|
||||||
|
use base64::Engine;
|
||||||
let streams = title
|
let streams = title
|
||||||
.streams
|
.streams
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| match s {
|
.enumerate()
|
||||||
|
.map(|(i, s)| match s {
|
||||||
Stream::Video(v) => MetaStream::Video {
|
Stream::Video(v) => MetaStream::Video {
|
||||||
pid: v.pid,
|
pid: v.pid,
|
||||||
codec: v.codec.id().into(),
|
codec: v.codec.id().into(),
|
||||||
@@ -105,7 +93,9 @@ impl M2tsMeta {
|
|||||||
hdr: v.hdr.id().into(),
|
hdr: v.hdr.id().into(),
|
||||||
label: v.label.clone(),
|
label: v.label.clone(),
|
||||||
secondary: v.secondary,
|
secondary: v.secondary,
|
||||||
codec_private: None,
|
codec_private: title.codec_privates.get(i)
|
||||||
|
.and_then(|cp| cp.as_ref())
|
||||||
|
.map(|cp| base64::engine::general_purpose::STANDARD.encode(cp)),
|
||||||
},
|
},
|
||||||
Stream::Audio(a) => MetaStream::Audio {
|
Stream::Audio(a) => MetaStream::Audio {
|
||||||
pid: a.pid,
|
pid: a.pid,
|
||||||
@@ -200,6 +190,7 @@ impl M2tsMeta {
|
|||||||
chapters: Vec::new(),
|
chapters: Vec::new(),
|
||||||
extents: Vec::new(),
|
extents: Vec::new(),
|
||||||
content_format: crate::disc::ContentFormat::BdTs,
|
content_format: crate::disc::ContentFormat::BdTs,
|
||||||
|
codec_privates: self.codec_privates(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,27 +228,21 @@ pub fn write_header(w: &mut impl Write, meta: &M2tsMeta) -> io::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to read a metadata header from the start of an m2ts file.
|
/// Try to read an FMKV metadata header.
|
||||||
/// Returns None for bare m2ts files (no header).
|
/// Returns None if magic bytes don't match. Consumes header bytes on success.
|
||||||
/// On success, leaves reader positioned at the first TS packet.
|
/// Caller handles seek-back on failure if needed (e.g. for fallback PMT scan).
|
||||||
/// On failure, seeks back to the start.
|
pub fn read_header(r: &mut impl Read) -> io::Result<Option<M2tsMeta>> {
|
||||||
pub fn read_header<R: Read + Seek>(r: &mut R) -> io::Result<Option<M2tsMeta>> {
|
const MAX_JSON_SIZE: usize = 10 * 1024 * 1024; // 10 MB
|
||||||
let start = r.stream_position()?;
|
|
||||||
|
|
||||||
let mut magic = [0u8; 8];
|
let mut magic = [0u8; 8];
|
||||||
if r.read_exact(&mut magic).is_err() {
|
if r.read_exact(&mut magic).is_err() {
|
||||||
r.seek(SeekFrom::Start(start))?;
|
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if magic[..4] != MAGIC[..4] {
|
if magic[..4] != MAGIC[..4] {
|
||||||
// Not a freemkv m2ts — seek back
|
|
||||||
r.seek(SeekFrom::Start(start))?;
|
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_JSON_SIZE: usize = 10 * 1024 * 1024; // 10 MB
|
|
||||||
|
|
||||||
let mut len_buf = [0u8; 4];
|
let mut len_buf = [0u8; 4];
|
||||||
r.read_exact(&mut len_buf)?;
|
r.read_exact(&mut len_buf)?;
|
||||||
let json_len = u32::from_be_bytes(len_buf) as usize;
|
let json_len = u32::from_be_bytes(len_buf) as usize;
|
||||||
@@ -275,42 +260,6 @@ pub fn read_header<R: Read + Seek>(r: &mut R) -> io::Result<Option<M2tsMeta>> {
|
|||||||
let raw_len = 8 + 4 + json_len;
|
let raw_len = 8 + 4 + json_len;
|
||||||
let padded_len = raw_len.div_ceil(PACKET_SIZE) * PACKET_SIZE;
|
let padded_len = raw_len.div_ceil(PACKET_SIZE) * PACKET_SIZE;
|
||||||
let padding = padded_len - raw_len;
|
let padding = padded_len - raw_len;
|
||||||
if padding > 0 {
|
|
||||||
r.seek(SeekFrom::Current(padding as i64))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Some(meta))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read a metadata header from a forward-only stream (no Seek required).
|
|
||||||
/// Returns None if the magic bytes don't match. Consumes the header bytes.
|
|
||||||
pub fn read_header_from_stream(r: &mut impl Read) -> io::Result<Option<M2tsMeta>> {
|
|
||||||
let mut magic = [0u8; 8];
|
|
||||||
r.read_exact(&mut magic)?;
|
|
||||||
|
|
||||||
if magic[..4] != MAGIC[..4] {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAX_JSON_SIZE: usize = 10 * 1024 * 1024;
|
|
||||||
|
|
||||||
let mut len_buf = [0u8; 4];
|
|
||||||
r.read_exact(&mut len_buf)?;
|
|
||||||
let json_len = u32::from_be_bytes(len_buf) as usize;
|
|
||||||
if json_len > MAX_JSON_SIZE {
|
|
||||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "FMKV JSON too large"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut json_buf = vec![0u8; json_len];
|
|
||||||
r.read_exact(&mut json_buf)?;
|
|
||||||
|
|
||||||
let meta: M2tsMeta = serde_json::from_slice(&json_buf)
|
|
||||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
|
||||||
|
|
||||||
// Skip padding
|
|
||||||
let raw_len = 8 + 4 + json_len;
|
|
||||||
let padded_len = raw_len.div_ceil(PACKET_SIZE) * PACKET_SIZE;
|
|
||||||
let padding = padded_len - raw_len;
|
|
||||||
if padding > 0 {
|
if padding > 0 {
|
||||||
let mut skip = vec![0u8; padding];
|
let mut skip = vec![0u8; padding];
|
||||||
r.read_exact(&mut skip)?;
|
r.read_exact(&mut skip)?;
|
||||||
|
|||||||
+2
-5
@@ -15,13 +15,10 @@ pub struct MkvOutputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MkvOutputStream {
|
impl MkvOutputStream {
|
||||||
/// Create an MKV output stream.
|
/// Create an MKV output stream. Codec privates come from title.codec_privates.
|
||||||
/// `codec_privates` provides initialization data per track (from InputStream).
|
|
||||||
/// Tracks without codec_private get None.
|
|
||||||
pub fn create(
|
pub fn create(
|
||||||
writer: Box<dyn WriteSeek>,
|
writer: Box<dyn WriteSeek>,
|
||||||
title: &DiscTitle,
|
title: &DiscTitle,
|
||||||
codec_privates: &[Option<Vec<u8>>],
|
|
||||||
) -> io::Result<Self> {
|
) -> io::Result<Self> {
|
||||||
let mut tracks = Vec::new();
|
let mut tracks = Vec::new();
|
||||||
for (idx, s) in title.streams.iter().enumerate() {
|
for (idx, s) in title.streams.iter().enumerate() {
|
||||||
@@ -30,7 +27,7 @@ impl MkvOutputStream {
|
|||||||
crate::disc::Stream::Audio(a) => MkvTrack::audio(a),
|
crate::disc::Stream::Audio(a) => MkvTrack::audio(a),
|
||||||
crate::disc::Stream::Subtitle(s) => MkvTrack::subtitle(s),
|
crate::disc::Stream::Subtitle(s) => MkvTrack::subtitle(s),
|
||||||
};
|
};
|
||||||
if let Some(cp) = codec_privates.get(idx).and_then(|c| c.as_ref()) {
|
if let Some(cp) = title.codec_privates.get(idx).and_then(|c| c.as_ref()) {
|
||||||
track.codec_private = Some(cp.clone());
|
track.codec_private = Some(cp.clone());
|
||||||
}
|
}
|
||||||
tracks.push(track);
|
tracks.push(track);
|
||||||
|
|||||||
+3
-2
@@ -58,8 +58,8 @@ impl NetworkStream {
|
|||||||
stream.set_nodelay(true)?;
|
stream.set_nodelay(true)?;
|
||||||
let mut reader = BufReader::with_capacity(NET_BUF_SIZE, stream);
|
let mut reader = BufReader::with_capacity(NET_BUF_SIZE, stream);
|
||||||
|
|
||||||
// Read FMKV metadata header (inline, since TcpStream doesn't impl Seek)
|
// Read FMKV metadata header
|
||||||
let disc_title = meta::read_header_from_stream(&mut reader)?
|
let disc_title = meta::read_header(&mut reader)?
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
io::Error::new(
|
io::Error::new(
|
||||||
io::ErrorKind::InvalidData,
|
io::ErrorKind::InvalidData,
|
||||||
@@ -149,6 +149,7 @@ mod tests {
|
|||||||
chapters: Vec::new(),
|
chapters: Vec::new(),
|
||||||
extents: Vec::new(),
|
extents: Vec::new(),
|
||||||
content_format: ContentFormat::BdTs,
|
content_format: ContentFormat::BdTs,
|
||||||
|
codec_privates: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-11
@@ -13,23 +13,17 @@ pub struct M2tsOutputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl M2tsOutputStream {
|
impl M2tsOutputStream {
|
||||||
pub fn create(
|
pub fn create(path: &str, title: &DiscTitle) -> io::Result<Self> {
|
||||||
path: &str,
|
|
||||||
title: &DiscTitle,
|
|
||||||
codec_privates: &[Option<Vec<u8>>],
|
|
||||||
) -> io::Result<Self> {
|
|
||||||
let file = std::fs::File::create(path)
|
let file = std::fs::File::create(path)
|
||||||
.map_err(|e| io::Error::new(e.kind(), format!("m2ts://{}: {}", path, e)))?;
|
.map_err(|e| io::Error::new(e.kind(), format!("m2ts://{}: {}", path, e)))?;
|
||||||
let mut writer = io::BufWriter::with_capacity(4 * 1024 * 1024, file);
|
let mut writer = io::BufWriter::with_capacity(4 * 1024 * 1024, file);
|
||||||
// Write FMKV metadata header with codec_privates so M2tsStream::open can read them back
|
|
||||||
if !title.streams.is_empty() {
|
if !title.streams.is_empty() {
|
||||||
let m = super::meta::M2tsMeta::from_title_with_privates(title, codec_privates);
|
let m = super::meta::M2tsMeta::from_title(title);
|
||||||
super::meta::write_header(&mut writer, &m)?;
|
super::meta::write_header(&mut writer, &m)?;
|
||||||
}
|
}
|
||||||
let pids = extract_pids(title);
|
let pids = extract_pids(title);
|
||||||
let mut muxer = TsMuxer::new(writer, &pids);
|
let mut muxer = TsMuxer::new(writer, &pids);
|
||||||
// Pass codec_privates to TsMuxer for Annex B parameter set injection
|
for (i, cp) in title.codec_privates.iter().enumerate() {
|
||||||
for (i, cp) in codec_privates.iter().enumerate() {
|
|
||||||
if let Some(data) = cp {
|
if let Some(data) = cp {
|
||||||
muxer.set_codec_private(i, data.clone());
|
muxer.set_codec_private(i, data.clone());
|
||||||
}
|
}
|
||||||
@@ -45,7 +39,7 @@ impl crate::pes::Stream for M2tsOutputStream {
|
|||||||
fn write(&mut self, frame: &PesFrame) -> io::Result<()> {
|
fn write(&mut self, frame: &PesFrame) -> io::Result<()> {
|
||||||
self.muxer.write_frame(frame.track, frame.pts, &frame.data)
|
self.muxer.write_frame(frame.track, frame.pts, &frame.data)
|
||||||
}
|
}
|
||||||
fn finish(&mut self) -> io::Result<()> { self.muxer.finish_ref() }
|
fn finish(&mut self) -> io::Result<()> { self.muxer.finish() }
|
||||||
fn info(&self) -> &DiscTitle { &self.title }
|
fn info(&self) -> &DiscTitle { &self.title }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +93,6 @@ impl NetworkOutputStream {
|
|||||||
pub fn connect(addr: &str, title: &DiscTitle) -> io::Result<Self> {
|
pub fn connect(addr: &str, title: &DiscTitle) -> io::Result<Self> {
|
||||||
let stream = std::net::TcpStream::connect(addr)?;
|
let stream = std::net::TcpStream::connect(addr)?;
|
||||||
let mut writer = io::BufWriter::with_capacity(256 * 1024, stream);
|
let mut writer = io::BufWriter::with_capacity(256 * 1024, stream);
|
||||||
// Send FMKV metadata header immediately so receiver can read it
|
|
||||||
if !title.streams.is_empty() {
|
if !title.streams.is_empty() {
|
||||||
let m = super::meta::M2tsMeta::from_title(title);
|
let m = super::meta::M2tsMeta::from_title(title);
|
||||||
super::meta::write_header(&mut writer, &m)?;
|
super::meta::write_header(&mut writer, &m)?;
|
||||||
|
|||||||
+2
-3
@@ -370,7 +370,6 @@ pub fn input(url: &str, opts: &InputOptions) -> io::Result<Box<dyn crate::pes::S
|
|||||||
pub fn output(
|
pub fn output(
|
||||||
url: &str,
|
url: &str,
|
||||||
title: &crate::disc::DiscTitle,
|
title: &crate::disc::DiscTitle,
|
||||||
codec_privates: &[Option<Vec<u8>>],
|
|
||||||
) -> io::Result<Box<dyn crate::pes::Stream>> {
|
) -> io::Result<Box<dyn crate::pes::Stream>> {
|
||||||
let parsed = parse_url(url);
|
let parsed = parse_url(url);
|
||||||
match parsed {
|
match parsed {
|
||||||
@@ -380,11 +379,11 @@ pub fn output(
|
|||||||
.map_err(|e| io::Error::new(e.kind(), format!("mkv://{}: {}", path.display(), e)))?;
|
.map_err(|e| io::Error::new(e.kind(), format!("mkv://{}: {}", path.display(), e)))?;
|
||||||
let writer: Box<dyn super::WriteSeek> =
|
let writer: Box<dyn super::WriteSeek> =
|
||||||
Box::new(std::io::BufWriter::with_capacity(IO_BUF_SIZE, file));
|
Box::new(std::io::BufWriter::with_capacity(IO_BUF_SIZE, file));
|
||||||
Ok(Box::new(super::mkvout::MkvOutputStream::create(writer, title, codec_privates)?))
|
Ok(Box::new(super::mkvout::MkvOutputStream::create(writer, title)?))
|
||||||
}
|
}
|
||||||
StreamUrl::M2ts { ref path } => {
|
StreamUrl::M2ts { ref path } => {
|
||||||
validate_file_path(path, "m2ts")?;
|
validate_file_path(path, "m2ts")?;
|
||||||
Ok(Box::new(super::pesout::M2tsOutputStream::create(&path.to_string_lossy(), title, codec_privates)?))
|
Ok(Box::new(super::pesout::M2tsOutputStream::create(&path.to_string_lossy(), title)?))
|
||||||
}
|
}
|
||||||
StreamUrl::Network { ref addr } => {
|
StreamUrl::Network { ref addr } => {
|
||||||
validate_network_addr(addr)?;
|
validate_network_addr(addr)?;
|
||||||
|
|||||||
+1
-5
@@ -139,11 +139,7 @@ impl<W: Write> TsMuxer<W> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(mut self) -> io::Result<()> {
|
pub fn finish(&mut self) -> io::Result<()> {
|
||||||
self.writer.flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish_ref(&mut self) -> io::Result<()> {
|
|
||||||
self.writer.flush()
|
self.writer.flush()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,6 +171,7 @@ fn title_with_video(
|
|||||||
chapters: Vec::new(),
|
chapters: Vec::new(),
|
||||||
extents: Vec::new(),
|
extents: Vec::new(),
|
||||||
content_format,
|
content_format,
|
||||||
|
codec_privates: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ fn sample_disc_title() -> DiscTitle {
|
|||||||
chapters: Vec::new(),
|
chapters: Vec::new(),
|
||||||
extents: Vec::new(),
|
extents: Vec::new(),
|
||||||
content_format: ContentFormat::BdTs,
|
content_format: ContentFormat::BdTs,
|
||||||
|
codec_privates: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,6 +453,7 @@ fn meta_codec_roundtrip() {
|
|||||||
chapters: Vec::new(),
|
chapters: Vec::new(),
|
||||||
extents: Vec::new(),
|
extents: Vec::new(),
|
||||||
content_format: ContentFormat::BdTs,
|
content_format: ContentFormat::BdTs,
|
||||||
|
codec_privates: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let meta = M2tsMeta::from_title(&dt);
|
let meta = M2tsMeta::from_title(&dt);
|
||||||
@@ -486,6 +488,7 @@ fn meta_empty_streams() {
|
|||||||
chapters: Vec::new(),
|
chapters: Vec::new(),
|
||||||
extents: Vec::new(),
|
extents: Vec::new(),
|
||||||
content_format: ContentFormat::BdTs,
|
content_format: ContentFormat::BdTs,
|
||||||
|
codec_privates: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let meta = M2tsMeta::from_title(&dt);
|
let meta = M2tsMeta::from_title(&dt);
|
||||||
@@ -505,6 +508,7 @@ fn meta_all_stream_types() {
|
|||||||
clips: Vec::new(),
|
clips: Vec::new(),
|
||||||
chapters: Vec::new(),
|
chapters: Vec::new(),
|
||||||
content_format: ContentFormat::BdTs,
|
content_format: ContentFormat::BdTs,
|
||||||
|
codec_privates: Vec::new(),
|
||||||
streams: vec![
|
streams: vec![
|
||||||
Stream::Video(VideoStream {
|
Stream::Video(VideoStream {
|
||||||
pid: 0x1011,
|
pid: 0x1011,
|
||||||
@@ -651,6 +655,7 @@ fn mkvstream_roundtrip_bdts() {
|
|||||||
chapters: Vec::new(),
|
chapters: Vec::new(),
|
||||||
extents: Vec::new(),
|
extents: Vec::new(),
|
||||||
content_format: ContentFormat::BdTs,
|
content_format: ContentFormat::BdTs,
|
||||||
|
codec_privates: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let output = Cursor::new(Vec::new());
|
let output = Cursor::new(Vec::new());
|
||||||
@@ -731,6 +736,7 @@ fn mkvstream_meta_preserves_all_streams() {
|
|||||||
chapters: Vec::new(),
|
chapters: Vec::new(),
|
||||||
extents: Vec::new(),
|
extents: Vec::new(),
|
||||||
content_format: ContentFormat::BdTs,
|
content_format: ContentFormat::BdTs,
|
||||||
|
codec_privates: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let output = Cursor::new(Vec::new());
|
let output = Cursor::new(Vec::new());
|
||||||
@@ -791,6 +797,7 @@ fn mkvstream_e2e_h264_produces_valid_mkv() {
|
|||||||
chapters: Vec::new(),
|
chapters: Vec::new(),
|
||||||
extents: Vec::new(),
|
extents: Vec::new(),
|
||||||
content_format: ContentFormat::BdTs,
|
content_format: ContentFormat::BdTs,
|
||||||
|
codec_privates: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Build synthetic BD-TS packets containing valid H.264 NALs
|
// Build synthetic BD-TS packets containing valid H.264 NALs
|
||||||
|
|||||||
Reference in New Issue
Block a user