blob: 5ad3f8ce6a3f3527ae436d31dbe3301ae9b31a13 [file] [log] [blame]
/*
* 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/interface/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/interface/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,
uint8_t vp8_video_payload_type,
uint8_t vp9_video_payload_type,
uint8_t tl_discard_threshold,
uint8_t sl_discard_threshold)
: test::DirectTransport(config),
vp8_video_payload_type_(vp8_video_payload_type),
vp9_video_payload_type_(vp9_video_payload_type),
tl_discard_threshold_(tl_discard_threshold),
sl_discard_threshold_(sl_discard_threshold),
current_seq_num_(10000) {
} // TODO(ivica): random seq num?
bool LayerFilteringTransport::SendRtp(const uint8_t* packet, size_t length) {
if (tl_discard_threshold_ == 0 && sl_discard_threshold_ == 0) {
// Nothing to change, forward the packet immediately.
return test::DirectTransport::SendRtp(packet, length);
}
bool set_marker_bit = false;
rtc::scoped_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
RTPHeader header;
parser->Parse(packet, length, &header);
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<RtpDepacketizer> depacketizer(
RtpDepacketizer::Create(is_vp8 ? kRtpVideoVp8 : kRtpVideoVp9));
RtpDepacketizer::ParsedPayload parsed_payload;
if (depacketizer->Parse(&parsed_payload, payload, payload_data_length)) {
const uint8_t temporalIdx =
is_vp8 ? parsed_payload.type.Video.codecHeader.VP8.temporalIdx
: parsed_payload.type.Video.codecHeader.VP9.temporal_idx;
const uint8_t spatialIdx =
is_vp8 ? kNoSpatialIdx
: parsed_payload.type.Video.codecHeader.VP9.spatial_idx;
if (sl_discard_threshold_ > 0 &&
spatialIdx == sl_discard_threshold_ - 1 &&
parsed_payload.type.Video.codecHeader.VP9.end_of_frame) {
// This layer is now the last in the superframe.
set_marker_bit = true;
}
if ((tl_discard_threshold_ > 0 && temporalIdx != kNoTemporalIdx &&
temporalIdx >= tl_discard_threshold_) ||
(sl_discard_threshold_ > 0 && spatialIdx != kNoSpatialIdx &&
spatialIdx >= sl_discard_threshold_)) {
return true; // Discard the packet.
}
} else {
RTC_NOTREACHED() << "Parse error";
}
}
uint8_t temp_buffer[IP_PACKET_SIZE];
memcpy(temp_buffer, packet, length);
// 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;
}
ByteWriter<uint16_t>::WriteBigEndian(&temp_buffer[2], current_seq_num_);
++current_seq_num_; // Increase only if packet not discarded.
return test::DirectTransport::SendRtp(temp_buffer, length);
}
} // namespace test
} // namespace webrtc