16次发布
0.6.2 | 2024年4月4日 |
---|---|
0.6.1 | 2024年2月27日 |
0.6.0 | 2023年10月20日 |
0.5.4 | 2023年2月13日 |
0.3.0 | 2021年7月15日 |
#30 in 视频
每月下载 181次
73KB
880 行
此crate是为了简化解析Matroska容器编码的文件而构建的,例如WebMs或MKVs。
[dependencies]
webm-iterable = "0.6.2"
使用方法
WebmIterator
类型是使用MatroskaSpec
作为泛型类型,将ebml-iterable
的TagIterator
作为别名,并实现了Rust的标准Iterator
特性。可以使用任何实现了标准Read
特性的源上的new
函数创建此结构。迭代器输出包含标签数据的MatroskaSpec
变体。
注意:可以使用
with_capacity
方法构建具有指定默认缓冲区大小的WebmIterator
。如果知道要读取的文件的最大标签大小,这仅作为内存管理的微优化是有用的。
然后可以根据需要修改标签中的数据(加密、压缩等),并使用WebmWriter
类型重新编码。 WebmWriter
简单地封装了ebml-iterable
的TagWriter
。可以使用任何实现了标准Write
特性的源上的new
函数创建此结构。
有关迭代ebml数据的更多信息,请参阅ebml-iterable文档。
Matroska特定类型
此crate为特殊Matroska数据标签提供了三个附加结构
Block
SimpleBlock
Frame
(本身不是标签,但在Blocks和Simple Blocks中使用)
Block
pub struct Block {
pub track: u64,
pub timestamp: i16,
pub invisible: bool,
pub lacing: BlockLacing,
}
impl Block {
pub fn read_frame_data(&self) -> Result<Vec<Frame>, WebmCoercionError>
pub fn raw_frame_data(&self) -> &[u8]
}
这些属性是针对由Block元素定义的,该元素由Matroska定义。`Block`结构体实现了`TryFrom<&MatroskaSpec>`和`Into
SimpleBlock
pub struct SimpleBlock {
pub track: u64,
pub timestamp: i16,
pub invisible: bool,
pub lacing: Option<BlockLacing>,
pub discardable: bool,
pub keyframe: bool,
}
impl SimpleBlock {
pub fn read_frame_data(&self) -> Result<Vec<Frame>, WebmCoercionError>
pub fn raw_frame_data(&self) -> &[u8]
}
这些属性是针对由SimpleBlock元素定义的,该元素由Matroska定义。`SimpleBlock`结构体也实现了`TryFrom<&MatroskaSpec>`和`Into
示例
此示例将媒体文件读入内存并解码。
use std::fs::File;
use webm_iterable::WebmIterator;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut src = File::open("media/test.webm").unwrap();
let tag_iterator = WebmIterator::new(&mut src, &[]);
for tag in tag_iterator {
println!("[{:?}]", tag?);
}
Ok(())
}
此示例执行相同操作,但记录每个标签在文件中出现的次数。
use std::fs::File;
use std::collections::HashMap;
use webm_iterable::WebmIterator;
use webm_iterable::matroska_spec::EbmlTag;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut src = File::open("media/test.webm").unwrap();
let tag_iterator = WebmIterator::new(&mut src, &[]);
let mut tag_counts = HashMap::new();
for tag in tag_iterator {
let count = tag_counts.entry(tag?.get_id()).or_insert(0);
*count += 1;
}
println!("{:?}", tag_counts);
Ok(())
}
此示例从webm文件中抓取音频并将结果存储在新文件中。此示例中的逻辑相当复杂 - 代码后的解释。
use std::fs::File;
use std::convert::TryInto;
use webm_iterable::{
WebmIterator,
WebmWriter,
matroska_spec::{MatroskaSpec, Master, Block, EbmlSpecification, EbmlTag},
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1
let mut src = File::open("media/audiosample.webm").unwrap();
let tag_iterator = WebmIterator::new(&mut src, &[MatroskaSpec::TrackEntry(Master::Start)]);
let mut dest = File::create("media/audioout.webm").unwrap();
let mut tag_writer = WebmWriter::new(&mut dest);
let mut stripped_tracks = Vec::new();
// 2
for tag in tag_iterator {
let tag = tag?;
match tag {
// 3
MatroskaSpec::TrackEntry(master) => {
let children = master.get_children();
let is_audio_track = |tag: &MatroskaSpec| {
if let MatroskaSpec::TrackType(val) = tag {
return *val != 2;
} else {
false
}
};
if children.iter().any(is_audio_track) {
let track_number_variant = children.iter().find(|c| matches!(c, MatroskaSpec::TrackNumber(_))).expect("should have a k number child");
let track_number = track_number_variant.as_unsigned_int().expect("TrackNumber is an unsigned int variant");
stripped_tracks.push(*track_number);
} else {
tag_writer.write(&MatroskaSpec::TrackEntry(Master::Full(children)))?;
}
},
// 4
MatroskaSpec::Block(ref data) => {
let block: Block = data.try_into()?;
if !stripped_tracks.iter().any(|t| *t == block.track) {
tag_writer.write(&tag)?;
}
},
MatroskaSpec::SimpleBlock(ref data) => {
let block: Block = data.try_into()?;
if !stripped_tracks.iter().any(|t| *t == block.track) {
tag_writer.write(&tag)?;
}
},
// 5
_ => {
tag_writer.write(&tag)?;
}
}
}
Ok(())
}
在上面的示例中,我们(1)根据本地文件路径构建我们的迭代器和写入器,并声明有用的局部变量,(2)遍历webm文件中的标签,(3)识别任何非音频轨道并将它们的编号存储在`stripped_tracks`变量中;如果是音频,我们将其"TrackEntry"写入,(4)仅写入音频轨道的数据块,并将所有其他标签写入输出目的地。
注意
- 注意传递给`WebmIterator::new()`函数的第二个参数。此参数告诉解码器哪些"主"标签应作为`Master::Full`变体而不是标准`Master::Start`和`Master::End`变体读取。这极大地简化了我们的迭代循环逻辑,因为我们不需要维护一个内部缓冲区来存储我们感兴趣处理的"TrackEntry"标签。
本项目状态
解析和写入完整文件都应正常工作。从版本0.4.0开始,现在也支持流(使用未知大小的标签)。如果有什么问题,请创建一个问题。
任何额外的功能请求也可以作为一个问题提交。
作者
依赖项
~2.5MB
~52K SLoC