use crate::flv::flv_tag_body;
use crate::flv::flv_tag_header::FlvTagHeader;
use crate::flv::{FLV_TAG_HEADER_LENGTH, PREVIOUS_TAG_SIZE_LENGTH};
#[derive(Debug, Clone)]
pub struct FlvTag {
pub header: FlvTagHeader,
pub data: bytes::Bytes, pub previous_tag_size: u32, }
impl FlvTag {
pub fn as_bytes_with_previous_tag_size(&self) -> Vec<u8> {
let mut bytes =
Vec::with_capacity(FLV_TAG_HEADER_LENGTH + self.data.len() + PREVIOUS_TAG_SIZE_LENGTH);
bytes.extend_from_slice(&self.header.as_bytes());
bytes.extend_from_slice(&self.data);
bytes.extend_from_slice(&self.previous_tag_size.to_be_bytes());
bytes
}
pub fn is_audio(&self) -> bool {
self.header.is_audio()
}
pub fn is_video(&self) -> bool {
self.header.is_video()
}
pub fn is_script_data(&self) -> bool {
self.header.is_script_data()
}
pub fn is_video_sequence_header(&self) -> bool {
self.is_video() && flv_tag_body::is_video_sequence_header(&self.data)
}
pub fn is_audio_sequence_header(&self) -> bool {
self.is_audio() && flv_tag_body::is_audio_sequence_header(&self.data)
}
pub fn is_video_keyframe(&self) -> bool {
self.is_video() && flv_tag_body::is_video_keyframe(&self.data)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn tag(tag_type: u8, data: &'static [u8]) -> FlvTag {
FlvTag {
header: FlvTagHeader {
tag_type,
data_size: data.len() as u32,
timestamp: 0,
timestamp_ext: 0,
stream_id: 0,
},
data: bytes::Bytes::from_static(data),
previous_tag_size: 0,
}
}
#[test]
fn classification_is_gated_on_tag_type() {
assert!(tag(0x09, &[0x17, 0x00]).is_video_sequence_header());
assert!(!tag(0x08, &[0x17, 0x00]).is_video_sequence_header());
assert!(tag(0x08, &[0xaf, 0x00]).is_audio_sequence_header());
assert!(!tag(0x09, &[0xaf, 0x00]).is_audio_sequence_header());
}
#[test]
fn video_keyframe_excludes_config_and_end_of_sequence() {
assert!(tag(0x09, &[0x17, 0x01]).is_video_keyframe());
assert!(!tag(0x09, &[0x17, 0x00]).is_video_keyframe());
assert!(!tag(0x09, &[0x17, 0x02]).is_video_keyframe());
}
}