use alloc::vec::Vec;
use crate::bytes::{BytesReader, BytesWriter};
use crate::rtmp_timestamp::{RtmpTimestamp, RtmpTimestampDelta};
use crate::{
AudioFormat, AudioFrame, AudioSampleRate, AvcPacketType, Error, VideoCodec, VideoFrame,
VideoFrameType,
};
pub fn encode_audio_frame(buf: &mut Vec<u8>, frame: &AudioFrame) {
let header = ((frame.format as u8) << 4)
| ((frame.sample_rate as u8) << 2)
| ((frame.is_8bit_sample as u8) << 1)
| (frame.is_stereo as u8);
buf.write_u8(header);
if frame.format == AudioFormat::Aac {
buf.write_u8(if frame.is_aac_sequence_header { 0 } else { 1 });
}
buf.write_bytes(&frame.data);
}
pub fn decode_audio_frame(buf: &[u8], timestamp: RtmpTimestamp) -> Result<AudioFrame, Error> {
let mut reader = buf;
let header = reader.read_u8()?;
let format_bits = (header >> 4) & 0x0F;
let format = match format_bits {
1 => AudioFormat::Adpcm,
2 => AudioFormat::Mp3,
3 => AudioFormat::LinearPcmLittleEndian,
4 => AudioFormat::Nellymoser16khzMono,
5 => AudioFormat::Nellymoser8KhzMono,
6 => AudioFormat::Nellymoser,
7 => AudioFormat::G711AlawLogarithmicPcm,
8 => AudioFormat::G711MuLawLogarithmicPcm,
10 => AudioFormat::Aac,
11 => AudioFormat::Speex,
14 => AudioFormat::Mp3_8khz,
15 => AudioFormat::DeviceSpecificSound,
_ => {
return Err(Error::invalid_data(format!(
"Invalid audio format: {}",
format_bits
)));
}
};
let sample_rate_bits = (header >> 2) & 0x03;
let sample_rate = match sample_rate_bits {
0 => AudioSampleRate::Khz5,
1 => AudioSampleRate::Khz11,
2 => AudioSampleRate::Khz22,
3 => AudioSampleRate::Khz44,
_ => unreachable!(),
};
let is_8bit_sample = (header & 0x02) != 0;
let is_stereo = (header & 0x01) != 0;
let is_aac_sequence_header = if format == AudioFormat::Aac {
let aac_packet_type = reader.read_u8()?;
aac_packet_type == 0 } else {
false
};
let data = reader.to_vec();
Ok(AudioFrame {
timestamp,
format,
sample_rate,
is_8bit_sample,
is_stereo,
is_aac_sequence_header,
data,
})
}
pub fn encode_video_frame(buf: &mut Vec<u8>, frame: &VideoFrame) {
let frame_type_codec = ((frame.frame_type as u8) << 4) | (frame.codec as u8);
buf.write_u8(frame_type_codec);
if let Some(avc_packet_type) = frame.avc_packet_type {
buf.write_u8(avc_packet_type as u8);
buf.write_i24(frame.composition_timestamp_offset.as_millis());
}
buf.write_bytes(&frame.data);
}
pub fn decode_video_frame(buf: &[u8], timestamp: RtmpTimestamp) -> Result<VideoFrame, Error> {
let mut reader = buf;
let frame_type_codec = reader.read_u8()?;
let frame_type_bits = (frame_type_codec >> 4) & 0x0F;
let frame_type = match frame_type_bits {
1 => VideoFrameType::KeyFrame,
2 => VideoFrameType::InterFrame,
3 => VideoFrameType::DisposableInterFrame,
4 => VideoFrameType::GeneratedKeyFrame,
5 => VideoFrameType::VideoInfoOrCommandFrame,
_ => {
return Err(Error::invalid_data(format!(
"Invalid video frame type: {}",
frame_type_bits
)));
}
};
let codec_bits = frame_type_codec & 0x0F;
let codec = match codec_bits {
1 => VideoCodec::Jpeg,
2 => VideoCodec::H263,
3 => VideoCodec::ScreenVideo,
4 => VideoCodec::Vp6,
5 => VideoCodec::Vp6WithAlpha,
6 => VideoCodec::ScreenVideoV2,
7 => VideoCodec::Avc,
_ => {
return Err(Error::invalid_data(format!(
"Invalid video codec: {}",
codec_bits
)));
}
};
let (avc_packet_type, composition_timestamp_offset) =
if codec == VideoCodec::Avc && frame_type != VideoFrameType::VideoInfoOrCommandFrame {
let avc_packet_type_byte = reader.read_u8()?;
let avc_packet_type = match avc_packet_type_byte {
0 => AvcPacketType::SequenceHeader,
1 => AvcPacketType::NalUnit,
2 => AvcPacketType::EndOfSequence,
_ => {
return Err(Error::invalid_data(format!(
"Invalid AVC packet type: {}",
avc_packet_type_byte
)));
}
};
let composition_timestamp_offset = RtmpTimestampDelta::from_millis(reader.read_i24()?);
(Some(avc_packet_type), composition_timestamp_offset)
} else {
(None, RtmpTimestampDelta::ZERO)
};
let data = reader.to_vec();
Ok(VideoFrame {
timestamp,
composition_timestamp_offset,
frame_type,
codec,
avc_packet_type,
data,
})
}