Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ default = ["std"]
std = ["nom/std"]

[dependencies]
nom = { version = "6.1", default-features = false, features = ["alloc"] }
nom = { version = "8", default-features = false, features = ["alloc"] }
3 changes: 0 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
#[cfg(not(feature = "std"))]
extern crate alloc;

#[macro_use]
extern crate nom;

mod parse;

pub use nom::{
Expand Down
109 changes: 53 additions & 56 deletions src/parse/audio.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use nom::{Err as NomErr, IResult, Needed, number::streaming::be_u8};
use nom::{
Err as NomErr, IResult, Needed,
error::{Error, ErrorKind},
number::streaming::be_u8,
};

/// The tag data part of `audio` FLV tag, including `tag data header` and `tag data body`.
#[derive(Clone, Debug, PartialEq)]
Expand All @@ -12,15 +16,9 @@ pub struct AudioTag<'a> {
impl<'a> AudioTag<'a> {
/// Parse audio tag data.
pub fn parse(input: &'a [u8], size: usize) -> IResult<&'a [u8], AudioTag<'a>> {
do_parse!(
input,
// parse audio tag header
header: call!(AudioTagHeader::parse, size) >>
// parse audio tag body
body: call!(AudioTagBody::parse, size - 1) >>

(AudioTag { header, body })
)
let (input, header) = AudioTagHeader::parse(input, size)?;
let (input, body) = AudioTagBody::parse(input, size.saturating_sub(1))?;
Ok((input, AudioTag { header, body }))
}
}

Expand Down Expand Up @@ -109,45 +107,45 @@ impl AudioTagHeader {
return Err(NomErr::Incomplete(Needed::new(1)));
}

let (remain, (sound_format, sound_rate, sound_size, sound_type)) = try_parse!(
input,
bits!(tuple!(
// parse sound format
switch!(take_bits!(4u8),
0 => value!(SoundFormat::PcmPlatformEndian) |
1 => value!(SoundFormat::ADPCM) |
2 => value!(SoundFormat::MP3) |
3 => value!(SoundFormat::PcmLittleEndian) |
4 => value!(SoundFormat::Nellymoser16kHzMono) |
5 => value!(SoundFormat::Nellymoser8kHzMono) |
6 => value!(SoundFormat::Nellymoser) |
7 => value!(SoundFormat::PcmALaw) |
8 => value!(SoundFormat::PcmMuLaw) |
9 => value!(SoundFormat::Reserved) |
10 => value!(SoundFormat::AAC) |
11 => value!(SoundFormat::Speex) |
14 => value!(SoundFormat::MP3_8kHz) |
15 => value!(SoundFormat::DeviceSpecific)
),
// parse sound rate
switch!(take_bits!(2u8),
0 => value!(SoundRate::_5_5KHZ) |
1 => value!(SoundRate::_11KHZ) |
2 => value!(SoundRate::_22KHZ) |
3 => value!(SoundRate::_44KHZ)
),
// parse sound sample size
switch!(take_bits!(1u8),
0 => value!(SoundSize::_8Bit) |
1 => value!(SoundSize::_16Bit)
),
// parse sound type
switch!(take_bits!(1u8),
0 => value!(SoundType::Mono) |
1 => value!(SoundType::Stereo)
)
))
);
let (remain, byte) = be_u8(input)?;

let sound_format = match byte >> 4 {
0 => SoundFormat::PcmPlatformEndian,
1 => SoundFormat::ADPCM,
2 => SoundFormat::MP3,
3 => SoundFormat::PcmLittleEndian,
4 => SoundFormat::Nellymoser16kHzMono,
5 => SoundFormat::Nellymoser8kHzMono,
6 => SoundFormat::Nellymoser,
7 => SoundFormat::PcmALaw,
8 => SoundFormat::PcmMuLaw,
9 => SoundFormat::Reserved,
10 => SoundFormat::AAC,
11 => SoundFormat::Speex,
14 => SoundFormat::MP3_8kHz,
15 => SoundFormat::DeviceSpecific,
_ => SoundFormat::Reserved,
};

let sound_rate = match (byte >> 2) & 0b11 {
0 => SoundRate::_5_5KHZ,
1 => SoundRate::_11KHZ,
2 => SoundRate::_22KHZ,
3 => SoundRate::_44KHZ,
_ => SoundRate::_5_5KHZ,
};

let sound_size = match (byte >> 1) & 0b1 {
0 => SoundSize::_8Bit,
1 => SoundSize::_16Bit,
_ => SoundSize::_8Bit,
};

let sound_type = match byte & 0b1 {
0 => SoundType::Mono,
1 => SoundType::Stereo,
_ => SoundType::Mono,
};

Ok((remain, AudioTagHeader { sound_format, sound_rate, sound_size, sound_type }))
}
Expand Down Expand Up @@ -199,13 +197,12 @@ pub fn aac_audio_packet(input: &[u8], size: usize) -> IResult<&[u8], AACAudioPac
return Err(NomErr::Incomplete(Needed::new(1)));
}

