Skip to main content

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