Skip to content

Commit e8feb77

Browse files
committed
add EnhancedVideoBody
1 parent 2fd8445 commit e8feb77

File tree

2 files changed

+31
-25
lines changed

2 files changed

+31
-25
lines changed

rtmp/src/flv/video.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,12 @@ impl VideoTagH264PacketType {
114114
}
115115
}
116116

117-
/// Parses SI24 composition time from 3 bytes.
117+
/// Parses SI24 (signed 24-bit integer) composition time from 3 bytes.
118+
/// Negative values occur with B-frames where PTS < DTS.
118119
pub(super) fn parse_composition_time(bytes: &[u8]) -> i32 {
119-
i32::from_be_bytes([0, bytes[0], bytes[1], bytes[2]])
120+
// bytes are placed at the top of i32 so that the SI24 sign bit aligns
121+
// with the i32 sign bit, arithmetic right-shift then propagates it
122+
i32::from_be_bytes([bytes[0], bytes[1], bytes[2], 0]) >> 8
120123
}
121124

122125
/// Serializes SI24 composition time to 3 bytes.

rtmp/src/flv/video_enhanced.rs

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,6 @@ const EX_HEADER_BIT: u8 = 0b10000000;
1414
pub enum FlvVideoData {
1515
Legacy(VideoTag),
1616
Enhanced(EnhancedVideoTag),
17-
/// Enhanced RTMP command frame (e.g. seek start/end).
18-
/// Sent when `VideoFrameType == Command` and packet type is not Metadata.
19-
/// Per the spec, the payload is a single UI8 command byte with no video body.
20-
EnhancedCommand {
21-
command: VideoCommand,
22-
timestamp_nano_offset: Option<u32>,
23-
},
2417
}
2518

2619
/// Video command signals for Enhanced RTMP.
@@ -50,9 +43,21 @@ impl VideoCommand {
5043
#[derive(Debug, Clone)]
5144
pub struct EnhancedVideoTag {
5245
pub frame_type: VideoTagFrameType,
53-
pub four_cc: VideoFourCc,
5446
pub timestamp_nano_offset: Option<u32>,
55-
pub packet_type: VideoPacketType,
47+
pub body: EnhancedVideoBody,
48+
}
49+
50+
/// The body of an Enhanced RTMP video tag.
51+
///
52+
/// Command frames (gated by `VideoFrameType == Command`) have no FourCC or
53+
/// video body. All other cases carry a FourCC and a `VideoPacketType`.
54+
#[derive(Debug, Clone)]
55+
pub enum EnhancedVideoBody {
56+
Command(VideoCommand),
57+
Packet {
58+
four_cc: VideoFourCc,
59+
packet_type: VideoPacketType,
60+
},
5661
}
5762

5863
/// Semantic video packet type after parsing.
@@ -196,7 +201,7 @@ impl FlvVideoData {
196201
}
197202

198203
if data[0] & EX_HEADER_BIT != 0 {
199-
EnhancedVideoTag::parse(data)
204+
EnhancedVideoTag::parse(data).map(FlvVideoData::Enhanced)
200205
} else {
201206
VideoTag::parse(data).map(FlvVideoData::Legacy)
202207
}
@@ -206,17 +211,14 @@ impl FlvVideoData {
206211
match self {
207212
FlvVideoData::Legacy(tag) => tag.serialize(),
208213
FlvVideoData::Enhanced(tag) => tag.serialize(),
209-
FlvVideoData::EnhancedCommand { .. } => {
210-
unimplemented!()
211-
}
212214
}
213215
}
214216
}
215217

216218
impl EnhancedVideoTag {
217219
/// Parses Enhanced RTMP video tag.
218220
/// First byte: `[isExHeader(1) | VideoFrameType(3 bits) | RawVideoPacketType(4 bits)]`
219-
fn parse(data: Bytes) -> Result<FlvVideoData, FlvVideoTagParseError> {
221+
fn parse(data: Bytes) -> Result<Self, FlvVideoTagParseError> {
220222
if data.is_empty() {
221223
return Err(FlvVideoTagParseError::TooShort);
222224
}
@@ -233,17 +235,18 @@ impl EnhancedVideoTag {
233235
};
234236

235237
// Per spec: if frame_type is Command and packet_type is not Metadata,
236-
// the payload is a single UI8 VideoCommand with no video body.
238+
// the payload is a single UI8 VideoCommand with no FourCC or video body.
237239
if frame_type == VideoTagFrameType::VideoInfoOrCommandFrame
238240
&& raw_packet_type != RawVideoPacketType::Metadata
239241
{
240242
if rest.is_empty() {
241243
return Err(FlvVideoTagParseError::TooShort);
242244
}
243245
let command = VideoCommand::from_raw(rest[0])?;
244-
return Ok(FlvVideoData::EnhancedCommand {
245-
command,
246+
return Ok(EnhancedVideoTag {
247+
frame_type,
246248
timestamp_nano_offset,
249+
body: EnhancedVideoBody::Command(command),
247250
});
248251
}
249252

@@ -277,12 +280,14 @@ impl EnhancedVideoTag {
277280
}
278281
};
279282

280-
Ok(FlvVideoData::Enhanced(EnhancedVideoTag {
283+
Ok(EnhancedVideoTag {
281284
frame_type,
282-
four_cc,
283285
timestamp_nano_offset,
284-
packet_type,
285-
}))
286+
body: EnhancedVideoBody::Packet {
287+
four_cc,
288+
packet_type,
289+
},
290+
})
286291
}
287292

288293
/// Parses CodedFrames body: optional SI24 composition time (3 bytes) + payload.
@@ -330,7 +335,6 @@ impl EnhancedVideoTag {
330335
let mut mod_ex_data_size = data[offset] as usize + 1;
331336
offset += 1;
332337

333-
// If size == 256, use UI16 + 1 instead
334338
if mod_ex_data_size == 256 {
335339
if data.len() < offset + 2 {
336340
return Err(FlvVideoTagParseError::TooShort);
@@ -369,7 +373,6 @@ impl EnhancedVideoTag {
369373
}
370374
}
371375

372-
// If another ModEx, continue the loop; otherwise return resolved state.
373376
if next_packet_type != RawVideoPacketType::ModEx {
374377
return Ok((
375378
next_packet_type,

0 commit comments

Comments
 (0)