let (_, packet_type) = try_parse!(
input,
switch!(be_u8,
0 => value!(AACPacketType::SequenceHeader) |
1 => value!(AACPacketType::Raw)
)
);
let (remain, packet_type_byte) = be_u8(input)?;
let packet_type = match packet_type_byte {
0 => AACPacketType::SequenceHeader,
1 => AACPacketType::Raw,
_ => return Err(NomErr::Error(Error::new(remain, ErrorKind::Switch))),
};

Ok((&input[size..], AACAudioPacket { packet_type, aac_data: &input[1..size] }))
}
121 changes: 58 additions & 63 deletions src/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,24 @@ mod video;
use alloc::vec::Vec;

use nom::{
IResult,
number::streaming::{be_u8, be_u24, be_u32},
Err as NomErr, IResult, Parser,
bytes::streaming::{tag, take},
combinator::complete,
error::{Error, ErrorKind},
multi::many0,
number::streaming::{be_u8, be_u32},
};

pub use self::{audio::*, script::*, video::*};

const FLV_HEADER_SIGNATURE: [u8; 3] = [0x46, 0x4c, 0x56];

fn be_u24(input: &[u8]) -> IResult<&[u8], u32> {
let (input, bytes) = take(3usize)(input)?;
let value = (u32::from(bytes[0]) << 16) | (u32::from(bytes[1]) << 8) | u32::from(bytes[2]);
Ok((input, value))
}

/// The FLV file structure, including header and body.
#[derive(Clone, Debug, PartialEq)]
pub struct FlvFile<'a> {
Expand All @@ -29,15 +39,9 @@ pub struct FlvFile<'a> {
impl<'a> FlvFile<'a> {
/// Parse FLV file.
pub fn parse(input: &'a [u8]) -> IResult<&'a [u8], FlvFile<'a>> {
do_parse!(
input,
// parse file header
header: call!(FlvFileHeader::parse) >>
// parse file body
body: call!(FlvFileBody::parse) >>

(FlvFile { header, body })
)
let (input, header) = FlvFileHeader::parse(input)?;
let (input, body) = FlvFileBody::parse(input)?;
Ok((input, FlvFile { header, body }))
}
}

