openigtlink_rust/protocol/types/
videometa.rs1use crate::protocol::message::Message;
7use crate::error::{IgtlError, Result};
8use bytes::{Buf, BufMut};
9
10use super::video::CodecType;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub struct VideoMetaMessage {
20 pub codec: CodecType,
22 pub width: u16,
24 pub height: u16,
26 pub framerate: u8,
28 pub bitrate: u32,
30}
31
32impl VideoMetaMessage {
33 pub fn new(
35 codec: CodecType,
36 width: u16,
37 height: u16,
38 framerate: u8,
39 bitrate: u32,
40 ) -> Self {
41 VideoMetaMessage {
42 codec,
43 width,
44 height,
45 framerate,
46 bitrate,
47 }
48 }
49
50 pub fn hd1080(codec: CodecType, framerate: u8, bitrate: u32) -> Self {
52 VideoMetaMessage {
53 codec,
54 width: 1920,
55 height: 1080,
56 framerate,
57 bitrate,
58 }
59 }
60
61 pub fn hd720(codec: CodecType, framerate: u8, bitrate: u32) -> Self {
63 VideoMetaMessage {
64 codec,
65 width: 1280,
66 height: 720,
67 framerate,
68 bitrate,
69 }
70 }
71
72 pub fn sd(codec: CodecType, framerate: u8, bitrate: u32) -> Self {
74 VideoMetaMessage {
75 codec,
76 width: 640,
77 height: 480,
78 framerate,
79 bitrate,
80 }
81 }
82
83 pub fn pixels_per_frame(&self) -> u32 {
85 self.width as u32 * self.height as u32
86 }
87
88 pub fn bandwidth_bps(&self) -> u32 {
90 self.bitrate * 1000 / 8 }
92}
93
94impl Message for VideoMetaMessage {
95 fn message_type() -> &'static str {
96 "VIDEOMETA"
97 }
98
99 fn encode_content(&self) -> Result<Vec<u8>> {
100 let mut buf = Vec::with_capacity(12);
101
102 buf.put_u8(self.codec as u8);
104
105 buf.put_u16(self.width);
107
108 buf.put_u16(self.height);
110
111 buf.put_u8(self.framerate);
113
114 buf.put_u32(self.bitrate);
116
117 buf.put_u16(0);
119
120 Ok(buf)
121 }
122
123 fn decode_content(mut data: &[u8]) -> Result<Self> {
124 if data.len() != 12 {
125 return Err(IgtlError::InvalidSize {
126 expected: 12,
127 actual: data.len(),
128 });
129 }
130
131 let codec = CodecType::from_u8(data.get_u8())?;
133
134 let width = data.get_u16();
136
137 let height = data.get_u16();
139
140 let framerate = data.get_u8();
142
143 let bitrate = data.get_u32();
145
146 let _reserved = data.get_u16();
148
149 Ok(VideoMetaMessage {
150 codec,
151 width,
152 height,
153 framerate,
154 bitrate,
155 })
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162
163 #[test]
164 fn test_message_type() {
165 assert_eq!(VideoMetaMessage::message_type(), "VIDEOMETA");
166 }
167
168 #[test]
169 fn test_new() {
170 let meta = VideoMetaMessage::new(CodecType::H264, 1920, 1080, 30, 5000);
171
172 assert_eq!(meta.codec, CodecType::H264);
173 assert_eq!(meta.width, 1920);
174 assert_eq!(meta.height, 1080);
175 assert_eq!(meta.framerate, 30);
176 assert_eq!(meta.bitrate, 5000);
177 }
178
179 #[test]
180 fn test_hd1080() {
181 let meta = VideoMetaMessage::hd1080(CodecType::H264, 60, 10000);
182
183 assert_eq!(meta.width, 1920);
184 assert_eq!(meta.height, 1080);
185 assert_eq!(meta.framerate, 60);
186 }
187
188 #[test]
189 fn test_hd720() {
190 let meta = VideoMetaMessage::hd720(CodecType::VP9, 30, 3000);
191
192 assert_eq!(meta.width, 1280);
193 assert_eq!(meta.height, 720);
194 }
195
196 #[test]
197 fn test_sd() {
198 let meta = VideoMetaMessage::sd(CodecType::MJPEG, 25, 1000);
199
200 assert_eq!(meta.width, 640);
201 assert_eq!(meta.height, 480);
202 }
203
204 #[test]
205 fn test_pixels_per_frame() {
206 let meta = VideoMetaMessage::new(CodecType::H264, 100, 100, 30, 1000);
207 assert_eq!(meta.pixels_per_frame(), 10000);
208 }
209
210 #[test]
211 fn test_bandwidth_bps() {
212 let meta = VideoMetaMessage::new(CodecType::H264, 1920, 1080, 30, 8000);
213 assert_eq!(meta.bandwidth_bps(), 1000000);
215 }
216
217 #[test]
218 fn test_encode() {
219 let meta = VideoMetaMessage::new(CodecType::H264, 1920, 1080, 30, 5000);
220 let encoded = meta.encode_content().unwrap();
221
222 assert_eq!(encoded.len(), 12);
223 assert_eq!(encoded[0], CodecType::H264 as u8);
224 }
225
226 #[test]
227 fn test_roundtrip() {
228 let original = VideoMetaMessage::new(CodecType::H264, 1920, 1080, 30, 5000);
229
230 let encoded = original.encode_content().unwrap();
231 let decoded = VideoMetaMessage::decode_content(&encoded).unwrap();
232
233 assert_eq!(decoded.codec, original.codec);
234 assert_eq!(decoded.width, original.width);
235 assert_eq!(decoded.height, original.height);
236 assert_eq!(decoded.framerate, original.framerate);
237 assert_eq!(decoded.bitrate, original.bitrate);
238 }
239
240 #[test]
241 fn test_roundtrip_vp9() {
242 let original = VideoMetaMessage::hd720(CodecType::VP9, 60, 4000);
243
244 let encoded = original.encode_content().unwrap();
245 let decoded = VideoMetaMessage::decode_content(&encoded).unwrap();
246
247 assert_eq!(decoded.codec, CodecType::VP9);
248 assert_eq!(decoded.width, 1280);
249 assert_eq!(decoded.height, 720);
250 assert_eq!(decoded.framerate, 60);
251 }
252
253 #[test]
254 fn test_decode_invalid_size() {
255 let data = vec![0u8; 11]; let result = VideoMetaMessage::decode_content(&data);
257 assert!(result.is_err());
258 }
259
260 #[test]
261 fn test_decode_too_long() {
262 let data = vec![0u8; 13]; let result = VideoMetaMessage::decode_content(&data);
264 assert!(result.is_err());
265 }
266
267 #[test]
268 fn test_decode_invalid_codec() {
269 let mut data = vec![0u8; 12];
270 data[0] = 99; let result = VideoMetaMessage::decode_content(&data);
272 assert!(result.is_err());
273 }
274}