1 /* 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/base/checks.h" 12 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" 13 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" 14 #include "webrtc/modules/rtp_rtcp/source/rtp_format.h" 15 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" 16 #include "webrtc/test/layer_filtering_transport.h" 17 18 namespace webrtc { 19 namespace test { 20 21 LayerFilteringTransport::LayerFilteringTransport( 22 const FakeNetworkPipe::Config& config, 23 Call* send_call, 24 uint8_t vp8_video_payload_type, 25 uint8_t vp9_video_payload_type, 26 int selected_tl, 27 int selected_sl) 28 : test::DirectTransport(config, send_call), 29 vp8_video_payload_type_(vp8_video_payload_type), 30 vp9_video_payload_type_(vp9_video_payload_type), 31 selected_tl_(selected_tl), 32 selected_sl_(selected_sl), 33 discarded_last_packet_(false) {} 34 35 bool LayerFilteringTransport::DiscardedLastPacket() const { 36 return discarded_last_packet_; 37 } 38 39 bool LayerFilteringTransport::SendRtp(const uint8_t* packet, 40 size_t length, 41 const PacketOptions& options) { 42 if (selected_tl_ == -1 && selected_sl_ == -1) { 43 // Nothing to change, forward the packet immediately. 44 return test::DirectTransport::SendRtp(packet, length, options); 45 } 46 47 bool set_marker_bit = false; 48 RtpUtility::RtpHeaderParser parser(packet, length); 49 RTPHeader header; 50 parser.Parse(&header); 51 52 RTC_DCHECK_LE(length, static_cast<size_t>(IP_PACKET_SIZE)); 53 uint8_t temp_buffer[IP_PACKET_SIZE]; 54 memcpy(temp_buffer, packet, length); 55 56 if (header.payloadType == vp8_video_payload_type_ || 57 header.payloadType == vp9_video_payload_type_) { 58 const uint8_t* payload = packet + header.headerLength; 59 RTC_DCHECK_GT(length, header.headerLength); 60 const size_t payload_length = length - header.headerLength; 61 RTC_DCHECK_GT(payload_length, header.paddingLength); 62 const size_t payload_data_length = payload_length - header.paddingLength; 63 64 const bool is_vp8 = header.payloadType == vp8_video_payload_type_; 65 rtc::scoped_ptr<RtpDepacketizer> depacketizer( 66 RtpDepacketizer::Create(is_vp8 ? kRtpVideoVp8 : kRtpVideoVp9)); 67 RtpDepacketizer::ParsedPayload parsed_payload; 68 if (depacketizer->Parse(&parsed_payload, payload, payload_data_length)) { 69 const int temporal_idx = static_cast<int>( 70 is_vp8 ? parsed_payload.type.Video.codecHeader.VP8.temporalIdx 71 : parsed_payload.type.Video.codecHeader.VP9.temporal_idx); 72 const int spatial_idx = static_cast<int>( 73 is_vp8 ? kNoSpatialIdx 74 : parsed_payload.type.Video.codecHeader.VP9.spatial_idx); 75 if (selected_sl_ >= 0 && spatial_idx == selected_sl_ && 76 parsed_payload.type.Video.codecHeader.VP9.end_of_frame) { 77 // This layer is now the last in the superframe. 78 set_marker_bit = true; 79 } else if ((selected_tl_ >= 0 && temporal_idx != kNoTemporalIdx && 80 temporal_idx > selected_tl_) || 81 (selected_sl_ >= 0 && spatial_idx != kNoSpatialIdx && 82 spatial_idx > selected_sl_)) { 83 // Truncate packet to a padding packet. 84 length = header.headerLength + 1; 85 temp_buffer[0] |= (1 << 5); // P = 1. 86 temp_buffer[1] &= 0x7F; // M = 0. 87 discarded_last_packet_ = true; 88 temp_buffer[header.headerLength] = 1; // One byte of padding. 89 } 90 } else { 91 RTC_NOTREACHED() << "Parse error"; 92 } 93 } 94 95 // We are discarding some of the packets (specifically, whole layers), so 96 // make sure the marker bit is set properly, and that sequence numbers are 97 // continuous. 98 if (set_marker_bit) 99 temp_buffer[1] |= kRtpMarkerBitMask; 100 101 return test::DirectTransport::SendRtp(temp_buffer, length, options); 102 } 103 104 } // namespace test 105 } // namespace webrtc 106