diff --git a/talk/media/base/constants.cc b/talk/media/base/constants.cc index 46f29bff28..6e1c460e2a 100644 --- a/talk/media/base/constants.cc +++ b/talk/media/base/constants.cc @@ -109,6 +109,11 @@ const int kRtpAbsoluteSenderTimeHeaderExtensionDefaultId = 3; const char kRtpAbsoluteSenderTimeHeaderExtension[] = "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"; +const int kRtpVideoRotationHeaderExtensionDefaultId = 4; +const char kRtpVideoRotationHeaderExtension[] = "urn:3gpp:video-orientation"; +const char kRtpVideoRotation6BitsHeaderExtensionForTesting[] = + "urn:3gpp:video-orientation:6"; + const int kNumDefaultUnsignalledVideoRecvStreams = 0; diff --git a/talk/media/base/constants.h b/talk/media/base/constants.h index ce2748c25b..2fb4fdc136 100644 --- a/talk/media/base/constants.h +++ b/talk/media/base/constants.h @@ -121,21 +121,29 @@ extern const char kGoogleSctpDataCodecName[]; extern const char kComfortNoiseCodecName[]; -// Extension header for audio levels, as defined in +// Header extension for audio levels, as defined in // http://tools.ietf.org/html/draft-ietf-avtext-client-to-mixer-audio-level-03 extern const int kRtpAudioLevelHeaderExtensionDefaultId; extern const char kRtpAudioLevelHeaderExtension[]; -// Extension header for RTP timestamp offset, see RFC 5450 for details: +// Header extension for RTP timestamp offset, see RFC 5450 for details: // http://tools.ietf.org/html/rfc5450 extern const int kRtpTimestampOffsetHeaderExtensionDefaultId; extern const char kRtpTimestampOffsetHeaderExtension[]; -// Extension header for absolute send time, see url for details: +// Header extension for absolute send time, see url for details: // http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time extern const int kRtpAbsoluteSenderTimeHeaderExtensionDefaultId; extern const char kRtpAbsoluteSenderTimeHeaderExtension[]; +// Header extension for coordination of video orientation, see url for details: +// http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/ +// ts_126114v120700p.pdf +extern const int kRtpVideoRotationHeaderExtensionDefaultId; +extern const char kRtpVideoRotationHeaderExtension[]; +// We don't support 6 bit CVO. Added here for testing purpose. +extern const char kRtpVideoRotation6BitsHeaderExtensionForTesting[]; + extern const int kNumDefaultUnsignalledVideoRecvStreams; } // namespace cricket diff --git a/talk/media/webrtc/fakewebrtcvideoengine.h b/talk/media/webrtc/fakewebrtcvideoengine.h index f64cd40a95..16c7f8b71c 100644 --- a/talk/media/webrtc/fakewebrtcvideoengine.h +++ b/talk/media/webrtc/fakewebrtcvideoengine.h @@ -285,6 +285,8 @@ class FakeWebRtcVideoEngine rtp_offset_receive_id_(-1), rtp_absolute_send_time_send_id_(-1), rtp_absolute_send_time_receive_id_(-1), + rtp_video_rotation_send_id_(-1), + rtp_video_rotation_receive_id_(-1), sender_target_delay_(0), receiver_target_delay_(0), transmission_smoothing_(false), @@ -325,6 +327,8 @@ class FakeWebRtcVideoEngine int rtp_offset_receive_id_; int rtp_absolute_send_time_send_id_; int rtp_absolute_send_time_receive_id_; + int rtp_video_rotation_send_id_; + int rtp_video_rotation_receive_id_; int sender_target_delay_; int receiver_target_delay_; bool transmission_smoothing_; @@ -503,6 +507,8 @@ class FakeWebRtcVideoEngine return channels_.find(channel)->second->rtp_offset_send_id_; } else if (extension == kRtpAbsoluteSenderTimeHeaderExtension) { return channels_.find(channel)->second->rtp_absolute_send_time_send_id_; + } else if (extension == kRtpVideoRotationHeaderExtension) { + return channels_.find(channel)->second->rtp_video_rotation_send_id_; } return -1; } @@ -513,6 +519,8 @@ class FakeWebRtcVideoEngine } else if (extension == kRtpAbsoluteSenderTimeHeaderExtension) { return channels_.find(channel)->second->rtp_absolute_send_time_receive_id_; + } else if (extension == kRtpVideoRotationHeaderExtension) { + return channels_.find(channel)->second->rtp_video_rotation_receive_id_; } return -1; } @@ -1107,25 +1115,36 @@ class FakeWebRtcVideoEngine WEBRTC_FUNC(SetSendTimestampOffsetStatus, (int channel, bool enable, int id)) { WEBRTC_CHECK_CHANNEL(channel); - channels_[channel]->rtp_offset_send_id_ = (enable) ? id : -1; + channels_[channel]->rtp_offset_send_id_ = enable? id : -1; return 0; } WEBRTC_FUNC(SetReceiveTimestampOffsetStatus, (int channel, bool enable, int id)) { WEBRTC_CHECK_CHANNEL(channel); - channels_[channel]->rtp_offset_receive_id_ = (enable) ? id : -1; + channels_[channel]->rtp_offset_receive_id_ = enable? id : -1; return 0; } WEBRTC_FUNC(SetSendAbsoluteSendTimeStatus, (int channel, bool enable, int id)) { WEBRTC_CHECK_CHANNEL(channel); - channels_[channel]->rtp_absolute_send_time_send_id_ = (enable) ? id : -1; + channels_[channel]->rtp_absolute_send_time_send_id_ = enable? id : -1; return 0; } WEBRTC_FUNC(SetReceiveAbsoluteSendTimeStatus, (int channel, bool enable, int id)) { WEBRTC_CHECK_CHANNEL(channel); - channels_[channel]->rtp_absolute_send_time_receive_id_ = (enable) ? id : -1; + channels_[channel]->rtp_absolute_send_time_receive_id_ = enable? id : -1; + return 0; + } + WEBRTC_FUNC(SetSendVideoRotationStatus, (int channel, bool enable, int id)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->rtp_video_rotation_send_id_ = enable? id : -1; + return 0; + } + WEBRTC_FUNC(SetReceiveVideoRotationStatus, + (int channel, bool enable, int id)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->rtp_video_rotation_receive_id_ = enable? id : -1; return 0; } WEBRTC_STUB(SetRtcpXrRrtrStatus, (int, bool)); diff --git a/webrtc/config.h b/webrtc/config.h index 1777937137..e43a58805d 100644 --- a/webrtc/config.h +++ b/webrtc/config.h @@ -51,6 +51,7 @@ struct RtpExtension { static const char* kTOffset; static const char* kAbsSendTime; + static const char* kVideoRotation; std::string name; int id; }; diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_cvo.h b/webrtc/modules/rtp_rtcp/interface/rtp_cvo.h new file mode 100644 index 0000000000..c7a0268ef0 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/interface/rtp_cvo.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_CVO__H_ +#define WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_CVO__H_ + +#include "webrtc/common_video/rotation.h" + +namespace webrtc { + +// Please refer to http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/ +// 12.07.00_60/ts_126114v120700p.pdf Section 7.4.5. The rotation of a frame is +// the clockwise angle the frames must be rotated in order to display the frames +// correctly if the display is rotated in its natural orientation. +inline uint8_t ConvertVideoRotationToCVOByte(VideoRotation rotation) { + switch (rotation) { + case kVideoRotation_0: + return 0; + case kVideoRotation_90: + return 1; + case kVideoRotation_180: + return 2; + case kVideoRotation_270: + return 3; + } + assert(false); + return 0; +} + +inline VideoRotation ConvertCVOByteToVideoRotation(uint8_t rotation) { + switch (rotation) { + case 0: + return kVideoRotation_0; + case 1: + return kVideoRotation_90; + case 2: + return kVideoRotation_180; + break; + case 3: + return kVideoRotation_270; + default: + assert(false); + return kVideoRotation_0; + } +} + +} // namespace webrtc +#endif // WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_CVO__H_ diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc b/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc index fd3b7af2c1..2823868015 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc @@ -13,6 +13,7 @@ #include #include +#include "webrtc/modules/rtp_rtcp/interface/rtp_cvo.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h" #include "webrtc/modules/rtp_rtcp/source/rtp_format.h" #include "webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h" @@ -62,6 +63,13 @@ int32_t RTPReceiverVideo::ParseRtpPacket(WebRtcRTPHeader* rtp_header, const size_t payload_data_length = payload_length - rtp_header->header.paddingLength; + // Retrieve the video rotation information. + rtp_header->type.Video.rotation = kVideoRotation_0; + if (rtp_header->header.extension.hasVideoRotation) { + rtp_header->type.Video.rotation = ConvertCVOByteToVideoRotation( + rtp_header->header.extension.videoRotation); + } + if (payload == NULL || payload_data_length == 0) { return data_callback_->OnReceivedPayloadData(NULL, 0, rtp_header) == 0 ? 0 : -1; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc index 28c458ddb7..c01cb361d7 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -12,6 +12,7 @@ #include // srand +#include "webrtc/modules/rtp_rtcp/interface/rtp_cvo.h" #include "webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h" #include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" @@ -453,25 +454,6 @@ int32_t RTPSender::CheckPayloadType(int8_t payload_type, return 0; } -// Please refer to http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/ -// 12.07.00_60/ts_126114v120700p.pdf Section 7.4.5. The rotation of a frame is -// the clockwise angle the frames must be rotated in order to display the frames -// correctly if the display is rotated in its natural orientation. -uint8_t RTPSender::ConvertToCVOByte(VideoRotation rotation) { - switch (rotation) { - case kVideoRotation_0: - return 0; - case kVideoRotation_90: - return 1; - case kVideoRotation_180: - return 2; - case kVideoRotation_270: - return 3; - } - assert(false); - return 0; -} - int32_t RTPSender::SendOutgoingData(FrameType frame_type, int8_t payload_type, uint32_t capture_timestamp, @@ -1367,7 +1349,7 @@ uint8_t RTPSender::BuildVideoRotationExtension(uint8_t* data_buffer) const { size_t pos = 0; const uint8_t len = 0; data_buffer[pos++] = (id << 4) + len; - data_buffer[pos++] = ConvertToCVOByte(rotation_); + data_buffer[pos++] = ConvertVideoRotationToCVOByte(rotation_); data_buffer[pos++] = 0; // padding data_buffer[pos++] = 0; // padding assert(pos == kVideoRotationLength); @@ -1508,7 +1490,7 @@ bool RTPSender::UpdateVideoRotation(uint8_t* rtp_packet, LOG(LS_WARNING) << "Failed to update CVO."; return false; } - rtp_packet[block_pos + 1] = ConvertToCVOByte(rotation); + rtp_packet[block_pos + 1] = ConvertVideoRotationToCVOByte(rotation); return true; } diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/webrtc/modules/rtp_rtcp/source/rtp_sender.h index 67fb1feaf0..72763edf9d 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.h @@ -284,8 +284,6 @@ class RTPSender : public RTPSenderInterface { void SetRtxRtpState(const RtpState& rtp_state); RtpState GetRtxRtpState() const; - static uint8_t ConvertToCVOByte(VideoRotation rotation); - protected: int32_t CheckPayloadType(int8_t payload_type, RtpVideoCodecTypes* video_type); diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc index c6e8398658..e5c3b6fee1 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -17,6 +17,7 @@ #include "webrtc/base/buffer.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/modules/pacing/include/mock/mock_paced_sender.h" +#include "webrtc/modules/rtp_rtcp/interface/rtp_cvo.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h" #include "webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h" @@ -189,7 +190,7 @@ class RtpSenderVideoTest : public RtpSenderTest { EXPECT_EQ(rtp_sender_->SSRC(), rtp_header.ssrc); EXPECT_EQ(0, rtp_header.numCSRCs); EXPECT_EQ(0U, rtp_header.paddingLength); - EXPECT_EQ(RTPSender::ConvertToCVOByte(rotation), + EXPECT_EQ(ConvertVideoRotationToCVOByte(rotation), rtp_header.extension.videoRotation); } }; @@ -427,7 +428,7 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithVideoRotation_MarkerBit) { VerifyRTPHeaderCommon(rtp_header); EXPECT_EQ(length, rtp_header.headerLength); EXPECT_TRUE(rtp_header.extension.hasVideoRotation); - EXPECT_EQ(RTPSender::ConvertToCVOByte(kRotation), + EXPECT_EQ(ConvertVideoRotationToCVOByte(kRotation), rtp_header.extension.videoRotation); } diff --git a/webrtc/video/call.cc b/webrtc/video/call.cc index bf80ee5b95..21a78da7ed 100644 --- a/webrtc/video/call.cc +++ b/webrtc/video/call.cc @@ -41,10 +41,12 @@ namespace webrtc { const char* RtpExtension::kTOffset = "urn:ietf:params:rtp-hdrext:toffset"; const char* RtpExtension::kAbsSendTime = "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"; +const char* RtpExtension::kVideoRotation = "urn:3gpp:video-orientation"; bool RtpExtension::IsSupported(const std::string& name) { return name == webrtc::RtpExtension::kTOffset || - name == webrtc::RtpExtension::kAbsSendTime; + name == webrtc::RtpExtension::kAbsSendTime || + name == webrtc::RtpExtension::kVideoRotation; } VideoEncoder* VideoEncoder::Create(VideoEncoder::EncoderType codec_type) { diff --git a/webrtc/video/video_receive_stream.cc b/webrtc/video/video_receive_stream.cc index 8665c1149a..ce65bcd28d 100644 --- a/webrtc/video/video_receive_stream.cc +++ b/webrtc/video/video_receive_stream.cc @@ -181,6 +181,9 @@ VideoReceiveStream::VideoReceiveStream(webrtc::VideoEngine* video_engine, } else if (extension == RtpExtension::kAbsSendTime) { if (rtp_rtcp_->SetReceiveAbsoluteSendTimeStatus(channel_, true, id) != 0) abort(); + } else if (extension == RtpExtension::kVideoRotation) { + if (rtp_rtcp_->SetReceiveVideoRotationStatus(channel_, true, id) != 0) + abort(); } else { abort(); // Unsupported extension. } diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc index 881802afb1..65e45e6aa1 100644 --- a/webrtc/video/video_send_stream.cc +++ b/webrtc/video/video_send_stream.cc @@ -144,6 +144,9 @@ VideoSendStream::VideoSendStream( } else if (extension == RtpExtension::kAbsSendTime) { if (rtp_rtcp_->SetSendAbsoluteSendTimeStatus(channel_, true, id) != 0) abort(); + } else if (extension == RtpExtension::kVideoRotation) { + if (rtp_rtcp_->SetSendVideoRotationStatus(channel_, true, id) != 0) + abort(); } else { abort(); // Unsupported extension. } diff --git a/webrtc/video_engine/include/vie_capture.h b/webrtc/video_engine/include/vie_capture.h index caaeacef2f..35c846954f 100644 --- a/webrtc/video_engine/include/vie_capture.h +++ b/webrtc/video_engine/include/vie_capture.h @@ -71,6 +71,7 @@ struct ViEVideoFrameI420 { v_pitch = 0; width = 0; height = 0; + rotation = kVideoRotation_0; } unsigned char* y_plane; @@ -83,6 +84,7 @@ struct ViEVideoFrameI420 { unsigned short width; unsigned short height; + VideoRotation rotation; }; // This class declares an abstract interface to be used when implementing diff --git a/webrtc/video_engine/include/vie_rtp_rtcp.h b/webrtc/video_engine/include/vie_rtp_rtcp.h index 7446e5f099..d9a6a1fca9 100644 --- a/webrtc/video_engine/include/vie_rtp_rtcp.h +++ b/webrtc/video_engine/include/vie_rtp_rtcp.h @@ -245,6 +245,14 @@ class WEBRTC_DLLEXPORT ViERTP_RTCP { bool enable, int id) = 0; + virtual int SetSendVideoRotationStatus(int video_channel, + bool enable, + int id) = 0; + + virtual int SetReceiveVideoRotationStatus(int video_channel, + bool enable, + int id) = 0; + // Enables/disables RTCP Receiver Reference Time Report Block extension/ // DLRR Report Block extension (RFC 3611). virtual int SetRtcpXrRrtrStatus(int video_channel, bool enable) = 0; diff --git a/webrtc/video_engine/vie_capturer.cc b/webrtc/video_engine/vie_capturer.cc index bc964250a2..b35be3e763 100644 --- a/webrtc/video_engine/vie_capturer.cc +++ b/webrtc/video_engine/vie_capturer.cc @@ -325,7 +325,8 @@ int ViECapturer::IncomingFrameI420(const ViEVideoFrameI420& video_frame, video_frame.height, video_frame.y_pitch, video_frame.u_pitch, - video_frame.v_pitch); + video_frame.v_pitch, + video_frame.rotation); if (ret < 0) { LOG_F(LS_ERROR) << "Could not create I420Frame."; diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc index eb16b1f345..1101213ca5 100644 --- a/webrtc/video_engine/vie_channel.cc +++ b/webrtc/video_engine/vie_channel.cc @@ -118,6 +118,7 @@ ViEChannel::ViEChannel(int32_t channel_id, bandwidth_observer_(bandwidth_observer), send_timestamp_extension_id_(kInvalidRtpExtensionId), absolute_send_time_extension_id_(kInvalidRtpExtensionId), + video_rotation_extension_id_(kInvalidRtpExtensionId), external_transport_(NULL), decoder_reset_(true), wait_for_key_frame_(false), @@ -459,6 +460,7 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec, if (rtp_rtcp->RegisterSendRtpHeaderExtension( kRtpExtensionTransmissionTimeOffset, send_timestamp_extension_id_) != 0) { + LOG(LS_WARNING) << "Register Transmission Time Offset failed"; } } else { rtp_rtcp->DeregisterSendRtpHeaderExtension( @@ -471,11 +473,23 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec, if (rtp_rtcp->RegisterSendRtpHeaderExtension( kRtpExtensionAbsoluteSendTime, absolute_send_time_extension_id_) != 0) { + LOG(LS_WARNING) << "Register Absolute Send Time failed"; } } else { rtp_rtcp->DeregisterSendRtpHeaderExtension( kRtpExtensionAbsoluteSendTime); } + if (video_rotation_extension_id_ != kInvalidRtpExtensionId) { + // Deregister in case the extension was previously enabled. + rtp_rtcp->DeregisterSendRtpHeaderExtension(kRtpExtensionVideoRotation); + if (rtp_rtcp->RegisterSendRtpHeaderExtension( + kRtpExtensionVideoRotation, video_rotation_extension_id_) != + 0) { + LOG(LS_WARNING) << "Register VideoRotation extension failed"; + } + } else { + rtp_rtcp->DeregisterSendRtpHeaderExtension(kRtpExtensionVideoRotation); + } rtp_rtcp->RegisterRtcpStatisticsCallback( rtp_rtcp_->GetRtcpStatisticsCallback()); rtp_rtcp->RegisterSendChannelRtpStatisticsCallback( @@ -899,6 +913,37 @@ int ViEChannel::SetReceiveAbsoluteSendTimeStatus(bool enable, int id) { return vie_receiver_.SetReceiveAbsoluteSendTimeStatus(enable, id) ? 0 : -1; } +int ViEChannel::SetSendVideoRotationStatus(bool enable, int id) { + CriticalSectionScoped cs(rtp_rtcp_cs_.get()); + int error = 0; + if (enable) { + // Enable the extension, but disable possible old id to avoid errors. + video_rotation_extension_id_ = id; + rtp_rtcp_->DeregisterSendRtpHeaderExtension(kRtpExtensionVideoRotation); + error = rtp_rtcp_->RegisterSendRtpHeaderExtension( + kRtpExtensionVideoRotation, id); + for (std::list::iterator it = simulcast_rtp_rtcp_.begin(); + it != simulcast_rtp_rtcp_.end(); it++) { + (*it)->DeregisterSendRtpHeaderExtension(kRtpExtensionVideoRotation); + error |= + (*it)->RegisterSendRtpHeaderExtension(kRtpExtensionVideoRotation, id); + } + } else { + // Disable the extension. + video_rotation_extension_id_ = kInvalidRtpExtensionId; + rtp_rtcp_->DeregisterSendRtpHeaderExtension(kRtpExtensionVideoRotation); + for (std::list::iterator it = simulcast_rtp_rtcp_.begin(); + it != simulcast_rtp_rtcp_.end(); it++) { + (*it)->DeregisterSendRtpHeaderExtension(kRtpExtensionVideoRotation); + } + } + return error; +} + +int ViEChannel::SetReceiveVideoRotationStatus(bool enable, int id) { + return vie_receiver_.SetReceiveVideoRotationStatus(enable, id) ? 0 : -1; +} + void ViEChannel::SetRtcpXrRrtrStatus(bool enable) { CriticalSectionScoped cs(rtp_rtcp_cs_.get()); rtp_rtcp_->SetRtcpXrRrtrStatus(enable); diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h index 3744d88819..1bf95f81ea 100644 --- a/webrtc/video_engine/vie_channel.h +++ b/webrtc/video_engine/vie_channel.h @@ -131,6 +131,8 @@ class ViEChannel int SetSendAbsoluteSendTimeStatus(bool enable, int id); int SetReceiveAbsoluteSendTimeStatus(bool enable, int id); bool GetReceiveAbsoluteSendTimeStatus() const; + int SetSendVideoRotationStatus(bool enable, int id); + int SetReceiveVideoRotationStatus(bool enable, int id); void SetRtcpXrRrtrStatus(bool enable); void SetTransmissionSmoothingStatus(bool enable); void EnableTMMBR(bool enable); @@ -526,6 +528,7 @@ class ViEChannel rtc::scoped_ptr bandwidth_observer_; int send_timestamp_extension_id_; int absolute_send_time_extension_id_; + int video_rotation_extension_id_; Transport* external_transport_; diff --git a/webrtc/video_engine/vie_receiver.cc b/webrtc/video_engine/vie_receiver.cc index 0d1f1ad1e6..e61c82bb9d 100644 --- a/webrtc/video_engine/vie_receiver.cc +++ b/webrtc/video_engine/vie_receiver.cc @@ -16,6 +16,7 @@ #include "webrtc/modules/rtp_rtcp/interface/fec_receiver.h" #include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h" #include "webrtc/modules/rtp_rtcp/interface/remote_ntp_time_estimator.h" +#include "webrtc/modules/rtp_rtcp/interface/rtp_cvo.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h" @@ -58,6 +59,7 @@ ViEReceiver::ViEReceiver(const int32_t channel_id, receiving_(false), restored_packet_in_use_(false), receiving_ast_enabled_(false), + receiving_cvo_enabled_(false), last_packet_log_ms_(-1) { assert(remote_bitrate_estimator); } @@ -187,6 +189,22 @@ bool ViEReceiver::SetReceiveAbsoluteSendTimeStatus(bool enable, int id) { } } +bool ViEReceiver::SetReceiveVideoRotationStatus(bool enable, int id) { + if (enable) { + if (rtp_header_parser_->RegisterRtpHeaderExtension( + kRtpExtensionVideoRotation, id)) { + receiving_cvo_enabled_ = true; + return true; + } else { + return false; + } + } else { + receiving_cvo_enabled_ = false; + return rtp_header_parser_->DeregisterRtpHeaderExtension( + kRtpExtensionVideoRotation); + } +} + int ViEReceiver::ReceivedRTPPacket(const void* rtp_packet, size_t rtp_packet_length, const PacketTime& packet_time) { @@ -382,6 +400,11 @@ void ViEReceiver::NotifyReceiverOfFecPacket(const RTPHeader& header) { return; } rtp_header.type.Video.codec = payload_specific.Video.videoCodecType; + rtp_header.type.Video.rotation = kVideoRotation_0; + if (header.extension.hasVideoRotation) { + rtp_header.type.Video.rotation = + ConvertCVOByteToVideoRotation(header.extension.videoRotation); + } OnReceivedPayloadData(NULL, 0, &rtp_header); } diff --git a/webrtc/video_engine/vie_receiver.h b/webrtc/video_engine/vie_receiver.h index e2e3daf260..5c09a3e482 100644 --- a/webrtc/video_engine/vie_receiver.h +++ b/webrtc/video_engine/vie_receiver.h @@ -64,6 +64,7 @@ class ViEReceiver : public RtpData { bool SetReceiveTimestampOffsetStatus(bool enable, int id); bool SetReceiveAbsoluteSendTimeStatus(bool enable, int id); + bool SetReceiveVideoRotationStatus(bool enable, int id); void StartReceive(); void StopReceive(); @@ -123,6 +124,7 @@ class ViEReceiver : public RtpData { uint8_t restored_packet_[kViEMaxMtu]; bool restored_packet_in_use_; bool receiving_ast_enabled_; + bool receiving_cvo_enabled_; int64_t last_packet_log_ms_; }; diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.cc b/webrtc/video_engine/vie_rtp_rtcp_impl.cc index 58e750d35d..38e7e97dae 100644 --- a/webrtc/video_engine/vie_rtp_rtcp_impl.cc +++ b/webrtc/video_engine/vie_rtp_rtcp_impl.cc @@ -615,6 +615,43 @@ int ViERTP_RTCPImpl::SetReceiveAbsoluteSendTimeStatus(int video_channel, return 0; } +int ViERTP_RTCPImpl::SetSendVideoRotationStatus(int video_channel, + bool enable, + int id) { + LOG_F(LS_INFO) << "channel: " << video_channel + << " enable: " << (enable ? "on" : "off") << " id: " << id; + + ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); + ViEChannel* vie_channel = cs.Channel(video_channel); + if (!vie_channel) { + shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + if (vie_channel->SetSendVideoRotationStatus(enable, id) != 0) { + shared_data_->SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +int ViERTP_RTCPImpl::SetReceiveVideoRotationStatus(int video_channel, + bool enable, + int id) { + LOG_F(LS_INFO) << "channel: " << video_channel + << " enable: " << (enable ? "on" : "off") << " id: " << id; + ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); + ViEChannel* vie_channel = cs.Channel(video_channel); + if (!vie_channel) { + shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + if (vie_channel->SetReceiveVideoRotationStatus(enable, id) != 0) { + shared_data_->SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + int ViERTP_RTCPImpl::SetRtcpXrRrtrStatus(int video_channel, bool enable) { LOG_F(LS_INFO) << "channel: " << video_channel << " enable: " << (enable ? "on" : "off"); diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.h b/webrtc/video_engine/vie_rtp_rtcp_impl.h index 7512222a2b..b6f3a23c39 100644 --- a/webrtc/video_engine/vie_rtp_rtcp_impl.h +++ b/webrtc/video_engine/vie_rtp_rtcp_impl.h @@ -90,6 +90,12 @@ class ViERTP_RTCPImpl virtual int SetReceiveAbsoluteSendTimeStatus(int video_channel, bool enable, int id); + virtual int SetSendVideoRotationStatus(int video_channel, + bool enable, + int id); + virtual int SetReceiveVideoRotationStatus(int video_channel, + bool enable, + int id); virtual int SetRtcpXrRrtrStatus(int video_channel, bool enable); virtual int SetTransmissionSmoothingStatus(int video_channel, bool enable); virtual int SetMinTransmitBitrate(int video_channel,