/* * 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. */ #include "webrtc/base/checks.h" #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "webrtc/modules/rtp_rtcp/source/byte_io.h" #include "webrtc/modules/rtp_rtcp/source/rtp_format.h" #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" #include "webrtc/test/layer_filtering_transport.h" namespace webrtc { namespace test { LayerFilteringTransport::LayerFilteringTransport( const FakeNetworkPipe::Config& config, Call* send_call, uint8_t vp8_video_payload_type, uint8_t vp9_video_payload_type, int selected_tl, int selected_sl) : test::DirectTransport(config, send_call), vp8_video_payload_type_(vp8_video_payload_type), vp9_video_payload_type_(vp9_video_payload_type), selected_tl_(selected_tl), selected_sl_(selected_sl), discarded_last_packet_(false) {} bool LayerFilteringTransport::DiscardedLastPacket() const { return discarded_last_packet_; } bool LayerFilteringTransport::SendRtp(const uint8_t* packet, size_t length, const PacketOptions& options) { if (selected_tl_ == -1 && selected_sl_ == -1) { // Nothing to change, forward the packet immediately. return test::DirectTransport::SendRtp(packet, length, options); } bool set_marker_bit = false; RtpUtility::RtpHeaderParser parser(packet, length); RTPHeader header; parser.Parse(&header); RTC_DCHECK_LE(length, static_cast(IP_PACKET_SIZE)); uint8_t temp_buffer[IP_PACKET_SIZE]; memcpy(temp_buffer, packet, length); if (header.payloadType == vp8_video_payload_type_ || header.payloadType == vp9_video_payload_type_) { const uint8_t* payload = packet + header.headerLength; RTC_DCHECK_GT(length, header.headerLength); const size_t payload_length = length - header.headerLength; RTC_DCHECK_GT(payload_length, header.paddingLength); const size_t payload_data_length = payload_length - header.paddingLength; const bool is_vp8 = header.payloadType == vp8_video_payload_type_; rtc::scoped_ptr depacketizer( RtpDepacketizer::Create(is_vp8 ? kRtpVideoVp8 : kRtpVideoVp9)); RtpDepacketizer::ParsedPayload parsed_payload; if (depacketizer->Parse(&parsed_payload, payload, payload_data_length)) { const int temporal_idx = static_cast( is_vp8 ? parsed_payload.type.Video.codecHeader.VP8.temporalIdx : parsed_payload.type.Video.codecHeader.VP9.temporal_idx); const int spatial_idx = static_cast( is_vp8 ? kNoSpatialIdx : parsed_payload.type.Video.codecHeader.VP9.spatial_idx); if (selected_sl_ >= 0 && spatial_idx == selected_sl_ && parsed_payload.type.Video.codecHeader.VP9.end_of_frame) { // This layer is now the last in the superframe. set_marker_bit = true; } else if ((selected_tl_ >= 0 && temporal_idx != kNoTemporalIdx && temporal_idx > selected_tl_) || (selected_sl_ >= 0 && spatial_idx != kNoSpatialIdx && spatial_idx > selected_sl_)) { // Truncate packet to a padding packet. length = header.headerLength + 1; temp_buffer[0] |= (1 << 5); // P = 1. temp_buffer[1] &= 0x7F; // M = 0. discarded_last_packet_ = true; temp_buffer[header.headerLength] = 1; // One byte of padding. } } else { RTC_NOTREACHED() << "Parse error"; } } // We are discarding some of the packets (specifically, whole layers), so // make sure the marker bit is set properly, and that sequence numbers are // continuous. if (set_marker_bit) temp_buffer[1] |= kRtpMarkerBitMask; return test::DirectTransport::SendRtp(temp_buffer, length, options); } } // namespace test } // namespace webrtc