-
-
Notifications
You must be signed in to change notification settings - Fork 363
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #331 from webrtc-rs/feature/video-orientation
Video orientation extension
- Loading branch information
Showing
4 changed files
with
256 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
pub mod abs_send_time_extension; | ||
pub mod audio_level_extension; | ||
pub mod transport_cc_extension; | ||
pub mod video_orientation_extension; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
#[cfg(test)] | ||
mod video_orientation_extension_test; | ||
|
||
use std::convert::{TryFrom, TryInto}; | ||
|
||
use bytes::BufMut; | ||
use util::{marshal::Unmarshal, Marshal, MarshalSize}; | ||
|
||
use crate::Error; | ||
|
||
// One byte header size | ||
pub const VIDEO_ORIENTATION_EXTENSION_SIZE: usize = 1; | ||
|
||
/// Coordination of Video Orientation in RTP streams. | ||
/// | ||
/// Coordination of Video Orientation consists in signaling of the current | ||
/// orientation of the image captured on the sender side to the receiver for | ||
/// appropriate rendering and displaying. | ||
/// | ||
/// C = Camera: indicates the direction of the camera used for this video | ||
/// stream. It can be used by the MTSI client in receiver to e.g. display | ||
/// the received video differently depending on the source camera. | ||
/// | ||
/// 0: Front-facing camera, facing the user. If camera direction is | ||
/// unknown by the sending MTSI client in the terminal then this is the | ||
/// default value used. | ||
/// 1: Back-facing camera, facing away from the user. | ||
/// | ||
/// F = Flip: indicates a horizontal (left-right flip) mirror operation on | ||
/// the video as sent on the link. | ||
/// | ||
/// 0 1 | ||
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 | ||
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
/// | ID | len=0 |0 0 0 0 C F R R| | ||
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
#[derive(PartialEq, Eq, Debug, Default, Copy, Clone)] | ||
pub struct VideoOrientationExtension { | ||
pub direction: CameraDirection, | ||
pub flip: bool, | ||
pub rotation: VideoRotation, | ||
} | ||
|
||
#[derive(PartialEq, Eq, Debug, Copy, Clone)] | ||
pub enum CameraDirection { | ||
Front = 0, | ||
Back = 1, | ||
} | ||
|
||
#[derive(PartialEq, Eq, Debug, Copy, Clone)] | ||
pub enum VideoRotation { | ||
Degree0 = 0, | ||
Degree90 = 1, | ||
Degree180 = 2, | ||
Degree270 = 3, | ||
} | ||
|
||
impl MarshalSize for VideoOrientationExtension { | ||
fn marshal_size(&self) -> usize { | ||
VIDEO_ORIENTATION_EXTENSION_SIZE | ||
} | ||
} | ||
|
||
impl Unmarshal for VideoOrientationExtension { | ||
fn unmarshal<B>(buf: &mut B) -> util::Result<Self> | ||
where | ||
Self: Sized, | ||
B: bytes::Buf, | ||
{ | ||
if buf.remaining() < VIDEO_ORIENTATION_EXTENSION_SIZE { | ||
return Err(Error::ErrBufferTooSmall.into()); | ||
} | ||
|
||
let b = buf.get_u8(); | ||
|
||
let c = (b & 0b1000) >> 3; | ||
let f = b & 0b0100; | ||
let r = b & 0b0011; | ||
|
||
Ok(VideoOrientationExtension { | ||
direction: c.try_into()?, | ||
flip: f > 0, | ||
rotation: r.try_into()?, | ||
}) | ||
} | ||
} | ||
|
||
impl Marshal for VideoOrientationExtension { | ||
fn marshal_to(&self, mut buf: &mut [u8]) -> util::Result<usize> { | ||
let c = (self.direction as u8) << 3; | ||
let f = if self.flip { 0b0100 } else { 0 }; | ||
let r = self.rotation as u8; | ||
|
||
buf.put_u8(c | f | r); | ||
|
||
Ok(VIDEO_ORIENTATION_EXTENSION_SIZE) | ||
} | ||
} | ||
|
||
impl TryFrom<u8> for CameraDirection { | ||
type Error = util::Error; | ||
|
||
fn try_from(value: u8) -> Result<Self, Self::Error> { | ||
match value { | ||
0 => Ok(CameraDirection::Front), | ||
1 => Ok(CameraDirection::Back), | ||
_ => Err(util::Error::Other(format!( | ||
"Unhandled camera direction: {}", | ||
value | ||
))), | ||
} | ||
} | ||
} | ||
|
||
impl TryFrom<u8> for VideoRotation { | ||
type Error = util::Error; | ||
|
||
fn try_from(value: u8) -> Result<Self, Self::Error> { | ||
match value { | ||
0 => Ok(VideoRotation::Degree0), | ||
1 => Ok(VideoRotation::Degree90), | ||
2 => Ok(VideoRotation::Degree180), | ||
3 => Ok(VideoRotation::Degree270), | ||
_ => Err(util::Error::Other(format!( | ||
"Unhandled video rotation: {}", | ||
value | ||
))), | ||
} | ||
} | ||
} | ||
|
||
impl Default for CameraDirection { | ||
fn default() -> Self { | ||
CameraDirection::Front | ||
} | ||
} | ||
|
||
impl Default for VideoRotation { | ||
fn default() -> Self { | ||
VideoRotation::Degree0 | ||
} | ||
} |
112 changes: 112 additions & 0 deletions
112
rtp/src/extension/video_orientation_extension/video_orientation_extension_test.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
use super::*; | ||
use crate::error::Result; | ||
use bytes::{Bytes, BytesMut}; | ||
|
||
#[test] | ||
fn test_video_orientation_extension_too_small() -> Result<()> { | ||
let mut buf = &vec![0u8; 0][..]; | ||
let result = VideoOrientationExtension::unmarshal(&mut buf); | ||
assert!(result.is_err()); | ||
|
||
Ok(()) | ||
} | ||
|
||
#[test] | ||
fn test_video_orientation_extension_back_facing_camera() -> Result<()> { | ||
let raw = Bytes::from_static(&[0b1000]); | ||
let buf = &mut raw.clone(); | ||
let a1 = VideoOrientationExtension::unmarshal(buf)?; | ||
let a2 = VideoOrientationExtension { | ||
direction: CameraDirection::Back, | ||
flip: false, | ||
rotation: VideoRotation::Degree0, | ||
}; | ||
assert_eq!(a1, a2); | ||
|
||
let mut dst = BytesMut::with_capacity(a2.marshal_size()); | ||
dst.resize(a2.marshal_size(), 0); | ||
a2.marshal_to(&mut dst)?; | ||
assert_eq!(raw, dst.freeze()); | ||
|
||
Ok(()) | ||
} | ||
|
||
#[test] | ||
fn test_video_orientation_extension_flip_true() -> Result<()> { | ||
let raw = Bytes::from_static(&[0b0100]); | ||
let buf = &mut raw.clone(); | ||
let a1 = VideoOrientationExtension::unmarshal(buf)?; | ||
let a2 = VideoOrientationExtension { | ||
direction: CameraDirection::Front, | ||
flip: true, | ||
rotation: VideoRotation::Degree0, | ||
}; | ||
assert_eq!(a1, a2); | ||
|
||
let mut dst = BytesMut::with_capacity(a2.marshal_size()); | ||
dst.resize(a2.marshal_size(), 0); | ||
a2.marshal_to(&mut dst)?; | ||
assert_eq!(raw, dst.freeze()); | ||
|
||
Ok(()) | ||
} | ||
|
||
#[test] | ||
fn test_video_orientation_extension_degree_90() -> Result<()> { | ||
let raw = Bytes::from_static(&[0b0001]); | ||
let buf = &mut raw.clone(); | ||
let a1 = VideoOrientationExtension::unmarshal(buf)?; | ||
let a2 = VideoOrientationExtension { | ||
direction: CameraDirection::Front, | ||
flip: false, | ||
rotation: VideoRotation::Degree90, | ||
}; | ||
assert_eq!(a1, a2); | ||
|
||
let mut dst = BytesMut::with_capacity(a2.marshal_size()); | ||
dst.resize(a2.marshal_size(), 0); | ||
a2.marshal_to(&mut dst)?; | ||
assert_eq!(raw, dst.freeze()); | ||
|
||
Ok(()) | ||
} | ||
|
||
#[test] | ||
fn test_video_orientation_extension_degree_180() -> Result<()> { | ||
let raw = Bytes::from_static(&[0b0010]); | ||
let buf = &mut raw.clone(); | ||
let a1 = VideoOrientationExtension::unmarshal(buf)?; | ||
let a2 = VideoOrientationExtension { | ||
direction: CameraDirection::Front, | ||
flip: false, | ||
rotation: VideoRotation::Degree180, | ||
}; | ||
assert_eq!(a1, a2); | ||
|
||
let mut dst = BytesMut::with_capacity(a2.marshal_size()); | ||
dst.resize(a2.marshal_size(), 0); | ||
a2.marshal_to(&mut dst)?; | ||
assert_eq!(raw, dst.freeze()); | ||
|
||
Ok(()) | ||
} | ||
|
||
#[test] | ||
fn test_video_orientation_extension_degree_270() -> Result<()> { | ||
let raw = Bytes::from_static(&[0b0011]); | ||
let buf = &mut raw.clone(); | ||
let a1 = VideoOrientationExtension::unmarshal(buf)?; | ||
let a2 = VideoOrientationExtension { | ||
direction: CameraDirection::Front, | ||
flip: false, | ||
rotation: VideoRotation::Degree270, | ||
}; | ||
assert_eq!(a1, a2); | ||
|
||
let mut dst = BytesMut::with_capacity(a2.marshal_size()); | ||
dst.resize(a2.marshal_size(), 0); | ||
a2.marshal_to(&mut dst)?; | ||
assert_eq!(raw, dst.freeze()); | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters