blob: 7c3a93362c508b07983285c2f9ed714da25b12a6 [file] [log] [blame]
/*
* Copyright (c) 2017 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 <memory>
#include <string>
#include "modules/include/module_common_types.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "modules/rtp_rtcp/source/rtp_format_video_stereo.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "rtc_base/logging.h"
namespace webrtc {
namespace {
// Write the Stereo header descriptor.
// 0 1 2 3 4 5 6 7 8
// +-+-+-+-+-+-+-+-+-+
// | VideoCodecType | (optional)
// +-+-+-+-+-+-+-+-+-+
// | frame_index | (optional)
// +-+-+-+-+-+-+-+-+-+
// | frame_count | (optional)
// +-+-+-+-+-+-+-+-+-+
// | picture_index | (optional)
// | (16 bits) |
// +-+-+-+-+-+-+-+-+-+
// | HeaderMarker | (mandatory)
// +-+-+-+-+-+-+-+-+-+
constexpr size_t kStereoHeaderLength =
sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint16_t);
constexpr size_t kHeaderMarkerLength = 1;
constexpr uint8_t kHeaderMarkerBit = 0x02;
} // namespace
RtpPacketizerStereo::RtpPacketizerStereo(const RTPVideoHeaderStereo& header,
FrameType frame_type,
size_t max_payload_len,
size_t last_packet_reduction_len)
: header_(header),
max_payload_len_(max_payload_len - kHeaderMarkerLength),
last_packet_reduction_len_(last_packet_reduction_len +
kStereoHeaderLength),
packetizer_(frame_type, max_payload_len_, last_packet_reduction_len_) {}
RtpPacketizerStereo::~RtpPacketizerStereo() {}
size_t RtpPacketizerStereo::SetPayloadData(
const uint8_t* payload_data,
size_t payload_size,
const RTPFragmentationHeader* fragmentation) {
num_packets_remaining_ =
packetizer_.SetPayloadData(payload_data, payload_size, fragmentation);
return num_packets_remaining_;
}
bool RtpPacketizerStereo::NextPacket(RtpPacketToSend* packet) {
if (max_payload_len_ <= last_packet_reduction_len_) {
RTC_LOG(LS_ERROR) << "Payload length not large enough.";
return false;
}
RTC_DCHECK(packet);
if (!packetizer_.NextPacket(packet))
return false;
RTC_DCHECK_GT(num_packets_remaining_, 0);
const bool last_packet = --num_packets_remaining_ == 0;
const size_t header_length = last_packet
? kHeaderMarkerLength + kStereoHeaderLength
: kHeaderMarkerLength;
const uint8_t* payload_ptr = packet->payload().data();
const size_t payload_size = packet->payload_size();
uint8_t* padded_payload_ptr =
packet->SetPayloadSize(header_length + packet->payload_size());
RTC_DCHECK(padded_payload_ptr);
padded_payload_ptr += payload_size;
if (last_packet) {
ByteWriter<uint8_t>::WriteBigEndian(
padded_payload_ptr,
static_cast<uint8_t>(header_.associated_codec_type));
padded_payload_ptr += sizeof(uint8_t);
ByteWriter<uint8_t>::WriteBigEndian(padded_payload_ptr,
header_.indices.frame_index);
padded_payload_ptr += sizeof(uint8_t);
ByteWriter<uint8_t>::WriteBigEndian(padded_payload_ptr,
header_.indices.frame_count);
padded_payload_ptr += sizeof(uint8_t);
ByteWriter<uint16_t>::WriteBigEndian(padded_payload_ptr,
header_.indices.picture_index);
padded_payload_ptr += sizeof(uint16_t);
RTC_DCHECK_EQ(payload_size + kStereoHeaderLength,
padded_payload_ptr - payload_ptr);
}
padded_payload_ptr[0] = last_packet ? kHeaderMarkerBit : 0;
return true;
}
std::string RtpPacketizerStereo::ToString() {
return "RtpPacketizerStereo";
}
RtpDepacketizerStereo::~RtpDepacketizerStereo() {}
bool RtpDepacketizerStereo::Parse(ParsedPayload* parsed_payload,
const uint8_t* payload_data,
size_t payload_data_length) {
RTC_DCHECK(parsed_payload);
if (payload_data_length == 0) {
RTC_LOG(LS_ERROR) << "Empty payload.";
return false;
}
uint8_t header_marker = payload_data[payload_data_length - 1];
--payload_data_length;
const bool last_packet = (header_marker & kHeaderMarkerBit) != 0;
if (last_packet) {
if (payload_data_length <= kStereoHeaderLength) {
RTC_LOG(LS_WARNING) << "Payload not large enough.";
return false;
}
size_t offset = payload_data_length - kStereoHeaderLength;
uint8_t associated_codec_type =
ByteReader<uint8_t>::ReadBigEndian(&payload_data[offset]);
switch (associated_codec_type) {
case kRtpVideoVp8:
case kRtpVideoVp9:
case kRtpVideoH264:
break;
default:
RTC_LOG(LS_WARNING) << "Unexpected codec type.";
return false;
}
parsed_payload->type.Video.codecHeader.stereo.associated_codec_type =
static_cast<RtpVideoCodecTypes>(associated_codec_type);
offset += sizeof(uint8_t);
parsed_payload->type.Video.codecHeader.stereo.indices.frame_index =
ByteReader<uint8_t>::ReadBigEndian(&payload_data[offset]);
offset += sizeof(uint8_t);
parsed_payload->type.Video.codecHeader.stereo.indices.frame_count =
ByteReader<uint8_t>::ReadBigEndian(&payload_data[offset]);
offset += sizeof(uint8_t);
parsed_payload->type.Video.codecHeader.stereo.indices.picture_index =
ByteReader<uint16_t>::ReadBigEndian(&payload_data[offset]);
RTC_DCHECK_EQ(payload_data_length, offset + sizeof(uint16_t));
payload_data_length -= kStereoHeaderLength;
}
if (!depacketizer_.Parse(parsed_payload, payload_data, payload_data_length))
return false;
parsed_payload->type.Video.codec = kRtpVideoStereo;
return true;
}
} // namespace webrtc