Expand All @@ -64,26 +68,22 @@ pub struct FlvFileHeader {
impl FlvFileHeader {
/// Parse FLV file header.
pub fn parse(input: &[u8]) -> IResult<&[u8], FlvFileHeader> {
do_parse!(
let (input, _) = tag(FLV_HEADER_SIGNATURE.as_slice())(input)?;
let (input, version) = be_u8(input)?;
let (input, flags) = be_u8(input)?;
let (input, data_offset) = be_u32(input)?;

Ok((
input,
// FLV Signature
tag!(FLV_HEADER_SIGNATURE) >>
// FLV File Version
version: be_u8 >>
// Flags the presents whether `audio` tags or `video` tags are exist.
flags: be_u8 >>
// The length of this header in bytes
data_offset: be_u32 >>

(FlvFileHeader {
FlvFileHeader {
signature: FLV_HEADER_SIGNATURE,
version,
flags,
has_audio: flags & 4 == 4,
has_video: flags & 1 == 1,
data_offset,
})
)
},
))
}
}

Expand All @@ -100,15 +100,10 @@ impl<'a> FlvFileBody<'a> {
// https://github.com/Geal/nom/issues/790 - many0 returns Incomplete in weird cases.
/// Parse FLV file body.
pub fn parse(input: &'a [u8]) -> IResult<&'a [u8], FlvFileBody<'a>> {
do_parse!(
input,
// The first previous tag size.
first_previous_tag_size: be_u32 >>
// FLV Tag and the size of the tag.
tags: many0!(complete!(tuple!(call!(FlvTag::parse), be_u32))) >>
let (input, first_previous_tag_size) = be_u32(input)?;
let (input, tags) = many0(complete((|i| FlvTag::parse(i), be_u32))).parse(input)?;

(FlvFileBody { first_previous_tag_size, tags })
)
Ok((input, FlvFileBody { first_previous_tag_size, tags }))
}
}

Expand All @@ -129,15 +124,9 @@ pub struct FlvTag<'a> {
impl<'a> FlvTag<'a> {
/// Parse FLV tag.
pub fn parse(input: &'a [u8]) -> IResult<&'a [u8], FlvTag<'a>> {
do_parse!(
input,
// parse tag header
header: call!(FlvTagHeader::parse) >>
// parse tag data
data: call!(FlvTagData::parse, header.tag_type, header.data_size as usize) >>

(FlvTag { header, data })
)
let (input, header) = FlvTagHeader::parse(input)?;
let (input, data) = FlvTagData::parse(input, header.tag_type, header.data_size as usize)?;
Ok((input, FlvTag { header, data }))
}
}

Expand Down Expand Up @@ -175,30 +164,27 @@ pub enum FlvTagType {
impl FlvTagHeader {
/// Parse FLV tag header.
pub fn parse(input: &[u8]) -> IResult<&[u8], FlvTagHeader> {
do_parse!(
let (input, tag_type_byte) = be_u8(input)?;
let tag_type = match tag_type_byte {
8 => FlvTagType::Audio,
9 => FlvTagType::Video,
18 => FlvTagType::Script,
_ => return Err(NomErr::Error(Error::new(input, ErrorKind::Switch))),
};
let (input, data_size) = be_u24(input)?;
let (input, timestamp) = be_u24(input)?;
let (input, timestamp_extended) = be_u8(input)?;
let (input, stream_id) = be_u24(input)?;

Ok((
input,
// Tag Type
tag_type: switch!(be_u8,
8 => value!(FlvTagType::Audio) |
9 => value!(FlvTagType::Video) |
18 => value!(FlvTagType::Script)
) >>
// The size of the tag's data part
data_size: be_u24 >>
// The timestamp (in milliseconds) of the tag
timestamp: be_u24 >>
// Extension of the timestamp field to form a SI32 value
timestamp_extended: be_u8 >>
// The id of stream
stream_id: be_u24 >>

(FlvTagHeader {
FlvTagHeader {
tag_type,
data_size,
timestamp: (u32::from(timestamp_extended) << 24) + timestamp,
stream_id,
})
)
},
))
}
}

Expand All @@ -221,9 +207,18 @@ impl<'a> FlvTagData<'a> {
size: usize,
) -> IResult<&'a [u8], FlvTagData<'a>> {
match tag_type {
FlvTagType::Audio => map!(input, call!(AudioTag::parse, size), FlvTagData::Audio),
FlvTagType::Video => map!(input, call!(VideoTag::parse, size), FlvTagData::Video),
FlvTagType::Script => map!(input, call!(ScriptTag::parse, size), FlvTagData::Script),
FlvTagType::Audio => {
let (input, tag) = AudioTag::parse(input, size)?;
Ok((input, FlvTagData::Audio(tag)))
},
FlvTagType::Video => {
let (input, tag) = VideoTag::parse(input, size)?;
Ok((input, FlvTagData::Video(tag)))
},
FlvTagType::Script => {
let (input, tag) = ScriptTag::parse(input, size)?;
Ok((input, FlvTagData::Script(tag)))
},
}
}
}
Loading