gstreamer_rtp/
rtp_buffer.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{fmt, marker::PhantomData, mem, ptr, slice};
4
5use crate::ffi;
6use glib::translate::{from_glib, mut_override, FromGlibPtrFull, IntoGlib};
7
8pub enum Readable {}
9pub enum Writable {}
10
11pub struct RTPBuffer<'a, T> {
12    rtp_buffer: ffi::GstRTPBuffer,
13    phantom: PhantomData<&'a T>,
14}
15
16unsafe impl<T> Send for RTPBuffer<'_, T> {}
17unsafe impl<T> Sync for RTPBuffer<'_, T> {}
18
19impl<T> fmt::Debug for RTPBuffer<'_, T> {
20    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21        f.debug_struct("RTPBuffer")
22            .field("rtp_buffer", &self.rtp_buffer)
23            .finish()
24    }
25}
26
27impl<'a> RTPBuffer<'a, Readable> {
28    #[inline]
29    pub fn from_buffer_readable(
30        buffer: &'a gst::BufferRef,
31    ) -> Result<RTPBuffer<'a, Readable>, glib::BoolError> {
32        skip_assert_initialized!();
33        unsafe {
34            let mut rtp_buffer = mem::MaybeUninit::zeroed();
35            let res: bool = from_glib(ffi::gst_rtp_buffer_map(
36                mut_override(buffer.as_ptr()),
37                gst::ffi::GST_MAP_READ,
38                rtp_buffer.as_mut_ptr(),
39            ));
40
41            if res {
42                Ok(RTPBuffer {
43                    rtp_buffer: rtp_buffer.assume_init(),
44                    phantom: PhantomData,
45                })
46            } else {
47                Err(glib::bool_error!("Failed to map RTP buffer readable"))
48            }
49        }
50    }
51
52    #[inline]
53    pub unsafe fn from_glib_borrow<'b>(
54        rtp_buffer: *mut ffi::GstRTPBuffer,
55    ) -> glib::translate::Borrowed<RTPBuffer<'b, Readable>> {
56        glib::translate::Borrowed::new(RTPBuffer {
57            rtp_buffer: *rtp_buffer,
58            phantom: PhantomData,
59        })
60    }
61}
62
63impl<'a> RTPBuffer<'a, Writable> {
64    #[inline]
65    pub fn from_buffer_writable(
66        buffer: &'a mut gst::BufferRef,
67    ) -> Result<RTPBuffer<'a, Writable>, glib::BoolError> {
68        skip_assert_initialized!();
69        unsafe {
70            let mut rtp_buffer = mem::MaybeUninit::zeroed();
71            let res: bool = from_glib(ffi::gst_rtp_buffer_map(
72                buffer.as_mut_ptr(),
73                gst::ffi::GST_MAP_READWRITE,
74                rtp_buffer.as_mut_ptr(),
75            ));
76
77            if res {
78                Ok(RTPBuffer {
79                    rtp_buffer: rtp_buffer.assume_init(),
80                    phantom: PhantomData,
81                })
82            } else {
83                Err(glib::bool_error!("Failed to map RTP buffer writable"))
84            }
85        }
86    }
87
88    #[doc(alias = "gst_rtp_buffer_set_seq")]
89    pub fn set_seq(&mut self, seq: u16) {
90        unsafe {
91            ffi::gst_rtp_buffer_set_seq(&mut self.rtp_buffer, seq);
92        }
93    }
94
95    #[doc(alias = "gst_rtp_buffer_set_marker")]
96    pub fn set_marker(&mut self, m: bool) {
97        unsafe {
98            ffi::gst_rtp_buffer_set_marker(&mut self.rtp_buffer, m.into_glib());
99        }
100    }
101
102    #[doc(alias = "gst_rtp_buffer_set_payload_type")]
103    pub fn set_payload_type(&mut self, pt: u8) {
104        unsafe {
105            ffi::gst_rtp_buffer_set_payload_type(&mut self.rtp_buffer, pt);
106        }
107    }
108
109    #[doc(alias = "gst_rtp_buffer_set_ssrc")]
110    pub fn set_ssrc(&mut self, ssrc: u32) {
111        unsafe { ffi::gst_rtp_buffer_set_ssrc(&mut self.rtp_buffer, ssrc) }
112    }
113
114    #[doc(alias = "gst_rtp_buffer_set_csrc")]
115    pub fn set_csrc(&mut self, idx: u8, ssrc: u32) {
116        unsafe { ffi::gst_rtp_buffer_set_csrc(&mut self.rtp_buffer, idx, ssrc) }
117    }
118
119    #[doc(alias = "gst_rtp_buffer_set_timestamp")]
120    pub fn set_timestamp(&mut self, rtptime: u32) {
121        unsafe {
122            ffi::gst_rtp_buffer_set_timestamp(&mut self.rtp_buffer, rtptime);
123        }
124    }
125
126    #[doc(alias = "gst_rtp_buffer_set_extension")]
127    pub fn set_extension(&mut self, extension: bool) {
128        unsafe { ffi::gst_rtp_buffer_set_extension(&mut self.rtp_buffer, extension.into_glib()) }
129    }
130
131    #[doc(alias = "gst_rtp_buffer_add_extension_onebyte_header")]
132    #[allow(clippy::manual_range_contains)]
133    pub fn add_extension_onebyte_header(
134        &mut self,
135        id: u8,
136        data: &[u8],
137    ) -> Result<(), glib::BoolError> {
138        assert!(
139            id >= 1 && id <= 14,
140            "id should be between 1 and 14 (inclusive)"
141        );
142        assert!(
143            !data.is_empty() && data.len() <= 16,
144            "data size should be between 1 and 16 (inclusive"
145        );
146        unsafe {
147            let result: bool = from_glib(ffi::gst_rtp_buffer_add_extension_onebyte_header(
148                &mut self.rtp_buffer,
149                id,
150                data.as_ptr() as glib::ffi::gconstpointer,
151                data.len() as u32,
152            ));
153            if result {
154                Ok(())
155            } else {
156                Err(glib::bool_error!("Failed to add onebyte header extension"))
157            }
158        }
159    }
160
161    #[doc(alias = "gst_rtp_buffer_add_extension_twobytes_header")]
162    pub fn add_extension_twobytes_header(
163        &mut self,
164        appbits: u8,
165        id: u8,
166        data: &[u8],
167    ) -> Result<(), glib::BoolError> {
168        assert_eq!(
169            appbits & 0xF0,
170            0,
171            "appbits must use only 4 bits (max value is 15)"
172        );
173        assert!(data.len() < 256, "data size should be smaller than 256");
174        unsafe {
175            let result: bool = from_glib(ffi::gst_rtp_buffer_add_extension_twobytes_header(
176                &mut self.rtp_buffer,
177                appbits,
178                id,
179                data.as_ptr() as glib::ffi::gconstpointer,
180                data.len() as u32,
181            ));
182            if result {
183                Ok(())
184            } else {
185                Err(glib::bool_error!("Failed to add twobytes header extension"))
186            }
187        }
188    }
189
190    #[cfg(feature = "v1_20")]
191    #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
192    #[doc(alias = "gst_rtp_buffer_remove_extension_data")]
193    pub fn remove_extension_data(&mut self) {
194        unsafe {
195            ffi::gst_rtp_buffer_remove_extension_data(&mut self.rtp_buffer);
196        }
197    }
198
199    #[doc(alias = "gst_rtp_buffer_set_padding")]
200    pub fn set_padding(&mut self, padding: bool) {
201        unsafe { ffi::gst_rtp_buffer_set_padding(&mut self.rtp_buffer, padding.into_glib()) }
202    }
203}
204
205impl<T> RTPBuffer<'_, T> {
206    #[doc(alias = "get_seq")]
207    #[doc(alias = "gst_rtp_buffer_get_seq")]
208    pub fn seq(&self) -> u16 {
209        unsafe { ffi::gst_rtp_buffer_get_seq(glib::translate::mut_override(&self.rtp_buffer)) }
210    }
211
212    #[doc(alias = "get_payload_type")]
213    #[doc(alias = "gst_rtp_buffer_get_payload_type")]
214    pub fn payload_type(&self) -> u8 {
215        unsafe {
216            ffi::gst_rtp_buffer_get_payload_type(glib::translate::mut_override(&self.rtp_buffer))
217        }
218    }
219
220    #[doc(alias = "get_ssrc")]
221    #[doc(alias = "gst_rtp_buffer_get_ssrc")]
222    pub fn ssrc(&self) -> u32 {
223        unsafe { ffi::gst_rtp_buffer_get_ssrc(glib::translate::mut_override(&self.rtp_buffer)) }
224    }
225
226    #[doc(alias = "get_timestamp")]
227    #[doc(alias = "gst_rtp_buffer_get_timestamp")]
228    pub fn timestamp(&self) -> u32 {
229        unsafe {
230            ffi::gst_rtp_buffer_get_timestamp(glib::translate::mut_override(&self.rtp_buffer))
231        }
232    }
233
234    #[doc(alias = "get_csrc")]
235    #[doc(alias = "gst_rtp_buffer_get_csrc")]
236    pub fn csrc(&self, idx: u8) -> Option<u32> {
237        if idx < self.csrc_count() {
238            unsafe {
239                Some(ffi::gst_rtp_buffer_get_csrc(
240                    glib::translate::mut_override(&self.rtp_buffer),
241                    idx,
242                ))
243            }
244        } else {
245            None
246        }
247    }
248
249    #[doc(alias = "get_csrc_count")]
250    #[doc(alias = "gst_rtp_buffer_get_csrc_count")]
251    pub fn csrc_count(&self) -> u8 {
252        unsafe {
253            ffi::gst_rtp_buffer_get_csrc_count(glib::translate::mut_override(&self.rtp_buffer))
254        }
255    }
256
257    #[doc(alias = "get_marker")]
258    pub fn is_marker(&self) -> bool {
259        unsafe {
260            from_glib(ffi::gst_rtp_buffer_get_marker(
261                glib::translate::mut_override(&self.rtp_buffer),
262            ))
263        }
264    }
265
266    #[doc(alias = "get_payload_size")]
267    pub fn payload_size(&self) -> u32 {
268        unsafe {
269            ffi::gst_rtp_buffer_get_payload_len(glib::translate::mut_override(&self.rtp_buffer))
270        }
271    }
272
273    #[doc(alias = "get_payload")]
274    #[doc(alias = "gst_rtp_buffer_get_payload")]
275    pub fn payload(&self) -> Result<&[u8], glib::error::BoolError> {
276        let size = self.payload_size();
277        if size == 0 {
278            return Ok(&[]);
279        }
280        unsafe {
281            let pointer =
282                ffi::gst_rtp_buffer_get_payload(glib::translate::mut_override(&self.rtp_buffer));
283            if pointer.is_null() {
284                Err(glib::bool_error!("Failed to get payload data"))
285            } else {
286                Ok(slice::from_raw_parts(pointer as *const u8, size as usize))
287            }
288        }
289    }
290
291    #[doc(alias = "get_payload")]
292    #[doc(alias = "gst_rtp_buffer_get_payload")]
293    pub fn payload_mut(&mut self) -> Result<&mut [u8], glib::error::BoolError> {
294        let size = self.payload_size();
295        if size == 0 {
296            return Ok(&mut []);
297        }
298        unsafe {
299            let pointer = ffi::gst_rtp_buffer_get_payload(&mut self.rtp_buffer);
300            if pointer.is_null() {
301                Err(glib::bool_error!("Failed to get payload data"))
302            } else {
303                Ok(slice::from_raw_parts_mut(pointer as *mut u8, size as usize))
304            }
305        }
306    }
307
308    #[doc(alias = "get_payload_buffer")]
309    #[doc(alias = "gst_rtp_buffer_get_payload_buffer")]
310    pub fn payload_buffer(&self) -> Result<gst::Buffer, glib::BoolError> {
311        unsafe {
312            Option::<_>::from_glib_full(ffi::gst_rtp_buffer_get_payload_buffer(
313                glib::translate::mut_override(&self.rtp_buffer),
314            ))
315            .ok_or_else(|| glib::bool_error!("Failed to get payload buffer"))
316        }
317    }
318
319    #[inline]
320    pub fn buffer(&self) -> &gst::BufferRef {
321        unsafe {
322            let ptr = self.rtp_buffer.buffer;
323
324            debug_assert!(!ptr.is_null());
325
326            gst::BufferRef::from_ptr(ptr)
327        }
328    }
329
330    #[doc(alias = "get_extension")]
331    pub fn is_extension(&self) -> bool {
332        unsafe {
333            from_glib(ffi::gst_rtp_buffer_get_extension(
334                glib::translate::mut_override(&self.rtp_buffer),
335            ))
336        }
337    }
338
339    #[doc(alias = "get_extension_bytes")]
340    #[doc(alias = "gst_rtp_buffer_get_extension_bytes")]
341    pub fn extension_bytes(&self) -> Option<(u16, glib::Bytes)> {
342        unsafe {
343            let mut bits: u16 = 0;
344            Option::<glib::Bytes>::from_glib_full(ffi::gst_rtp_buffer_get_extension_bytes(
345                glib::translate::mut_override(&self.rtp_buffer),
346                &mut bits,
347            ))
348            .map(|bytes| (bits, bytes))
349        }
350    }
351
352    #[doc(alias = "get_extension_onebyte_header")]
353    #[doc(alias = "gst_rtp_buffer_get_extension_onebyte_header")]
354    pub fn extension_onebyte_header(&self, id: u8, nth: u32) -> Option<&[u8]> {
355        unsafe {
356            let mut data = ptr::null_mut();
357            // FIXME: Workaround for gstreamer-rtp-sys having the wrong type for this parameter
358            let data_ptr = &mut data as *mut *mut u8 as *mut u8;
359            let mut size: u32 = 0;
360            let result: bool = from_glib(ffi::gst_rtp_buffer_get_extension_onebyte_header(
361                glib::translate::mut_override(&self.rtp_buffer),
362                id,
363                nth,
364                data_ptr,
365                &mut size,
366            ));
367            if result {
368                if size == 0 {
369                    Some(&[])
370                } else {
371                    Some(slice::from_raw_parts(data as *const u8, size as usize))
372                }
373            } else {
374                None
375            }
376        }
377    }
378
379    #[doc(alias = "get_extension_twobytes_header")]
380    #[doc(alias = "gst_rtp_buffer_get_extension_twobytes_header")]
381    pub fn extension_twobytes_header(&self, id: u8, nth: u32) -> Option<(u8, &[u8])> {
382        unsafe {
383            let mut data = ptr::null_mut();
384            // FIXME: Workaround for gstreamer-rtp-sys having the wrong type for this parameter
385            let data_ptr = &mut data as *mut *mut u8 as *mut u8;
386            let mut size: u32 = 0;
387            let mut appbits = 0;
388            let result: bool = from_glib(ffi::gst_rtp_buffer_get_extension_twobytes_header(
389                glib::translate::mut_override(&self.rtp_buffer),
390                &mut appbits,
391                id,
392                nth,
393                data_ptr,
394                &mut size,
395            ));
396            if result {
397                if size == 0 {
398                    Some((appbits, &[]))
399                } else {
400                    Some((
401                        appbits,
402                        slice::from_raw_parts(data as *const u8, size as usize),
403                    ))
404                }
405            } else {
406                None
407            }
408        }
409    }
410
411    #[doc(alias = "get_padding")]
412    #[doc(alias = "gst_rtp_buffer_get_padding")]
413    pub fn has_padding(&self) -> bool {
414        unsafe {
415            from_glib(ffi::gst_rtp_buffer_get_padding(
416                glib::translate::mut_override(&self.rtp_buffer),
417            ))
418        }
419    }
420
421    #[inline]
422    pub fn as_ptr(&self) -> *const ffi::GstRTPBuffer {
423        &self.rtp_buffer as *const ffi::GstRTPBuffer
424    }
425
426    #[inline]
427    pub fn as_mut_ptr(&self) -> *mut ffi::GstRTPBuffer {
428        &self.rtp_buffer as *const ffi::GstRTPBuffer as *mut ffi::GstRTPBuffer
429    }
430}
431
432impl<T> Drop for RTPBuffer<'_, T> {
433    #[inline]
434    fn drop(&mut self) {
435        unsafe {
436            ffi::gst_rtp_buffer_unmap(&mut self.rtp_buffer);
437        }
438    }
439}
440
441pub trait RTPBufferExt {
442    fn new_rtp_with_sizes(
443        payload_len: u32,
444        pad_len: u8,
445        csrc_count: u8,
446    ) -> Result<gst::Buffer, glib::BoolError>;
447}
448
449impl RTPBufferExt for gst::Buffer {
450    fn new_rtp_with_sizes(
451        payload_len: u32,
452        pad_len: u8,
453        csrc_count: u8,
454    ) -> Result<gst::Buffer, glib::BoolError> {
455        assert_initialized_main_thread!();
456        unsafe {
457            Option::<_>::from_glib_full(ffi::gst_rtp_buffer_new_allocate(
458                payload_len,
459                pad_len,
460                csrc_count,
461            ))
462            .ok_or_else(|| glib::bool_error!("Failed to allocate new RTP buffer"))
463        }
464    }
465}
466
467#[doc(alias = "gst_rtp_buffer_compare_seqnum")]
468pub fn compare_seqnum(seqnum1: u16, seqnum2: u16) -> i32 {
469    skip_assert_initialized!();
470    unsafe { ffi::gst_rtp_buffer_compare_seqnum(seqnum1, seqnum2) }
471}
472
473#[doc(alias = "gst_rtp_buffer_calc_header_len")]
474pub fn calc_header_len(csrc_count: u8) -> u32 {
475    skip_assert_initialized!();
476    unsafe { ffi::gst_rtp_buffer_calc_header_len(csrc_count) }
477}
478
479#[doc(alias = "gst_rtp_buffer_calc_packet_len")]
480pub fn calc_packet_len(payload_len: u32, pad_len: u8, csrc_count: u8) -> u32 {
481    skip_assert_initialized!();
482    unsafe { ffi::gst_rtp_buffer_calc_packet_len(payload_len, pad_len, csrc_count) }
483}
484
485#[doc(alias = "gst_rtp_buffer_calc_payload_len")]
486pub fn calc_payload_len(packet_len: u32, pad_len: u8, csrc_count: u8) -> u32 {
487    skip_assert_initialized!();
488    unsafe { ffi::gst_rtp_buffer_calc_payload_len(packet_len, pad_len, csrc_count) }
489}
490
491#[doc(alias = "gst_rtp_buffer_ext_timestamp")]
492pub fn ext_timestamp(exttimestamp: &mut u64, timestamp: u32) -> u64 {
493    skip_assert_initialized!();
494    unsafe { ffi::gst_rtp_buffer_ext_timestamp(exttimestamp, timestamp) }
495}
496
497#[cfg(test)]
498mod tests {
499    use super::*;
500
501    #[test]
502    fn test_map() {
503        gst::init().unwrap();
504
505        let csrc_count = 2;
506        let payload_size = 16;
507        let mut buffer = gst::Buffer::new_rtp_with_sizes(payload_size, 4, csrc_count).unwrap();
508        {
509            let buffer = buffer.get_mut().unwrap();
510            let mut rtp_buffer = RTPBuffer::from_buffer_writable(buffer).unwrap();
511
512            rtp_buffer.set_seq(42);
513            assert_eq!(rtp_buffer.seq(), 42);
514
515            rtp_buffer.set_marker(true);
516            assert!(rtp_buffer.is_marker());
517
518            rtp_buffer.set_payload_type(43);
519            assert_eq!(rtp_buffer.payload_type(), 43);
520
521            rtp_buffer.set_timestamp(44);
522            assert_eq!(rtp_buffer.timestamp(), 44);
523
524            rtp_buffer.set_ssrc(45);
525            assert_eq!(rtp_buffer.ssrc(), 45);
526
527            assert_eq!(rtp_buffer.payload_size(), payload_size);
528            let payload = rtp_buffer.payload();
529            assert!(payload.is_ok());
530            let payload = payload.unwrap();
531            assert_eq!(payload.len(), payload_size as usize);
532
533            assert_eq!(rtp_buffer.csrc_count(), csrc_count);
534            rtp_buffer.set_csrc(0, 12);
535            rtp_buffer.set_csrc(1, 15);
536            assert_eq!(rtp_buffer.csrc(0).unwrap(), 12);
537            assert_eq!(rtp_buffer.csrc(1).unwrap(), 15);
538            assert!(rtp_buffer.csrc(2).is_none());
539
540            rtp_buffer.set_extension(true);
541            assert!(rtp_buffer.is_extension());
542
543            assert_eq!(rtp_buffer.extension_bytes(), None);
544        }
545    }
546
547    #[test]
548    fn test_empty_payload() {
549        gst::init().unwrap();
550
551        let csrc_count = 0;
552        let payload_size = 0;
553        let buffer = gst::Buffer::new_rtp_with_sizes(payload_size, 4, csrc_count).unwrap();
554        let rtp_buffer = RTPBuffer::from_buffer_readable(&buffer).unwrap();
555
556        assert_eq!(rtp_buffer.payload_size(), payload_size);
557        let payload = rtp_buffer.payload();
558        assert!(payload.is_ok());
559        assert_eq!(payload.unwrap().len(), payload_size as usize);
560    }
561
562    #[test]
563    fn test_mut_payload() {
564        gst::init().unwrap();
565
566        let csrc_count = 2;
567        let payload_size = 8;
568        let mut buffer = gst::Buffer::new_rtp_with_sizes(payload_size, 4, csrc_count).unwrap();
569        {
570            let buffer = buffer.get_mut().unwrap();
571            let mut rtp_buffer = RTPBuffer::from_buffer_writable(buffer).unwrap();
572
573            let payload = rtp_buffer.payload_mut();
574            assert!(payload.is_ok());
575
576            let payload = payload.unwrap();
577            payload[3] = 42;
578        }
579
580        let rtp_buffer = RTPBuffer::from_buffer_readable(&buffer).unwrap();
581        let payload = rtp_buffer.payload();
582
583        assert!(payload.is_ok());
584        assert_eq!(payload.unwrap()[3], 42);
585    }
586
587    #[test]
588    fn test_extension_header_onebyte() {
589        gst::init().unwrap();
590
591        let extension_data: [u8; 4] = [100, 101, 102, 103];
592        let mut buffer = gst::Buffer::new_rtp_with_sizes(16, 4, 0).unwrap();
593        {
594            let buffer = buffer.get_mut().unwrap();
595            let mut rtp_buffer = RTPBuffer::from_buffer_writable(buffer).unwrap();
596
597            assert_eq!(rtp_buffer.extension_bytes(), None);
598
599            let result = rtp_buffer.add_extension_onebyte_header(1, &extension_data);
600            assert!(result.is_ok());
601        }
602
603        let rtp_buffer = RTPBuffer::from_buffer_readable(&buffer).unwrap();
604        let bytes_option = rtp_buffer.extension_bytes();
605        assert!(bytes_option.is_some());
606        let (bits, bytes) = bytes_option.unwrap();
607        // 0xBEDE is the onebyte extension header marker: https://tools.ietf.org/html/rfc5285 (4.2)
608        assert_eq!(bits, 0xbede);
609        /*
610         * bytes is:
611         * * id (4 bits)
612         * * size-1 (4 bits)
613         * * data (with padded length to multiples of 4)
614         */
615        assert_eq!(bytes[0] >> 4, 1);
616        assert_eq!(bytes[0] & 0xF, 3);
617        for i in 0..extension_data.len() {
618            assert_eq!(bytes[i + 1], extension_data[i]);
619        }
620
621        let result = rtp_buffer.extension_onebyte_header(2, 0);
622        assert!(result.is_none());
623
624        let result = rtp_buffer.extension_onebyte_header(1, 0);
625        assert!(result.is_some());
626        assert_eq!(result.unwrap(), &extension_data);
627    }
628
629    #[test]
630    fn test_extension_header_twobytes() {
631        gst::init().unwrap();
632
633        let extension_data: [u8; 4] = [100, 101, 102, 103];
634        let appbits = 5;
635        let id = 1;
636
637        let mut buffer = gst::Buffer::new_rtp_with_sizes(16, 4, 0).unwrap();
638        {
639            let buffer = buffer.get_mut().unwrap();
640            let mut rtp_buffer = RTPBuffer::from_buffer_writable(buffer).unwrap();
641
642            assert_eq!(rtp_buffer.extension_bytes(), None);
643
644            let result = rtp_buffer.add_extension_twobytes_header(appbits, id, &extension_data);
645            assert!(result.is_ok());
646        }
647
648        let rtp_buffer = RTPBuffer::from_buffer_readable(&buffer).unwrap();
649
650        let bytes_option = rtp_buffer.extension_bytes();
651        assert!(bytes_option.is_some());
652        let (bits, bytes) = bytes_option.unwrap();
653        // 0x100 + appbits is the twobyte extension header marker:
654        // https://tools.ietf.org/html/rfc5285 (4.3)
655        assert_eq!(bits, 0x1000 | appbits as u16);
656        /*
657         * bytes is:
658         * * id (1 byte)
659         * * size-2 (1 byte)
660         * * data (with padded length to multiples of 4)
661         */
662        assert_eq!(bytes[0], id);
663        assert_eq!(bytes[1], extension_data.len() as u8);
664        for i in 0..extension_data.len() {
665            assert_eq!(bytes[i + 2], extension_data[i]);
666        }
667
668        let result = rtp_buffer.extension_twobytes_header(2, 0);
669        assert!(result.is_none());
670
671        let result = rtp_buffer.extension_twobytes_header(id, 0);
672        assert!(result.is_some());
673        let (extracted_appbits, data) = result.unwrap();
674        assert_eq!(appbits, extracted_appbits);
675        assert_eq!(data, &extension_data);
676    }
677
678    #[test]
679    fn test_padding() {
680        gst::init().unwrap();
681
682        let csrc_count = 2;
683        let payload_size = 16;
684        let mut buffer = gst::Buffer::new_rtp_with_sizes(payload_size, 4, csrc_count).unwrap();
685        {
686            let rtp_buffer = RTPBuffer::from_buffer_readable(&buffer).unwrap();
687            assert!(rtp_buffer.has_padding());
688        }
689        {
690            let buffer = buffer.get_mut().unwrap();
691            let mut rtp_buffer = RTPBuffer::from_buffer_writable(buffer).unwrap();
692
693            rtp_buffer.set_padding(false);
694        }
695
696        {
697            let rtp_buffer = RTPBuffer::from_buffer_readable(&buffer).unwrap();
698            assert!(!rtp_buffer.has_padding());
699        }
700    }
701
702    #[test]
703    fn test_calc_functions() {
704        let res = super::calc_header_len(0);
705        assert_eq!(res, 12);
706        let res = super::calc_packet_len(100, 10, 2);
707        assert_eq!(res, 130);
708        let res = super::calc_payload_len(100, 5, 4);
709        assert_eq!(res, 67);
710    }
711}