Make RTPSender/RTPReceiver generic.
Changes include, 1) Introduce class RtpPacketizerGeneric & RtpDePacketizerGeneric. 2) Introduce class RtpDepacketizerVp8. 3) Make RTPSenderVideo::SendH264 generic and used by all packetizers. 4) Move codec specific functions from RTPSenderVideo/RTPReceiverVideo to RtpPacketizer/RtpDePacketizer sub-classes. R=pbos@webrtc.org, stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/26399004 Patch from Changbin Shao <changbin.shao@intel.com>. git-svn-id: http://webrtc.googlecode.com/svn/trunk@7163 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
6071b0636d
commit
b5e6bfc76a
@ -85,6 +85,7 @@ source_set("rtp_rtcp") {
|
|||||||
"source/rtp_format_h264.h",
|
"source/rtp_format_h264.h",
|
||||||
"source/rtp_format_vp8.cc",
|
"source/rtp_format_vp8.cc",
|
||||||
"source/rtp_format_vp8.h",
|
"source/rtp_format_vp8.h",
|
||||||
|
"source/rtp_format_video_generic.cc",
|
||||||
"source/rtp_format_video_generic.h",
|
"source/rtp_format_video_generic.h",
|
||||||
"source/vp8_partition_aggregator.cc",
|
"source/vp8_partition_aggregator.cc",
|
||||||
"source/vp8_partition_aggregator.h",
|
"source/vp8_partition_aggregator.h",
|
||||||
|
@ -63,6 +63,11 @@ enum RTPAliveType
|
|||||||
kRtpAlive = 2
|
kRtpAlive = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ProtectionType {
|
||||||
|
kUnprotectedPacket,
|
||||||
|
kProtectedPacket
|
||||||
|
};
|
||||||
|
|
||||||
enum StorageType {
|
enum StorageType {
|
||||||
kDontStore,
|
kDontStore,
|
||||||
kDontRetransmit,
|
kDontRetransmit,
|
||||||
|
@ -11,16 +11,23 @@
|
|||||||
#include "webrtc/modules/rtp_rtcp/source/rtp_format.h"
|
#include "webrtc/modules/rtp_rtcp/source/rtp_format.h"
|
||||||
|
|
||||||
#include "webrtc/modules/rtp_rtcp/source/rtp_format_h264.h"
|
#include "webrtc/modules/rtp_rtcp/source/rtp_format_h264.h"
|
||||||
|
#include "webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h"
|
||||||
|
#include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
RtpPacketizer* RtpPacketizer::Create(RtpVideoCodecTypes type,
|
RtpPacketizer* RtpPacketizer::Create(RtpVideoCodecTypes type,
|
||||||
size_t max_payload_len) {
|
size_t max_payload_len,
|
||||||
|
const RTPVideoTypeHeader* rtp_type_header,
|
||||||
|
FrameType frame_type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case kRtpVideoH264:
|
case kRtpVideoH264:
|
||||||
return new RtpPacketizerH264(max_payload_len);
|
return new RtpPacketizerH264(frame_type, max_payload_len);
|
||||||
case kRtpVideoNone:
|
|
||||||
case kRtpVideoGeneric:
|
|
||||||
case kRtpVideoVp8:
|
case kRtpVideoVp8:
|
||||||
|
assert(rtp_type_header != NULL);
|
||||||
|
return new RtpPacketizerVp8(rtp_type_header->VP8, max_payload_len);
|
||||||
|
case kRtpVideoGeneric:
|
||||||
|
return new RtpPacketizerGeneric(frame_type, max_payload_len);
|
||||||
|
case kRtpVideoNone:
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -31,9 +38,11 @@ RtpDepacketizer* RtpDepacketizer::Create(RtpVideoCodecTypes type,
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case kRtpVideoH264:
|
case kRtpVideoH264:
|
||||||
return new RtpDepacketizerH264(callback);
|
return new RtpDepacketizerH264(callback);
|
||||||
case kRtpVideoNone:
|
|
||||||
case kRtpVideoGeneric:
|
|
||||||
case kRtpVideoVp8:
|
case kRtpVideoVp8:
|
||||||
|
return new RtpDepacketizerVp8(callback);
|
||||||
|
case kRtpVideoGeneric:
|
||||||
|
return new RtpDepacketizerGeneric(callback);
|
||||||
|
case kRtpVideoNone:
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H_
|
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H_
|
||||||
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H_
|
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "webrtc/base/constructormagic.h"
|
#include "webrtc/base/constructormagic.h"
|
||||||
#include "webrtc/modules/interface/module_common_types.h"
|
#include "webrtc/modules/interface/module_common_types.h"
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
|
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
|
||||||
@ -19,7 +21,10 @@ namespace webrtc {
|
|||||||
|
|
||||||
class RtpPacketizer {
|
class RtpPacketizer {
|
||||||
public:
|
public:
|
||||||
static RtpPacketizer* Create(RtpVideoCodecTypes type, size_t max_payload_len);
|
static RtpPacketizer* Create(RtpVideoCodecTypes type,
|
||||||
|
size_t max_payload_len,
|
||||||
|
const RTPVideoTypeHeader* rtp_type_header,
|
||||||
|
FrameType frame_type);
|
||||||
|
|
||||||
virtual ~RtpPacketizer() {}
|
virtual ~RtpPacketizer() {}
|
||||||
|
|
||||||
@ -37,6 +42,12 @@ class RtpPacketizer {
|
|||||||
virtual bool NextPacket(uint8_t* buffer,
|
virtual bool NextPacket(uint8_t* buffer,
|
||||||
size_t* bytes_to_send,
|
size_t* bytes_to_send,
|
||||||
bool* last_packet) = 0;
|
bool* last_packet) = 0;
|
||||||
|
|
||||||
|
virtual ProtectionType GetProtectionType() = 0;
|
||||||
|
|
||||||
|
virtual StorageType GetStorageType(uint32_t retransmission_settings) = 0;
|
||||||
|
|
||||||
|
virtual std::string ToString() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RtpDepacketizer {
|
class RtpDepacketizer {
|
||||||
|
@ -94,8 +94,12 @@ void ParseFuaNalu(WebRtcRTPHeader* rtp_header,
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
RtpPacketizerH264::RtpPacketizerH264(size_t max_payload_len)
|
RtpPacketizerH264::RtpPacketizerH264(FrameType frame_type,
|
||||||
: payload_data_(NULL), payload_size_(0), max_payload_len_(max_payload_len) {
|
size_t max_payload_len)
|
||||||
|
: payload_data_(NULL),
|
||||||
|
payload_size_(0),
|
||||||
|
max_payload_len_(max_payload_len),
|
||||||
|
frame_type_(frame_type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
RtpPacketizerH264::~RtpPacketizerH264() {
|
RtpPacketizerH264::~RtpPacketizerH264() {
|
||||||
@ -272,6 +276,20 @@ void RtpPacketizerH264::NextFragmentPacket(uint8_t* buffer,
|
|||||||
packets_.pop();
|
packets_.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProtectionType RtpPacketizerH264::GetProtectionType() {
|
||||||
|
return (frame_type_ == kVideoFrameKey) ? kProtectedPacket
|
||||||
|
: kUnprotectedPacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageType RtpPacketizerH264::GetStorageType(
|
||||||
|
uint32_t retransmission_settings) {
|
||||||
|
return kAllowRetransmission;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RtpPacketizerH264::ToString() {
|
||||||
|
return "RtpPacketizerH264";
|
||||||
|
}
|
||||||
|
|
||||||
RtpDepacketizerH264::RtpDepacketizerH264(RtpData* const callback)
|
RtpDepacketizerH264::RtpDepacketizerH264(RtpData* const callback)
|
||||||
: callback_(callback) {
|
: callback_(callback) {
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ class RtpPacketizerH264 : public RtpPacketizer {
|
|||||||
public:
|
public:
|
||||||
// Initialize with payload from encoder.
|
// Initialize with payload from encoder.
|
||||||
// The payload_data must be exactly one encoded H264 frame.
|
// The payload_data must be exactly one encoded H264 frame.
|
||||||
explicit RtpPacketizerH264(size_t max_payload_len);
|
RtpPacketizerH264(FrameType frame_type, size_t max_payload_len);
|
||||||
|
|
||||||
virtual ~RtpPacketizerH264();
|
virtual ~RtpPacketizerH264();
|
||||||
|
|
||||||
@ -41,6 +41,12 @@ class RtpPacketizerH264 : public RtpPacketizer {
|
|||||||
size_t* bytes_to_send,
|
size_t* bytes_to_send,
|
||||||
bool* last_packet) OVERRIDE;
|
bool* last_packet) OVERRIDE;
|
||||||
|
|
||||||
|
virtual ProtectionType GetProtectionType() OVERRIDE;
|
||||||
|
|
||||||
|
virtual StorageType GetStorageType(uint32_t retrasmission_settings) OVERRIDE;
|
||||||
|
|
||||||
|
virtual std::string ToString() OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Packet {
|
struct Packet {
|
||||||
Packet(size_t offset,
|
Packet(size_t offset,
|
||||||
@ -78,6 +84,7 @@ class RtpPacketizerH264 : public RtpPacketizer {
|
|||||||
const size_t max_payload_len_;
|
const size_t max_payload_len_;
|
||||||
RTPFragmentationHeader fragmentation_;
|
RTPFragmentationHeader fragmentation_;
|
||||||
PacketQueue packets_;
|
PacketQueue packets_;
|
||||||
|
FrameType frame_type_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(RtpPacketizerH264);
|
DISALLOW_COPY_AND_ASSIGN(RtpPacketizerH264);
|
||||||
};
|
};
|
||||||
|
@ -88,8 +88,8 @@ void TestFua(size_t frame_size,
|
|||||||
fragmentation.VerifyAndAllocateFragmentationHeader(1);
|
fragmentation.VerifyAndAllocateFragmentationHeader(1);
|
||||||
fragmentation.fragmentationOffset[0] = 0;
|
fragmentation.fragmentationOffset[0] = 0;
|
||||||
fragmentation.fragmentationLength[0] = frame_size;
|
fragmentation.fragmentationLength[0] = frame_size;
|
||||||
scoped_ptr<RtpPacketizer> packetizer(
|
scoped_ptr<RtpPacketizer> packetizer(RtpPacketizer::Create(
|
||||||
RtpPacketizer::Create(kRtpVideoH264, max_payload_size));
|
kRtpVideoH264, max_payload_size, NULL, kFrameEmpty));
|
||||||
packetizer->SetPayloadData(frame.get(), frame_size, &fragmentation);
|
packetizer->SetPayloadData(frame.get(), frame_size, &fragmentation);
|
||||||
|
|
||||||
scoped_ptr<uint8_t[]> packet(new uint8_t[max_payload_size]);
|
scoped_ptr<uint8_t[]> packet(new uint8_t[max_payload_size]);
|
||||||
@ -163,7 +163,7 @@ TEST(RtpPacketizerH264Test, TestSingleNalu) {
|
|||||||
fragmentation.fragmentationOffset[0] = 0;
|
fragmentation.fragmentationOffset[0] = 0;
|
||||||
fragmentation.fragmentationLength[0] = sizeof(frame);
|
fragmentation.fragmentationLength[0] = sizeof(frame);
|
||||||
scoped_ptr<RtpPacketizer> packetizer(
|
scoped_ptr<RtpPacketizer> packetizer(
|
||||||
RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize));
|
RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kFrameEmpty));
|
||||||
packetizer->SetPayloadData(frame, sizeof(frame), &fragmentation);
|
packetizer->SetPayloadData(frame, sizeof(frame), &fragmentation);
|
||||||
uint8_t packet[kMaxPayloadSize] = {0};
|
uint8_t packet[kMaxPayloadSize] = {0};
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
@ -192,7 +192,7 @@ TEST(RtpPacketizerH264Test, TestSingleNaluTwoPackets) {
|
|||||||
frame[fragmentation.fragmentationOffset[1]] = 0x01;
|
frame[fragmentation.fragmentationOffset[1]] = 0x01;
|
||||||
|
|
||||||
scoped_ptr<RtpPacketizer> packetizer(
|
scoped_ptr<RtpPacketizer> packetizer(
|
||||||
RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize));
|
RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kFrameEmpty));
|
||||||
packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
|
packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
|
||||||
|
|
||||||
uint8_t packet[kMaxPayloadSize] = {0};
|
uint8_t packet[kMaxPayloadSize] = {0};
|
||||||
@ -229,7 +229,7 @@ TEST(RtpPacketizerH264Test, TestStapA) {
|
|||||||
fragmentation.fragmentationLength[2] =
|
fragmentation.fragmentationLength[2] =
|
||||||
kNalHeaderSize + kFrameSize - kPayloadOffset;
|
kNalHeaderSize + kFrameSize - kPayloadOffset;
|
||||||
scoped_ptr<RtpPacketizer> packetizer(
|
scoped_ptr<RtpPacketizer> packetizer(
|
||||||
RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize));
|
RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kFrameEmpty));
|
||||||
packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
|
packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
|
||||||
|
|
||||||
uint8_t packet[kMaxPayloadSize] = {0};
|
uint8_t packet[kMaxPayloadSize] = {0};
|
||||||
@ -264,7 +264,7 @@ TEST(RtpPacketizerH264Test, TestTooSmallForStapAHeaders) {
|
|||||||
fragmentation.fragmentationLength[2] =
|
fragmentation.fragmentationLength[2] =
|
||||||
kNalHeaderSize + kFrameSize - kPayloadOffset;
|
kNalHeaderSize + kFrameSize - kPayloadOffset;
|
||||||
scoped_ptr<RtpPacketizer> packetizer(
|
scoped_ptr<RtpPacketizer> packetizer(
|
||||||
RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize));
|
RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kFrameEmpty));
|
||||||
packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
|
packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
|
||||||
|
|
||||||
uint8_t packet[kMaxPayloadSize] = {0};
|
uint8_t packet[kMaxPayloadSize] = {0};
|
||||||
@ -312,7 +312,7 @@ TEST(RtpPacketizerH264Test, TestMixedStapA_FUA) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
scoped_ptr<RtpPacketizer> packetizer(
|
scoped_ptr<RtpPacketizer> packetizer(
|
||||||
RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize));
|
RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kFrameEmpty));
|
||||||
packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
|
packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
|
||||||
|
|
||||||
// First expecting two FU-A packets.
|
// First expecting two FU-A packets.
|
||||||
|
112
webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc
Normal file
112
webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 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 <string>
|
||||||
|
|
||||||
|
#include "webrtc/modules/interface/module_common_types.h"
|
||||||
|
#include "webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
static const size_t kGenericHeaderLength = 1;
|
||||||
|
|
||||||
|
RtpPacketizerGeneric::RtpPacketizerGeneric(FrameType frame_type,
|
||||||
|
size_t max_payload_len)
|
||||||
|
: payload_data_(NULL),
|
||||||
|
payload_size_(0),
|
||||||
|
max_payload_len_(max_payload_len - kGenericHeaderLength),
|
||||||
|
frame_type_(frame_type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
RtpPacketizerGeneric::~RtpPacketizerGeneric() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtpPacketizerGeneric::SetPayloadData(
|
||||||
|
const uint8_t* payload_data,
|
||||||
|
size_t payload_size,
|
||||||
|
const RTPFragmentationHeader* fragmentation) {
|
||||||
|
payload_data_ = payload_data;
|
||||||
|
payload_size_ = payload_size;
|
||||||
|
|
||||||
|
// Fragment packets more evenly by splitting the payload up evenly.
|
||||||
|
uint32_t num_packets =
|
||||||
|
(payload_size_ + max_payload_len_ - 1) / max_payload_len_;
|
||||||
|
payload_length_ = (payload_size_ + num_packets - 1) / num_packets;
|
||||||
|
assert(payload_length_ <= max_payload_len_);
|
||||||
|
|
||||||
|
generic_header_ = RtpFormatVideoGeneric::kFirstPacketBit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtpPacketizerGeneric::NextPacket(uint8_t* buffer,
|
||||||
|
size_t* bytes_to_send,
|
||||||
|
bool* last_packet) {
|
||||||
|
if (payload_size_ < payload_length_) {
|
||||||
|
payload_length_ = payload_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
payload_size_ -= payload_length_;
|
||||||
|
*bytes_to_send = payload_length_ + kGenericHeaderLength;
|
||||||
|
assert(payload_length_ <= max_payload_len_);
|
||||||
|
|
||||||
|
uint8_t* out_ptr = buffer;
|
||||||
|
// Put generic header in packet
|
||||||
|
if (frame_type_ == kVideoFrameKey) {
|
||||||
|
generic_header_ |= RtpFormatVideoGeneric::kKeyFrameBit;
|
||||||
|
}
|
||||||
|
*out_ptr++ = generic_header_;
|
||||||
|
// Remove first-packet bit, following packets are intermediate
|
||||||
|
generic_header_ &= ~RtpFormatVideoGeneric::kFirstPacketBit;
|
||||||
|
|
||||||
|
// Put payload in packet
|
||||||
|
memcpy(out_ptr, payload_data_, payload_length_);
|
||||||
|
payload_data_ += payload_length_;
|
||||||
|
|
||||||
|
*last_packet = payload_size_ <= 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtectionType RtpPacketizerGeneric::GetProtectionType() {
|
||||||
|
return kProtectedPacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageType RtpPacketizerGeneric::GetStorageType(
|
||||||
|
uint32_t retransmission_settings) {
|
||||||
|
return kAllowRetransmission;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RtpPacketizerGeneric::ToString() {
|
||||||
|
return "RtpPacketizerGeneric";
|
||||||
|
}
|
||||||
|
|
||||||
|
RtpDepacketizerGeneric::RtpDepacketizerGeneric(RtpData* const callback)
|
||||||
|
: callback_(callback) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtpDepacketizerGeneric::Parse(WebRtcRTPHeader* rtp_header,
|
||||||
|
const uint8_t* payload_data,
|
||||||
|
size_t payload_data_length) {
|
||||||
|
uint8_t generic_header = *payload_data++;
|
||||||
|
--payload_data_length;
|
||||||
|
|
||||||
|
rtp_header->frameType =
|
||||||
|
((generic_header & RtpFormatVideoGeneric::kKeyFrameBit) != 0)
|
||||||
|
? kVideoFrameKey
|
||||||
|
: kVideoFrameDelta;
|
||||||
|
rtp_header->type.Video.isFirstPacket =
|
||||||
|
(generic_header & RtpFormatVideoGeneric::kFirstPacketBit) != 0;
|
||||||
|
|
||||||
|
if (callback_->OnReceivedPayloadData(
|
||||||
|
payload_data, payload_data_length, rtp_header) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace webrtc
|
@ -10,13 +10,72 @@
|
|||||||
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_
|
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_
|
||||||
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_
|
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_
|
||||||
|
|
||||||
|
#include "webrtc/common_types.h"
|
||||||
|
#include "webrtc/modules/rtp_rtcp/source/rtp_format.h"
|
||||||
#include "webrtc/typedefs.h"
|
#include "webrtc/typedefs.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
namespace RtpFormatVideoGeneric {
|
namespace RtpFormatVideoGeneric {
|
||||||
static const uint8_t kKeyFrameBit = 0x01;
|
static const uint8_t kKeyFrameBit = 0x01;
|
||||||
static const uint8_t kFirstPacketBit = 0x02;
|
static const uint8_t kFirstPacketBit = 0x02;
|
||||||
} // namespace RtpFormatVideoGeneric
|
} // namespace RtpFormatVideoGeneric
|
||||||
} // namespace webrtc
|
|
||||||
|
|
||||||
|
class RtpPacketizerGeneric : public RtpPacketizer {
|
||||||
|
public:
|
||||||
|
// Initialize with payload from encoder.
|
||||||
|
// The payload_data must be exactly one encoded generic frame.
|
||||||
|
RtpPacketizerGeneric(FrameType frametype, size_t max_payload_len);
|
||||||
|
|
||||||
|
virtual ~RtpPacketizerGeneric();
|
||||||
|
|
||||||
|
virtual void SetPayloadData(
|
||||||
|
const uint8_t* payload_data,
|
||||||
|
size_t payload_size,
|
||||||
|
const RTPFragmentationHeader* fragmentation) OVERRIDE;
|
||||||
|
|
||||||
|
// Get the next payload with generic payload header.
|
||||||
|
// buffer is a pointer to where the output will be written.
|
||||||
|
// bytes_to_send is an output variable that will contain number of bytes
|
||||||
|
// written to buffer. The parameter last_packet is true for the last packet of
|
||||||
|
// the frame, false otherwise (i.e., call the function again to get the
|
||||||
|
// next packet).
|
||||||
|
// Returns true on success or false if there was no payload to packetize.
|
||||||
|
virtual bool NextPacket(uint8_t* buffer,
|
||||||
|
size_t* bytes_to_send,
|
||||||
|
bool* last_packet) OVERRIDE;
|
||||||
|
|
||||||
|
virtual ProtectionType GetProtectionType() OVERRIDE;
|
||||||
|
|
||||||
|
virtual StorageType GetStorageType(uint32_t retransmission_settings) OVERRIDE;
|
||||||
|
|
||||||
|
virtual std::string ToString() OVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint8_t* payload_data_;
|
||||||
|
size_t payload_size_;
|
||||||
|
const size_t max_payload_len_;
|
||||||
|
FrameType frame_type_;
|
||||||
|
uint32_t payload_length_;
|
||||||
|
uint8_t generic_header_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(RtpPacketizerGeneric);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Depacketizer for generic codec.
|
||||||
|
class RtpDepacketizerGeneric : public RtpDepacketizer {
|
||||||
|
public:
|
||||||
|
explicit RtpDepacketizerGeneric(RtpData* const callback);
|
||||||
|
|
||||||
|
virtual ~RtpDepacketizerGeneric() {}
|
||||||
|
|
||||||
|
virtual bool Parse(WebRtcRTPHeader* rtp_header,
|
||||||
|
const uint8_t* payload_data,
|
||||||
|
size_t payload_data_length) OVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RtpData* const callback_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(RtpDepacketizerGeneric);
|
||||||
|
};
|
||||||
|
} // namespace webrtc
|
||||||
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_
|
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_
|
||||||
|
@ -10,11 +10,12 @@
|
|||||||
|
|
||||||
#include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h"
|
#include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h"
|
||||||
|
|
||||||
#include <assert.h> // assert
|
#include <assert.h> // assert
|
||||||
#include <string.h> // memcpy
|
#include <string.h> // memcpy
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
|
||||||
#include "webrtc/modules/rtp_rtcp/source/vp8_partition_aggregator.h"
|
#include "webrtc/modules/rtp_rtcp/source/vp8_partition_aggregator.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@ -107,6 +108,29 @@ bool RtpPacketizerVp8::NextPacket(uint8_t* buffer,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProtectionType RtpPacketizerVp8::GetProtectionType() {
|
||||||
|
bool protect =
|
||||||
|
hdr_info_.temporalIdx == 0 || hdr_info_.temporalIdx == kNoTemporalIdx;
|
||||||
|
return protect ? kProtectedPacket : kUnprotectedPacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageType RtpPacketizerVp8::GetStorageType(uint32_t retransmission_settings) {
|
||||||
|
StorageType storage = kAllowRetransmission;
|
||||||
|
if (hdr_info_.temporalIdx == 0 &&
|
||||||
|
!(retransmission_settings & kRetransmitBaseLayer)) {
|
||||||
|
storage = kDontRetransmit;
|
||||||
|
} else if (hdr_info_.temporalIdx != kNoTemporalIdx &&
|
||||||
|
hdr_info_.temporalIdx > 0 &&
|
||||||
|
!(retransmission_settings & kRetransmitHigherLayers)) {
|
||||||
|
storage = kDontRetransmit;
|
||||||
|
}
|
||||||
|
return storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RtpPacketizerVp8::ToString() {
|
||||||
|
return "RtpPacketizerVp8";
|
||||||
|
}
|
||||||
|
|
||||||
int RtpPacketizerVp8::CalcNextSize(int max_payload_len,
|
int RtpPacketizerVp8::CalcNextSize(int max_payload_len,
|
||||||
int remaining_bytes,
|
int remaining_bytes,
|
||||||
bool split_payload) const {
|
bool split_payload) const {
|
||||||
@ -123,17 +147,17 @@ int RtpPacketizerVp8::CalcNextSize(int max_payload_len,
|
|||||||
// Number of fragments for remaining_bytes:
|
// Number of fragments for remaining_bytes:
|
||||||
int num_frags = remaining_bytes / max_payload_len + 1;
|
int num_frags = remaining_bytes / max_payload_len + 1;
|
||||||
// Number of bytes in this fragment:
|
// Number of bytes in this fragment:
|
||||||
return static_cast<int>(static_cast<double>(remaining_bytes)
|
return static_cast<int>(static_cast<double>(remaining_bytes) / num_frags +
|
||||||
/ num_frags + 0.5);
|
0.5);
|
||||||
} else {
|
} else {
|
||||||
return max_payload_len >= remaining_bytes ? remaining_bytes
|
return max_payload_len >= remaining_bytes ? remaining_bytes
|
||||||
: max_payload_len;
|
: max_payload_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int RtpPacketizerVp8::GeneratePackets() {
|
int RtpPacketizerVp8::GeneratePackets() {
|
||||||
if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_
|
if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ +
|
||||||
+ PayloadDescriptorExtraLength() + 1) {
|
PayloadDescriptorExtraLength() + 1) {
|
||||||
// The provided payload length is not long enough for the payload
|
// The provided payload length is not long enough for the payload
|
||||||
// descriptor and one payload byte. Return an error.
|
// descriptor and one payload byte. Return an error.
|
||||||
return -1;
|
return -1;
|
||||||
@ -143,16 +167,18 @@ int RtpPacketizerVp8::GeneratePackets() {
|
|||||||
bool beginning = true;
|
bool beginning = true;
|
||||||
int part_ix = 0;
|
int part_ix = 0;
|
||||||
while (total_bytes_processed < payload_size_) {
|
while (total_bytes_processed < payload_size_) {
|
||||||
int packet_bytes = 0; // How much data to send in this packet.
|
int packet_bytes = 0; // How much data to send in this packet.
|
||||||
bool split_payload = true; // Splitting of partitions is initially allowed.
|
bool split_payload = true; // Splitting of partitions is initially allowed.
|
||||||
int remaining_in_partition = part_info_.fragmentationOffset[part_ix] -
|
int remaining_in_partition = part_info_.fragmentationOffset[part_ix] -
|
||||||
total_bytes_processed + part_info_.fragmentationLength[part_ix];
|
total_bytes_processed +
|
||||||
int rem_payload_len = max_payload_len_ -
|
part_info_.fragmentationLength[part_ix];
|
||||||
|
int rem_payload_len =
|
||||||
|
max_payload_len_ -
|
||||||
(vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength());
|
(vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength());
|
||||||
int first_partition_in_packet = part_ix;
|
int first_partition_in_packet = part_ix;
|
||||||
|
|
||||||
while (int next_size = CalcNextSize(rem_payload_len, remaining_in_partition,
|
while (int next_size = CalcNextSize(
|
||||||
split_payload)) {
|
rem_payload_len, remaining_in_partition, split_payload)) {
|
||||||
packet_bytes += next_size;
|
packet_bytes += next_size;
|
||||||
rem_payload_len -= next_size;
|
rem_payload_len -= next_size;
|
||||||
remaining_in_partition -= next_size;
|
remaining_in_partition -= next_size;
|
||||||
@ -165,7 +191,7 @@ int RtpPacketizerVp8::GeneratePackets() {
|
|||||||
// with an intact partition (indicated by first_fragment_ == true).
|
// with an intact partition (indicated by first_fragment_ == true).
|
||||||
if (part_ix + 1 < num_partitions_ &&
|
if (part_ix + 1 < num_partitions_ &&
|
||||||
((aggr_mode_ == kAggrFragments) ||
|
((aggr_mode_ == kAggrFragments) ||
|
||||||
(aggr_mode_ == kAggrPartitions && start_on_new_fragment))) {
|
(aggr_mode_ == kAggrPartitions && start_on_new_fragment))) {
|
||||||
assert(part_ix < num_partitions_);
|
assert(part_ix < num_partitions_);
|
||||||
remaining_in_partition = part_info_.fragmentationLength[++part_ix];
|
remaining_in_partition = part_info_.fragmentationLength[++part_ix];
|
||||||
// Disallow splitting unless kAggrFragments. In kAggrPartitions,
|
// Disallow splitting unless kAggrFragments. In kAggrPartitions,
|
||||||
@ -181,7 +207,9 @@ int RtpPacketizerVp8::GeneratePackets() {
|
|||||||
}
|
}
|
||||||
assert(packet_bytes > 0);
|
assert(packet_bytes > 0);
|
||||||
|
|
||||||
QueuePacket(total_bytes_processed, packet_bytes, first_partition_in_packet,
|
QueuePacket(total_bytes_processed,
|
||||||
|
packet_bytes,
|
||||||
|
first_partition_in_packet,
|
||||||
start_on_new_fragment);
|
start_on_new_fragment);
|
||||||
total_bytes_processed += packet_bytes;
|
total_bytes_processed += packet_bytes;
|
||||||
start_on_new_fragment = (remaining_in_partition == 0);
|
start_on_new_fragment = (remaining_in_partition == 0);
|
||||||
@ -193,15 +221,15 @@ int RtpPacketizerVp8::GeneratePackets() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int RtpPacketizerVp8::GeneratePacketsBalancedAggregates() {
|
int RtpPacketizerVp8::GeneratePacketsBalancedAggregates() {
|
||||||
if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_
|
if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ +
|
||||||
+ PayloadDescriptorExtraLength() + 1) {
|
PayloadDescriptorExtraLength() + 1) {
|
||||||
// The provided payload length is not long enough for the payload
|
// The provided payload length is not long enough for the payload
|
||||||
// descriptor and one payload byte. Return an error.
|
// descriptor and one payload byte. Return an error.
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
std::vector<int> partition_decision;
|
std::vector<int> partition_decision;
|
||||||
const int overhead = vp8_fixed_payload_descriptor_bytes_ +
|
const int overhead =
|
||||||
PayloadDescriptorExtraLength();
|
vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength();
|
||||||
const uint32_t max_payload_len = max_payload_len_ - overhead;
|
const uint32_t max_payload_len = max_payload_len_ - overhead;
|
||||||
int min_size, max_size;
|
int min_size, max_size;
|
||||||
AggregateSmallPartitions(&partition_decision, &min_size, &max_size);
|
AggregateSmallPartitions(&partition_decision, &min_size, &max_size);
|
||||||
@ -217,10 +245,11 @@ int RtpPacketizerVp8::GeneratePacketsBalancedAggregates() {
|
|||||||
const int packet_bytes =
|
const int packet_bytes =
|
||||||
(remaining_partition + num_fragments - 1) / num_fragments;
|
(remaining_partition + num_fragments - 1) / num_fragments;
|
||||||
for (int n = 0; n < num_fragments; ++n) {
|
for (int n = 0; n < num_fragments; ++n) {
|
||||||
const int this_packet_bytes = packet_bytes < remaining_partition ?
|
const int this_packet_bytes = packet_bytes < remaining_partition
|
||||||
packet_bytes : remaining_partition;
|
? packet_bytes
|
||||||
QueuePacket(total_bytes_processed, this_packet_bytes, part_ix,
|
: remaining_partition;
|
||||||
(n == 0));
|
QueuePacket(
|
||||||
|
total_bytes_processed, this_packet_bytes, part_ix, (n == 0));
|
||||||
remaining_partition -= this_packet_bytes;
|
remaining_partition -= this_packet_bytes;
|
||||||
total_bytes_processed += this_packet_bytes;
|
total_bytes_processed += this_packet_bytes;
|
||||||
if (this_packet_bytes < min_size) {
|
if (this_packet_bytes < min_size) {
|
||||||
@ -237,13 +266,15 @@ int RtpPacketizerVp8::GeneratePacketsBalancedAggregates() {
|
|||||||
const int first_partition_in_packet = part_ix;
|
const int first_partition_in_packet = part_ix;
|
||||||
const int aggregation_index = partition_decision[part_ix];
|
const int aggregation_index = partition_decision[part_ix];
|
||||||
while (static_cast<size_t>(part_ix) < partition_decision.size() &&
|
while (static_cast<size_t>(part_ix) < partition_decision.size() &&
|
||||||
partition_decision[part_ix] == aggregation_index) {
|
partition_decision[part_ix] == aggregation_index) {
|
||||||
// Collect all partitions that were aggregated into the same packet.
|
// Collect all partitions that were aggregated into the same packet.
|
||||||
this_packet_bytes += part_info_.fragmentationLength[part_ix];
|
this_packet_bytes += part_info_.fragmentationLength[part_ix];
|
||||||
++part_ix;
|
++part_ix;
|
||||||
}
|
}
|
||||||
QueuePacket(total_bytes_processed, this_packet_bytes,
|
QueuePacket(total_bytes_processed,
|
||||||
first_partition_in_packet, true);
|
this_packet_bytes,
|
||||||
|
first_partition_in_packet,
|
||||||
|
true);
|
||||||
total_bytes_processed += this_packet_bytes;
|
total_bytes_processed += this_packet_bytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,8 +290,8 @@ void RtpPacketizerVp8::AggregateSmallPartitions(std::vector<int>* partition_vec,
|
|||||||
*max_size = -1;
|
*max_size = -1;
|
||||||
assert(partition_vec);
|
assert(partition_vec);
|
||||||
partition_vec->assign(num_partitions_, -1);
|
partition_vec->assign(num_partitions_, -1);
|
||||||
const int overhead = vp8_fixed_payload_descriptor_bytes_ +
|
const int overhead =
|
||||||
PayloadDescriptorExtraLength();
|
vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength();
|
||||||
const uint32_t max_payload_len = max_payload_len_ - overhead;
|
const uint32_t max_payload_len = max_payload_len_ - overhead;
|
||||||
int first_in_set = 0;
|
int first_in_set = 0;
|
||||||
int last_in_set = 0;
|
int last_in_set = 0;
|
||||||
@ -271,12 +302,12 @@ void RtpPacketizerVp8::AggregateSmallPartitions(std::vector<int>* partition_vec,
|
|||||||
// Found start of a set.
|
// Found start of a set.
|
||||||
last_in_set = first_in_set;
|
last_in_set = first_in_set;
|
||||||
while (last_in_set + 1 < num_partitions_ &&
|
while (last_in_set + 1 < num_partitions_ &&
|
||||||
part_info_.fragmentationLength[last_in_set + 1] < max_payload_len) {
|
part_info_.fragmentationLength[last_in_set + 1] <
|
||||||
|
max_payload_len) {
|
||||||
++last_in_set;
|
++last_in_set;
|
||||||
}
|
}
|
||||||
// Found end of a set. Run optimized aggregator. It is ok if start == end.
|
// Found end of a set. Run optimized aggregator. It is ok if start == end.
|
||||||
Vp8PartitionAggregator aggregator(part_info_, first_in_set,
|
Vp8PartitionAggregator aggregator(part_info_, first_in_set, last_in_set);
|
||||||
last_in_set);
|
|
||||||
if (*min_size >= 0 && *max_size >= 0) {
|
if (*min_size >= 0 && *max_size >= 0) {
|
||||||
aggregator.SetPriorMinMax(*min_size, *max_size);
|
aggregator.SetPriorMinMax(*min_size, *max_size);
|
||||||
}
|
}
|
||||||
@ -328,19 +359,23 @@ int RtpPacketizerVp8::WriteHeaderAndPayload(const InfoStruct& packet_info,
|
|||||||
|
|
||||||
assert(packet_info.size > 0);
|
assert(packet_info.size > 0);
|
||||||
buffer[0] = 0;
|
buffer[0] = 0;
|
||||||
if (XFieldPresent()) buffer[0] |= kXBit;
|
if (XFieldPresent())
|
||||||
if (hdr_info_.nonReference) buffer[0] |= kNBit;
|
buffer[0] |= kXBit;
|
||||||
if (packet_info.first_fragment) buffer[0] |= kSBit;
|
if (hdr_info_.nonReference)
|
||||||
|
buffer[0] |= kNBit;
|
||||||
|
if (packet_info.first_fragment)
|
||||||
|
buffer[0] |= kSBit;
|
||||||
buffer[0] |= (packet_info.first_partition_ix & kPartIdField);
|
buffer[0] |= (packet_info.first_partition_ix & kPartIdField);
|
||||||
|
|
||||||
const int extension_length = WriteExtensionFields(buffer, buffer_length);
|
const int extension_length = WriteExtensionFields(buffer, buffer_length);
|
||||||
|
|
||||||
memcpy(&buffer[vp8_fixed_payload_descriptor_bytes_ + extension_length],
|
memcpy(&buffer[vp8_fixed_payload_descriptor_bytes_ + extension_length],
|
||||||
&payload_data_[packet_info.payload_start_pos], packet_info.size);
|
&payload_data_[packet_info.payload_start_pos],
|
||||||
|
packet_info.size);
|
||||||
|
|
||||||
// Return total length of written data.
|
// Return total length of written data.
|
||||||
return packet_info.size + vp8_fixed_payload_descriptor_bytes_
|
return packet_info.size + vp8_fixed_payload_descriptor_bytes_ +
|
||||||
+ extension_length;
|
extension_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RtpPacketizerVp8::WriteExtensionFields(uint8_t* buffer,
|
int RtpPacketizerVp8::WriteExtensionFields(uint8_t* buffer,
|
||||||
@ -351,20 +386,20 @@ int RtpPacketizerVp8::WriteExtensionFields(uint8_t* buffer,
|
|||||||
*x_field = 0;
|
*x_field = 0;
|
||||||
extension_length = 1; // One octet for the X field.
|
extension_length = 1; // One octet for the X field.
|
||||||
if (PictureIdPresent()) {
|
if (PictureIdPresent()) {
|
||||||
if (WritePictureIDFields(x_field, buffer, buffer_length,
|
if (WritePictureIDFields(
|
||||||
&extension_length) < 0) {
|
x_field, buffer, buffer_length, &extension_length) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (TL0PicIdxFieldPresent()) {
|
if (TL0PicIdxFieldPresent()) {
|
||||||
if (WriteTl0PicIdxFields(x_field, buffer, buffer_length,
|
if (WriteTl0PicIdxFields(
|
||||||
&extension_length) < 0) {
|
x_field, buffer, buffer_length, &extension_length) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (TIDFieldPresent() || KeyIdxFieldPresent()) {
|
if (TIDFieldPresent() || KeyIdxFieldPresent()) {
|
||||||
if (WriteTIDAndKeyIdxFields(x_field, buffer, buffer_length,
|
if (WriteTIDAndKeyIdxFields(
|
||||||
&extension_length) < 0) {
|
x_field, buffer, buffer_length, &extension_length) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -380,18 +415,18 @@ int RtpPacketizerVp8::WritePictureIDFields(uint8_t* x_field,
|
|||||||
*x_field |= kIBit;
|
*x_field |= kIBit;
|
||||||
const int pic_id_length = WritePictureID(
|
const int pic_id_length = WritePictureID(
|
||||||
buffer + vp8_fixed_payload_descriptor_bytes_ + *extension_length,
|
buffer + vp8_fixed_payload_descriptor_bytes_ + *extension_length,
|
||||||
buffer_length - vp8_fixed_payload_descriptor_bytes_
|
buffer_length - vp8_fixed_payload_descriptor_bytes_ - *extension_length);
|
||||||
- *extension_length);
|
if (pic_id_length < 0)
|
||||||
if (pic_id_length < 0) return -1;
|
return -1;
|
||||||
*extension_length += pic_id_length;
|
*extension_length += pic_id_length;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RtpPacketizerVp8::WritePictureID(uint8_t* buffer, int buffer_length) const {
|
int RtpPacketizerVp8::WritePictureID(uint8_t* buffer, int buffer_length) const {
|
||||||
const uint16_t pic_id =
|
const uint16_t pic_id = static_cast<uint16_t>(hdr_info_.pictureId);
|
||||||
static_cast<uint16_t> (hdr_info_.pictureId);
|
|
||||||
int picture_id_len = PictureIdLength();
|
int picture_id_len = PictureIdLength();
|
||||||
if (picture_id_len > buffer_length) return -1;
|
if (picture_id_len > buffer_length)
|
||||||
|
return -1;
|
||||||
if (picture_id_len == 2) {
|
if (picture_id_len == 2) {
|
||||||
buffer[0] = 0x80 | ((pic_id >> 8) & 0x7F);
|
buffer[0] = 0x80 | ((pic_id >> 8) & 0x7F);
|
||||||
buffer[1] = pic_id & 0xFF;
|
buffer[1] = pic_id & 0xFF;
|
||||||
@ -405,13 +440,13 @@ int RtpPacketizerVp8::WriteTl0PicIdxFields(uint8_t* x_field,
|
|||||||
uint8_t* buffer,
|
uint8_t* buffer,
|
||||||
int buffer_length,
|
int buffer_length,
|
||||||
int* extension_length) const {
|
int* extension_length) const {
|
||||||
if (buffer_length < vp8_fixed_payload_descriptor_bytes_ + *extension_length
|
if (buffer_length <
|
||||||
+ 1) {
|
vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
*x_field |= kLBit;
|
*x_field |= kLBit;
|
||||||
buffer[vp8_fixed_payload_descriptor_bytes_
|
buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length] =
|
||||||
+ *extension_length] = hdr_info_.tl0PicIdx;
|
hdr_info_.tl0PicIdx;
|
||||||
++*extension_length;
|
++*extension_length;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -420,8 +455,8 @@ int RtpPacketizerVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field,
|
|||||||
uint8_t* buffer,
|
uint8_t* buffer,
|
||||||
int buffer_length,
|
int buffer_length,
|
||||||
int* extension_length) const {
|
int* extension_length) const {
|
||||||
if (buffer_length < vp8_fixed_payload_descriptor_bytes_ + *extension_length
|
if (buffer_length <
|
||||||
+ 1) {
|
vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
uint8_t* data_field =
|
uint8_t* data_field =
|
||||||
@ -443,9 +478,12 @@ int RtpPacketizerVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field,
|
|||||||
|
|
||||||
int RtpPacketizerVp8::PayloadDescriptorExtraLength() const {
|
int RtpPacketizerVp8::PayloadDescriptorExtraLength() const {
|
||||||
int length_bytes = PictureIdLength();
|
int length_bytes = PictureIdLength();
|
||||||
if (TL0PicIdxFieldPresent()) ++length_bytes;
|
if (TL0PicIdxFieldPresent())
|
||||||
if (TIDFieldPresent() || KeyIdxFieldPresent()) ++length_bytes;
|
++length_bytes;
|
||||||
if (length_bytes > 0) ++length_bytes; // Include the extension field.
|
if (TIDFieldPresent() || KeyIdxFieldPresent())
|
||||||
|
++length_bytes;
|
||||||
|
if (length_bytes > 0)
|
||||||
|
++length_bytes; // Include the extension field.
|
||||||
return length_bytes;
|
return length_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,8 +498,8 @@ int RtpPacketizerVp8::PictureIdLength() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool RtpPacketizerVp8::XFieldPresent() const {
|
bool RtpPacketizerVp8::XFieldPresent() const {
|
||||||
return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent()
|
return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent() ||
|
||||||
|| KeyIdxFieldPresent());
|
KeyIdxFieldPresent());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RtpPacketizerVp8::TIDFieldPresent() const {
|
bool RtpPacketizerVp8::TIDFieldPresent() const {
|
||||||
@ -477,4 +515,58 @@ bool RtpPacketizerVp8::KeyIdxFieldPresent() const {
|
|||||||
bool RtpPacketizerVp8::TL0PicIdxFieldPresent() const {
|
bool RtpPacketizerVp8::TL0PicIdxFieldPresent() const {
|
||||||
return (hdr_info_.tl0PicIdx != kNoTl0PicIdx);
|
return (hdr_info_.tl0PicIdx != kNoTl0PicIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RtpDepacketizerVp8::RtpDepacketizerVp8(RtpData* const callback)
|
||||||
|
: callback_(callback) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtpDepacketizerVp8::Parse(WebRtcRTPHeader* rtp_header,
|
||||||
|
const uint8_t* payload_data,
|
||||||
|
size_t payload_data_length) {
|
||||||
|
RtpUtility::RTPPayload parsed_packet;
|
||||||
|
RtpUtility::RTPPayloadParser rtp_payload_parser(
|
||||||
|
kRtpVideoVp8, payload_data, payload_data_length);
|
||||||
|
|
||||||
|
if (!rtp_payload_parser.Parse(parsed_packet))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (parsed_packet.info.VP8.dataLength == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
rtp_header->frameType = (parsed_packet.frameType == RtpUtility::kIFrame)
|
||||||
|
? kVideoFrameKey
|
||||||
|
: kVideoFrameDelta;
|
||||||
|
|
||||||
|
RTPVideoHeaderVP8* to_header = &rtp_header->type.Video.codecHeader.VP8;
|
||||||
|
RtpUtility::RTPPayloadVP8* from_header = &parsed_packet.info.VP8;
|
||||||
|
|
||||||
|
rtp_header->type.Video.isFirstPacket =
|
||||||
|
from_header->beginningOfPartition && (from_header->partitionID == 0);
|
||||||
|
to_header->nonReference = from_header->nonReferenceFrame;
|
||||||
|
to_header->pictureId =
|
||||||
|
from_header->hasPictureID ? from_header->pictureID : kNoPictureId;
|
||||||
|
to_header->tl0PicIdx =
|
||||||
|
from_header->hasTl0PicIdx ? from_header->tl0PicIdx : kNoTl0PicIdx;
|
||||||
|
if (from_header->hasTID) {
|
||||||
|
to_header->temporalIdx = from_header->tID;
|
||||||
|
to_header->layerSync = from_header->layerSync;
|
||||||
|
} else {
|
||||||
|
to_header->temporalIdx = kNoTemporalIdx;
|
||||||
|
to_header->layerSync = false;
|
||||||
|
}
|
||||||
|
to_header->keyIdx = from_header->hasKeyIdx ? from_header->keyIdx : kNoKeyIdx;
|
||||||
|
|
||||||
|
rtp_header->type.Video.width = from_header->frameWidth;
|
||||||
|
rtp_header->type.Video.height = from_header->frameHeight;
|
||||||
|
|
||||||
|
to_header->partitionId = from_header->partitionID;
|
||||||
|
to_header->beginningOfPartition = from_header->beginningOfPartition;
|
||||||
|
|
||||||
|
if (callback_->OnReceivedPayloadData(parsed_packet.info.VP8.data,
|
||||||
|
parsed_packet.info.VP8.dataLength,
|
||||||
|
rtp_header) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -79,6 +79,12 @@ class RtpPacketizerVp8 : public RtpPacketizer {
|
|||||||
size_t* bytes_to_send,
|
size_t* bytes_to_send,
|
||||||
bool* last_packet) OVERRIDE;
|
bool* last_packet) OVERRIDE;
|
||||||
|
|
||||||
|
virtual ProtectionType GetProtectionType() OVERRIDE;
|
||||||
|
|
||||||
|
virtual StorageType GetStorageType(uint32_t retransmission_settings) OVERRIDE;
|
||||||
|
|
||||||
|
virtual std::string ToString() OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int payload_start_pos;
|
int payload_start_pos;
|
||||||
@ -96,19 +102,20 @@ class RtpPacketizerVp8 : public RtpPacketizer {
|
|||||||
static const AggregationMode aggr_modes_[kNumModes];
|
static const AggregationMode aggr_modes_[kNumModes];
|
||||||
static const bool balance_modes_[kNumModes];
|
static const bool balance_modes_[kNumModes];
|
||||||
static const bool separate_first_modes_[kNumModes];
|
static const bool separate_first_modes_[kNumModes];
|
||||||
static const int kXBit = 0x80;
|
static const int kXBit = 0x80;
|
||||||
static const int kNBit = 0x20;
|
static const int kNBit = 0x20;
|
||||||
static const int kSBit = 0x10;
|
static const int kSBit = 0x10;
|
||||||
static const int kPartIdField = 0x0F;
|
static const int kPartIdField = 0x0F;
|
||||||
static const int kKeyIdxField = 0x1F;
|
static const int kKeyIdxField = 0x1F;
|
||||||
static const int kIBit = 0x80;
|
static const int kIBit = 0x80;
|
||||||
static const int kLBit = 0x40;
|
static const int kLBit = 0x40;
|
||||||
static const int kTBit = 0x20;
|
static const int kTBit = 0x20;
|
||||||
static const int kKBit = 0x10;
|
static const int kKBit = 0x10;
|
||||||
static const int kYBit = 0x20;
|
static const int kYBit = 0x20;
|
||||||
|
|
||||||
// Calculate size of next chunk to send. Returns 0 if none can be sent.
|
// Calculate size of next chunk to send. Returns 0 if none can be sent.
|
||||||
int CalcNextSize(int max_payload_len, int remaining_bytes,
|
int CalcNextSize(int max_payload_len,
|
||||||
|
int remaining_bytes,
|
||||||
bool split_payload) const;
|
bool split_payload) const;
|
||||||
|
|
||||||
// Calculate all packet sizes and load to packet info queue.
|
// Calculate all packet sizes and load to packet info queue.
|
||||||
@ -144,7 +151,6 @@ class RtpPacketizerVp8 : public RtpPacketizer {
|
|||||||
uint8_t* buffer,
|
uint8_t* buffer,
|
||||||
int buffer_length) const;
|
int buffer_length) const;
|
||||||
|
|
||||||
|
|
||||||
// Write the X field and the appropriate extension fields to buffer.
|
// Write the X field and the appropriate extension fields to buffer.
|
||||||
// The function returns the extension length (including X field), or -1
|
// The function returns the extension length (including X field), or -1
|
||||||
// on error.
|
// on error.
|
||||||
@ -152,19 +158,25 @@ class RtpPacketizerVp8 : public RtpPacketizer {
|
|||||||
|
|
||||||
// Set the I bit in the x_field, and write PictureID to the appropriate
|
// Set the I bit in the x_field, and write PictureID to the appropriate
|
||||||
// position in buffer. The function returns 0 on success, -1 otherwise.
|
// position in buffer. The function returns 0 on success, -1 otherwise.
|
||||||
int WritePictureIDFields(uint8_t* x_field, uint8_t* buffer,
|
int WritePictureIDFields(uint8_t* x_field,
|
||||||
int buffer_length, int* extension_length) const;
|
uint8_t* buffer,
|
||||||
|
int buffer_length,
|
||||||
|
int* extension_length) const;
|
||||||
|
|
||||||
// Set the L bit in the x_field, and write Tl0PicIdx to the appropriate
|
// Set the L bit in the x_field, and write Tl0PicIdx to the appropriate
|
||||||
// position in buffer. The function returns 0 on success, -1 otherwise.
|
// position in buffer. The function returns 0 on success, -1 otherwise.
|
||||||
int WriteTl0PicIdxFields(uint8_t* x_field, uint8_t* buffer,
|
int WriteTl0PicIdxFields(uint8_t* x_field,
|
||||||
int buffer_length, int* extension_length) const;
|
uint8_t* buffer,
|
||||||
|
int buffer_length,
|
||||||
|
int* extension_length) const;
|
||||||
|
|
||||||
// Set the T and K bits in the x_field, and write TID, Y and KeyIdx to the
|
// Set the T and K bits in the x_field, and write TID, Y and KeyIdx to the
|
||||||
// appropriate position in buffer. The function returns 0 on success,
|
// appropriate position in buffer. The function returns 0 on success,
|
||||||
// -1 otherwise.
|
// -1 otherwise.
|
||||||
int WriteTIDAndKeyIdxFields(uint8_t* x_field, uint8_t* buffer,
|
int WriteTIDAndKeyIdxFields(uint8_t* x_field,
|
||||||
int buffer_length, int* extension_length) const;
|
uint8_t* buffer,
|
||||||
|
int buffer_length,
|
||||||
|
int* extension_length) const;
|
||||||
|
|
||||||
// Write the PictureID from codec_specific_info_ to buffer. One or two
|
// Write the PictureID from codec_specific_info_ to buffer. One or two
|
||||||
// bytes are written, depending on magnitude of PictureID. The function
|
// bytes are written, depending on magnitude of PictureID. The function
|
||||||
@ -202,5 +214,22 @@ class RtpPacketizerVp8 : public RtpPacketizer {
|
|||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(RtpPacketizerVp8);
|
DISALLOW_COPY_AND_ASSIGN(RtpPacketizerVp8);
|
||||||
};
|
};
|
||||||
} // namespace
|
|
||||||
|
// Depacketizer for VP8.
|
||||||
|
class RtpDepacketizerVp8 : public RtpDepacketizer {
|
||||||
|
public:
|
||||||
|
explicit RtpDepacketizerVp8(RtpData* const callback);
|
||||||
|
|
||||||
|
virtual ~RtpDepacketizerVp8() {}
|
||||||
|
|
||||||
|
virtual bool Parse(WebRtcRTPHeader* rtp_header,
|
||||||
|
const uint8_t* payload_data,
|
||||||
|
size_t payload_data_length) OVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RtpData* const callback_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(RtpDepacketizerVp8);
|
||||||
|
};
|
||||||
|
} // namespace webrtc
|
||||||
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_
|
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_
|
||||||
|
@ -297,5 +297,4 @@ TEST_F(RtpPacketizerVp8Test, TestTIDAndKeyIdx) {
|
|||||||
helper_->GetAllPacketsAndCheck(&packetizer, kExpectedSizes, kExpectedPart,
|
helper_->GetAllPacketsAndCheck(&packetizer, kExpectedSizes, kExpectedPart,
|
||||||
kExpectedFragStart, kExpectedNum);
|
kExpectedFragStart, kExpectedNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -29,13 +29,13 @@ RTPReceiverStrategy* RTPReceiverStrategy::CreateVideoStrategy(
|
|||||||
}
|
}
|
||||||
|
|
||||||
RTPReceiverVideo::RTPReceiverVideo(RtpData* data_callback)
|
RTPReceiverVideo::RTPReceiverVideo(RtpData* data_callback)
|
||||||
: RTPReceiverStrategy(data_callback) {}
|
: RTPReceiverStrategy(data_callback) {
|
||||||
|
}
|
||||||
|
|
||||||
RTPReceiverVideo::~RTPReceiverVideo() {
|
RTPReceiverVideo::~RTPReceiverVideo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RTPReceiverVideo::ShouldReportCsrcChanges(
|
bool RTPReceiverVideo::ShouldReportCsrcChanges(uint8_t payload_type) const {
|
||||||
uint8_t payload_type) const {
|
|
||||||
// Always do this for video packets.
|
// Always do this for video packets.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -47,17 +47,19 @@ int32_t RTPReceiverVideo::OnNewPayloadTypeCreated(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t RTPReceiverVideo::ParseRtpPacket(
|
int32_t RTPReceiverVideo::ParseRtpPacket(WebRtcRTPHeader* rtp_header,
|
||||||
WebRtcRTPHeader* rtp_header,
|
const PayloadUnion& specific_payload,
|
||||||
const PayloadUnion& specific_payload,
|
bool is_red,
|
||||||
bool is_red,
|
const uint8_t* payload,
|
||||||
const uint8_t* payload,
|
uint16_t payload_length,
|
||||||
uint16_t payload_length,
|
int64_t timestamp_ms,
|
||||||
int64_t timestamp_ms,
|
bool is_first_packet) {
|
||||||
bool is_first_packet) {
|
TRACE_EVENT2("webrtc_rtp",
|
||||||
TRACE_EVENT2("webrtc_rtp", "Video::ParseRtp",
|
"Video::ParseRtp",
|
||||||
"seqnum", rtp_header->header.sequenceNumber,
|
"seqnum",
|
||||||
"timestamp", rtp_header->header.timestamp);
|
rtp_header->header.sequenceNumber,
|
||||||
|
"timestamp",
|
||||||
|
rtp_header->header.timestamp);
|
||||||
rtp_header->type.Video.codec = specific_payload.Video.videoCodecType;
|
rtp_header->type.Video.codec = specific_payload.Video.videoCodecType;
|
||||||
|
|
||||||
const uint16_t payload_data_length =
|
const uint16_t payload_data_length =
|
||||||
@ -67,12 +69,16 @@ int32_t RTPReceiverVideo::ParseRtpPacket(
|
|||||||
return data_callback_->OnReceivedPayloadData(NULL, 0, rtp_header) == 0 ? 0
|
return data_callback_->OnReceivedPayloadData(NULL, 0, rtp_header) == 0 ? 0
|
||||||
: -1;
|
: -1;
|
||||||
|
|
||||||
return ParseVideoCodecSpecific(rtp_header,
|
// We are not allowed to hold a critical section when calling below functions.
|
||||||
payload,
|
scoped_ptr<RtpDepacketizer> depacketizer(
|
||||||
payload_data_length,
|
RtpDepacketizer::Create(rtp_header->type.Video.codec, data_callback_));
|
||||||
specific_payload.Video.videoCodecType,
|
if (depacketizer.get() == NULL) {
|
||||||
timestamp_ms,
|
LOG(LS_ERROR) << "Failed to create depacketizer.";
|
||||||
is_first_packet);
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtp_header->type.Video.isFirstPacket = is_first_packet;
|
||||||
|
return depacketizer->Parse(rtp_header, payload, payload_data_length) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RTPReceiverVideo::GetPayloadTypeFrequency() const {
|
int RTPReceiverVideo::GetPayloadTypeFrequency() const {
|
||||||
@ -91,8 +97,9 @@ int32_t RTPReceiverVideo::InvokeOnInitializeDecoder(
|
|||||||
const char payload_name[RTP_PAYLOAD_NAME_SIZE],
|
const char payload_name[RTP_PAYLOAD_NAME_SIZE],
|
||||||
const PayloadUnion& specific_payload) const {
|
const PayloadUnion& specific_payload) const {
|
||||||
// For video we just go with default values.
|
// For video we just go with default values.
|
||||||
if (-1 == callback->OnInitializeDecoder(
|
if (-1 ==
|
||||||
id, payload_type, payload_name, kVideoPayloadTypeFrequency, 1, 0)) {
|
callback->OnInitializeDecoder(
|
||||||
|
id, payload_type, payload_name, kVideoPayloadTypeFrequency, 1, 0)) {
|
||||||
LOG(LS_ERROR) << "Failed to created decoder for payload type: "
|
LOG(LS_ERROR) << "Failed to created decoder for payload type: "
|
||||||
<< payload_type;
|
<< payload_type;
|
||||||
return -1;
|
return -1;
|
||||||
@ -100,36 +107,8 @@ int32_t RTPReceiverVideo::InvokeOnInitializeDecoder(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are not allowed to hold a critical section when calling this function.
|
int32_t RTPReceiverVideo::BuildRTPheader(const WebRtcRTPHeader* rtp_header,
|
||||||
int32_t RTPReceiverVideo::ParseVideoCodecSpecific(
|
uint8_t* data_buffer) const {
|
||||||
WebRtcRTPHeader* rtp_header,
|
|
||||||
const uint8_t* payload_data,
|
|
||||||
uint16_t payload_data_length,
|
|
||||||
RtpVideoCodecTypes video_type,
|
|
||||||
int64_t now_ms,
|
|
||||||
bool is_first_packet) {
|
|
||||||
switch (rtp_header->type.Video.codec) {
|
|
||||||
case kRtpVideoGeneric:
|
|
||||||
rtp_header->type.Video.isFirstPacket = is_first_packet;
|
|
||||||
return ReceiveGenericCodec(rtp_header, payload_data, payload_data_length);
|
|
||||||
case kRtpVideoVp8:
|
|
||||||
return ReceiveVp8Codec(rtp_header, payload_data, payload_data_length);
|
|
||||||
case kRtpVideoH264: {
|
|
||||||
scoped_ptr<RtpDepacketizer> depacketizer(RtpDepacketizer::Create(
|
|
||||||
rtp_header->type.Video.codec, data_callback_));
|
|
||||||
return depacketizer->Parse(rtp_header, payload_data, payload_data_length)
|
|
||||||
? 0
|
|
||||||
: -1;
|
|
||||||
}
|
|
||||||
case kRtpVideoNone:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t RTPReceiverVideo::BuildRTPheader(
|
|
||||||
const WebRtcRTPHeader* rtp_header,
|
|
||||||
uint8_t* data_buffer) const {
|
|
||||||
data_buffer[0] = static_cast<uint8_t>(0x80); // version 2
|
data_buffer[0] = static_cast<uint8_t>(0x80); // version 2
|
||||||
data_buffer[1] = static_cast<uint8_t>(rtp_header->header.payloadType);
|
data_buffer[1] = static_cast<uint8_t>(rtp_header->header.payloadType);
|
||||||
if (rtp_header->header.markerBit) {
|
if (rtp_header->header.markerBit) {
|
||||||
@ -161,73 +140,4 @@ int32_t RTPReceiverVideo::BuildRTPheader(
|
|||||||
return rtp_header_length;
|
return rtp_header_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t RTPReceiverVideo::ReceiveVp8Codec(WebRtcRTPHeader* rtp_header,
|
|
||||||
const uint8_t* payload_data,
|
|
||||||
uint16_t payload_data_length) {
|
|
||||||
RtpUtility::RTPPayload parsed_packet;
|
|
||||||
RtpUtility::RTPPayloadParser rtp_payload_parser(
|
|
||||||
kRtpVideoVp8, payload_data, payload_data_length);
|
|
||||||
|
|
||||||
if (!rtp_payload_parser.Parse(parsed_packet))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (parsed_packet.info.VP8.dataLength == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
rtp_header->frameType = (parsed_packet.frameType == RtpUtility::kIFrame)
|
|
||||||
? kVideoFrameKey
|
|
||||||
: kVideoFrameDelta;
|
|
||||||
|
|
||||||
RTPVideoHeaderVP8* to_header = &rtp_header->type.Video.codecHeader.VP8;
|
|
||||||
RtpUtility::RTPPayloadVP8* from_header = &parsed_packet.info.VP8;
|
|
||||||
|
|
||||||
rtp_header->type.Video.isFirstPacket =
|
|
||||||
from_header->beginningOfPartition && (from_header->partitionID == 0);
|
|
||||||
to_header->nonReference = from_header->nonReferenceFrame;
|
|
||||||
to_header->pictureId =
|
|
||||||
from_header->hasPictureID ? from_header->pictureID : kNoPictureId;
|
|
||||||
to_header->tl0PicIdx =
|
|
||||||
from_header->hasTl0PicIdx ? from_header->tl0PicIdx : kNoTl0PicIdx;
|
|
||||||
if (from_header->hasTID) {
|
|
||||||
to_header->temporalIdx = from_header->tID;
|
|
||||||
to_header->layerSync = from_header->layerSync;
|
|
||||||
} else {
|
|
||||||
to_header->temporalIdx = kNoTemporalIdx;
|
|
||||||
to_header->layerSync = false;
|
|
||||||
}
|
|
||||||
to_header->keyIdx = from_header->hasKeyIdx ? from_header->keyIdx : kNoKeyIdx;
|
|
||||||
|
|
||||||
rtp_header->type.Video.width = from_header->frameWidth;
|
|
||||||
rtp_header->type.Video.height = from_header->frameHeight;
|
|
||||||
|
|
||||||
to_header->partitionId = from_header->partitionID;
|
|
||||||
to_header->beginningOfPartition = from_header->beginningOfPartition;
|
|
||||||
|
|
||||||
if (data_callback_->OnReceivedPayloadData(parsed_packet.info.VP8.data,
|
|
||||||
parsed_packet.info.VP8.dataLength,
|
|
||||||
rtp_header) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t RTPReceiverVideo::ReceiveGenericCodec(
|
|
||||||
WebRtcRTPHeader* rtp_header,
|
|
||||||
const uint8_t* payload_data,
|
|
||||||
uint16_t payload_data_length) {
|
|
||||||
uint8_t generic_header = *payload_data++;
|
|
||||||
--payload_data_length;
|
|
||||||
|
|
||||||
rtp_header->frameType =
|
|
||||||
((generic_header & RtpFormatVideoGeneric::kKeyFrameBit) != 0) ?
|
|
||||||
kVideoFrameKey : kVideoFrameDelta;
|
|
||||||
rtp_header->type.Video.isFirstPacket =
|
|
||||||
(generic_header & RtpFormatVideoGeneric::kFirstPacketBit) != 0;
|
|
||||||
|
|
||||||
if (data_callback_->OnReceivedPayloadData(
|
|
||||||
payload_data, payload_data_length, rtp_header) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -22,27 +22,24 @@ namespace webrtc {
|
|||||||
|
|
||||||
class RTPReceiverVideo : public RTPReceiverStrategy {
|
class RTPReceiverVideo : public RTPReceiverStrategy {
|
||||||
public:
|
public:
|
||||||
RTPReceiverVideo(RtpData* data_callback);
|
explicit RTPReceiverVideo(RtpData* data_callback);
|
||||||
|
|
||||||
virtual ~RTPReceiverVideo();
|
virtual ~RTPReceiverVideo();
|
||||||
|
|
||||||
virtual int32_t ParseRtpPacket(
|
virtual int32_t ParseRtpPacket(WebRtcRTPHeader* rtp_header,
|
||||||
WebRtcRTPHeader* rtp_header,
|
const PayloadUnion& specific_payload,
|
||||||
const PayloadUnion& specific_payload,
|
bool is_red,
|
||||||
bool is_red,
|
const uint8_t* packet,
|
||||||
const uint8_t* packet,
|
uint16_t packet_length,
|
||||||
uint16_t packet_length,
|
int64_t timestamp,
|
||||||
int64_t timestamp,
|
bool is_first_packet) OVERRIDE;
|
||||||
bool is_first_packet) OVERRIDE;
|
|
||||||
|
|
||||||
TelephoneEventHandler* GetTelephoneEventHandler() {
|
TelephoneEventHandler* GetTelephoneEventHandler() { return NULL; }
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetPayloadTypeFrequency() const OVERRIDE;
|
int GetPayloadTypeFrequency() const OVERRIDE;
|
||||||
|
|
||||||
virtual RTPAliveType ProcessDeadOrAlive(uint16_t last_payload_length) const
|
virtual RTPAliveType ProcessDeadOrAlive(
|
||||||
OVERRIDE;
|
uint16_t last_payload_length) const OVERRIDE;
|
||||||
|
|
||||||
virtual bool ShouldReportCsrcChanges(uint8_t payload_type) const OVERRIDE;
|
virtual bool ShouldReportCsrcChanges(uint8_t payload_type) const OVERRIDE;
|
||||||
|
|
||||||
@ -61,28 +58,8 @@ class RTPReceiverVideo : public RTPReceiverStrategy {
|
|||||||
void SetPacketOverHead(uint16_t packet_over_head);
|
void SetPacketOverHead(uint16_t packet_over_head);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int32_t ReceiveGenericCodec(WebRtcRTPHeader* rtp_header,
|
|
||||||
const uint8_t* payload_data,
|
|
||||||
uint16_t payload_data_length);
|
|
||||||
|
|
||||||
int32_t ReceiveVp8Codec(WebRtcRTPHeader* rtp_header,
|
|
||||||
const uint8_t* payload_data,
|
|
||||||
uint16_t payload_data_length);
|
|
||||||
|
|
||||||
int32_t ReceiveH264Codec(WebRtcRTPHeader* rtp_header,
|
|
||||||
const uint8_t* payload_data,
|
|
||||||
uint16_t payload_data_length);
|
|
||||||
|
|
||||||
int32_t BuildRTPheader(const WebRtcRTPHeader* rtp_header,
|
int32_t BuildRTPheader(const WebRtcRTPHeader* rtp_header,
|
||||||
uint8_t* data_buffer) const;
|
uint8_t* data_buffer) const;
|
||||||
|
|
||||||
int32_t ParseVideoCodecSpecific(
|
|
||||||
WebRtcRTPHeader* rtp_header,
|
|
||||||
const uint8_t* payload_data,
|
|
||||||
uint16_t payload_data_length,
|
|
||||||
RtpVideoCodecTypes video_type,
|
|
||||||
int64_t now_ms,
|
|
||||||
bool is_first_packet);
|
|
||||||
};
|
};
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
||||||
|
@ -92,6 +92,7 @@
|
|||||||
'rtp_format_h264.h',
|
'rtp_format_h264.h',
|
||||||
'rtp_format_vp8.cc',
|
'rtp_format_vp8.cc',
|
||||||
'rtp_format_vp8.h',
|
'rtp_format_vp8.h',
|
||||||
|
'rtp_format_video_generic.cc',
|
||||||
'rtp_format_video_generic.h',
|
'rtp_format_video_generic.h',
|
||||||
'vp8_partition_aggregator.cc',
|
'vp8_partition_aggregator.cc',
|
||||||
'vp8_partition_aggregator.h',
|
'vp8_partition_aggregator.h',
|
||||||
|
@ -31,8 +31,7 @@ struct RtpPacket {
|
|||||||
ForwardErrorCorrection::Packet* pkt;
|
ForwardErrorCorrection::Packet* pkt;
|
||||||
};
|
};
|
||||||
|
|
||||||
RTPSenderVideo::RTPSenderVideo(Clock* clock,
|
RTPSenderVideo::RTPSenderVideo(Clock* clock, RTPSenderInterface* rtpSender)
|
||||||
RTPSenderInterface* rtpSender)
|
|
||||||
: _rtpSender(*rtpSender),
|
: _rtpSender(*rtpSender),
|
||||||
_sendVideoCritsect(CriticalSectionWrapper::CreateCriticalSection()),
|
_sendVideoCritsect(CriticalSectionWrapper::CreateCriticalSection()),
|
||||||
_videoType(kRtpVideoGeneric),
|
_videoType(kRtpVideoGeneric),
|
||||||
@ -55,29 +54,23 @@ RTPSenderVideo::RTPSenderVideo(Clock* clock,
|
|||||||
memset(&key_fec_params_, 0, sizeof(key_fec_params_));
|
memset(&key_fec_params_, 0, sizeof(key_fec_params_));
|
||||||
delta_fec_params_.max_fec_frames = key_fec_params_.max_fec_frames = 1;
|
delta_fec_params_.max_fec_frames = key_fec_params_.max_fec_frames = 1;
|
||||||
delta_fec_params_.fec_mask_type = key_fec_params_.fec_mask_type =
|
delta_fec_params_.fec_mask_type = key_fec_params_.fec_mask_type =
|
||||||
kFecMaskRandom;
|
kFecMaskRandom;
|
||||||
}
|
}
|
||||||
|
|
||||||
RTPSenderVideo::~RTPSenderVideo()
|
RTPSenderVideo::~RTPSenderVideo() {
|
||||||
{
|
if (_videoCodecInformation) {
|
||||||
if(_videoCodecInformation)
|
delete _videoCodecInformation;
|
||||||
{
|
}
|
||||||
delete _videoCodecInformation;
|
delete _sendVideoCritsect;
|
||||||
}
|
|
||||||
delete _sendVideoCritsect;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void RTPSenderVideo::SetVideoCodecType(RtpVideoCodecTypes videoType) {
|
||||||
RTPSenderVideo::SetVideoCodecType(RtpVideoCodecTypes videoType)
|
CriticalSectionScoped cs(_sendVideoCritsect);
|
||||||
{
|
_videoType = videoType;
|
||||||
CriticalSectionScoped cs(_sendVideoCritsect);
|
|
||||||
_videoType = videoType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RtpVideoCodecTypes
|
RtpVideoCodecTypes RTPSenderVideo::VideoCodecType() const {
|
||||||
RTPSenderVideo::VideoCodecType() const
|
return _videoType;
|
||||||
{
|
|
||||||
return _videoType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t RTPSenderVideo::RegisterVideoPayload(
|
int32_t RTPSenderVideo::RegisterVideoPayload(
|
||||||
@ -106,34 +99,34 @@ int32_t RTPSenderVideo::RegisterVideoPayload(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t
|
int32_t RTPSenderVideo::SendVideoPacket(uint8_t* data_buffer,
|
||||||
RTPSenderVideo::SendVideoPacket(uint8_t* data_buffer,
|
const uint16_t payload_length,
|
||||||
const uint16_t payload_length,
|
const uint16_t rtp_header_length,
|
||||||
const uint16_t rtp_header_length,
|
const uint32_t capture_timestamp,
|
||||||
const uint32_t capture_timestamp,
|
int64_t capture_time_ms,
|
||||||
int64_t capture_time_ms,
|
StorageType storage,
|
||||||
StorageType storage,
|
bool protect) {
|
||||||
bool protect) {
|
if (_fecEnabled) {
|
||||||
if(_fecEnabled) {
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int fec_overhead_sent = 0;
|
int fec_overhead_sent = 0;
|
||||||
int video_sent = 0;
|
int video_sent = 0;
|
||||||
|
|
||||||
RedPacket* red_packet = producer_fec_.BuildRedPacket(data_buffer,
|
RedPacket* red_packet = producer_fec_.BuildRedPacket(
|
||||||
payload_length,
|
data_buffer, payload_length, rtp_header_length, _payloadTypeRED);
|
||||||
rtp_header_length,
|
TRACE_EVENT_INSTANT2("webrtc_rtp",
|
||||||
_payloadTypeRED);
|
"Video::PacketRed",
|
||||||
TRACE_EVENT_INSTANT2("webrtc_rtp", "Video::PacketRed",
|
"timestamp",
|
||||||
"timestamp", capture_timestamp,
|
capture_timestamp,
|
||||||
"seqnum", _rtpSender.SequenceNumber());
|
"seqnum",
|
||||||
|
_rtpSender.SequenceNumber());
|
||||||
// Sending the media packet with RED header.
|
// Sending the media packet with RED header.
|
||||||
int packet_success = _rtpSender.SendToNetwork(
|
int packet_success =
|
||||||
red_packet->data(),
|
_rtpSender.SendToNetwork(red_packet->data(),
|
||||||
red_packet->length() - rtp_header_length,
|
red_packet->length() - rtp_header_length,
|
||||||
rtp_header_length,
|
rtp_header_length,
|
||||||
capture_time_ms,
|
capture_time_ms,
|
||||||
storage,
|
storage,
|
||||||
PacedSender::kNormalPriority);
|
PacedSender::kNormalPriority);
|
||||||
|
|
||||||
ret |= packet_success;
|
ret |= packet_success;
|
||||||
|
|
||||||
@ -144,34 +137,36 @@ RTPSenderVideo::SendVideoPacket(uint8_t* data_buffer,
|
|||||||
red_packet = NULL;
|
red_packet = NULL;
|
||||||
|
|
||||||
if (protect) {
|
if (protect) {
|
||||||
ret = producer_fec_.AddRtpPacketAndGenerateFec(data_buffer,
|
ret = producer_fec_.AddRtpPacketAndGenerateFec(
|
||||||
payload_length,
|
data_buffer, payload_length, rtp_header_length);
|
||||||
rtp_header_length);
|
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (producer_fec_.FecAvailable()) {
|
while (producer_fec_.FecAvailable()) {
|
||||||
red_packet = producer_fec_.GetFecPacket(
|
red_packet =
|
||||||
_payloadTypeRED,
|
producer_fec_.GetFecPacket(_payloadTypeRED,
|
||||||
_payloadTypeFEC,
|
_payloadTypeFEC,
|
||||||
_rtpSender.IncrementSequenceNumber(),
|
_rtpSender.IncrementSequenceNumber(),
|
||||||
rtp_header_length);
|
rtp_header_length);
|
||||||
StorageType storage = kDontRetransmit;
|
StorageType storage = kDontRetransmit;
|
||||||
if (_retransmissionSettings & kRetransmitFECPackets) {
|
if (_retransmissionSettings & kRetransmitFECPackets) {
|
||||||
storage = kAllowRetransmission;
|
storage = kAllowRetransmission;
|
||||||
}
|
}
|
||||||
TRACE_EVENT_INSTANT2("webrtc_rtp", "Video::PacketFec",
|
TRACE_EVENT_INSTANT2("webrtc_rtp",
|
||||||
"timestamp", capture_timestamp,
|
"Video::PacketFec",
|
||||||
"seqnum", _rtpSender.SequenceNumber());
|
"timestamp",
|
||||||
|
capture_timestamp,
|
||||||
|
"seqnum",
|
||||||
|
_rtpSender.SequenceNumber());
|
||||||
// Sending FEC packet with RED header.
|
// Sending FEC packet with RED header.
|
||||||
int packet_success = _rtpSender.SendToNetwork(
|
int packet_success =
|
||||||
red_packet->data(),
|
_rtpSender.SendToNetwork(red_packet->data(),
|
||||||
red_packet->length() - rtp_header_length,
|
red_packet->length() - rtp_header_length,
|
||||||
rtp_header_length,
|
rtp_header_length,
|
||||||
capture_time_ms,
|
capture_time_ms,
|
||||||
storage,
|
storage,
|
||||||
PacedSender::kNormalPriority);
|
PacedSender::kNormalPriority);
|
||||||
|
|
||||||
ret |= packet_success;
|
ret |= packet_success;
|
||||||
|
|
||||||
@ -185,9 +180,12 @@ RTPSenderVideo::SendVideoPacket(uint8_t* data_buffer,
|
|||||||
_fecOverheadRate.Update(fec_overhead_sent);
|
_fecOverheadRate.Update(fec_overhead_sent);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
TRACE_EVENT_INSTANT2("webrtc_rtp", "Video::PacketNormal",
|
TRACE_EVENT_INSTANT2("webrtc_rtp",
|
||||||
"timestamp", capture_timestamp,
|
"Video::PacketNormal",
|
||||||
"seqnum", _rtpSender.SequenceNumber());
|
"timestamp",
|
||||||
|
capture_timestamp,
|
||||||
|
"seqnum",
|
||||||
|
_rtpSender.SequenceNumber());
|
||||||
int ret = _rtpSender.SendToNetwork(data_buffer,
|
int ret = _rtpSender.SendToNetwork(data_buffer,
|
||||||
payload_length,
|
payload_length,
|
||||||
rtp_header_length,
|
rtp_header_length,
|
||||||
@ -200,69 +198,61 @@ RTPSenderVideo::SendVideoPacket(uint8_t* data_buffer,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t
|
int32_t RTPSenderVideo::SendRTPIntraRequest() {
|
||||||
RTPSenderVideo::SendRTPIntraRequest()
|
// RFC 2032
|
||||||
{
|
// 5.2.1. Full intra-frame Request (FIR) packet
|
||||||
// RFC 2032
|
|
||||||
// 5.2.1. Full intra-frame Request (FIR) packet
|
|
||||||
|
|
||||||
uint16_t length = 8;
|
uint16_t length = 8;
|
||||||
uint8_t data[8];
|
uint8_t data[8];
|
||||||
data[0] = 0x80;
|
data[0] = 0x80;
|
||||||
data[1] = 192;
|
data[1] = 192;
|
||||||
data[2] = 0;
|
data[2] = 0;
|
||||||
data[3] = 1; // length
|
data[3] = 1; // length
|
||||||
|
|
||||||
RtpUtility::AssignUWord32ToBuffer(data + 4, _rtpSender.SSRC());
|
RtpUtility::AssignUWord32ToBuffer(data + 4, _rtpSender.SSRC());
|
||||||
|
|
||||||
TRACE_EVENT_INSTANT1("webrtc_rtp",
|
TRACE_EVENT_INSTANT1("webrtc_rtp",
|
||||||
"Video::IntraRequest",
|
"Video::IntraRequest",
|
||||||
"seqnum", _rtpSender.SequenceNumber());
|
"seqnum",
|
||||||
return _rtpSender.SendToNetwork(data, 0, length, -1, kDontStore,
|
_rtpSender.SequenceNumber());
|
||||||
PacedSender::kNormalPriority);
|
return _rtpSender.SendToNetwork(
|
||||||
|
data, 0, length, -1, kDontStore, PacedSender::kNormalPriority);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t
|
int32_t RTPSenderVideo::SetGenericFECStatus(const bool enable,
|
||||||
RTPSenderVideo::SetGenericFECStatus(const bool enable,
|
const uint8_t payloadTypeRED,
|
||||||
const uint8_t payloadTypeRED,
|
const uint8_t payloadTypeFEC) {
|
||||||
const uint8_t payloadTypeFEC)
|
_fecEnabled = enable;
|
||||||
{
|
_payloadTypeRED = payloadTypeRED;
|
||||||
_fecEnabled = enable;
|
_payloadTypeFEC = payloadTypeFEC;
|
||||||
_payloadTypeRED = payloadTypeRED;
|
memset(&delta_fec_params_, 0, sizeof(delta_fec_params_));
|
||||||
_payloadTypeFEC = payloadTypeFEC;
|
memset(&key_fec_params_, 0, sizeof(key_fec_params_));
|
||||||
memset(&delta_fec_params_, 0, sizeof(delta_fec_params_));
|
delta_fec_params_.max_fec_frames = key_fec_params_.max_fec_frames = 1;
|
||||||
memset(&key_fec_params_, 0, sizeof(key_fec_params_));
|
delta_fec_params_.fec_mask_type = key_fec_params_.fec_mask_type =
|
||||||
delta_fec_params_.max_fec_frames = key_fec_params_.max_fec_frames = 1;
|
kFecMaskRandom;
|
||||||
delta_fec_params_.fec_mask_type = key_fec_params_.fec_mask_type =
|
return 0;
|
||||||
kFecMaskRandom;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t
|
int32_t RTPSenderVideo::GenericFECStatus(bool& enable,
|
||||||
RTPSenderVideo::GenericFECStatus(bool& enable,
|
uint8_t& payloadTypeRED,
|
||||||
uint8_t& payloadTypeRED,
|
uint8_t& payloadTypeFEC) const {
|
||||||
uint8_t& payloadTypeFEC) const
|
enable = _fecEnabled;
|
||||||
{
|
payloadTypeRED = _payloadTypeRED;
|
||||||
enable = _fecEnabled;
|
payloadTypeFEC = _payloadTypeFEC;
|
||||||
payloadTypeRED = _payloadTypeRED;
|
return 0;
|
||||||
payloadTypeFEC = _payloadTypeFEC;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t
|
uint16_t RTPSenderVideo::FECPacketOverhead() const {
|
||||||
RTPSenderVideo::FECPacketOverhead() const
|
if (_fecEnabled) {
|
||||||
{
|
// Overhead is FEC headers plus RED for FEC header plus anything in RTP
|
||||||
if (_fecEnabled)
|
// header beyond the 12 bytes base header (CSRC list, extensions...)
|
||||||
{
|
// This reason for the header extensions to be included here is that
|
||||||
// Overhead is FEC headers plus RED for FEC header plus anything in RTP
|
// from an FEC viewpoint, they are part of the payload to be protected.
|
||||||
// header beyond the 12 bytes base header (CSRC list, extensions...)
|
// (The base RTP header is already protected by the FEC header.)
|
||||||
// This reason for the header extensions to be included here is that
|
return ForwardErrorCorrection::PacketOverhead() + REDForFECHeaderLength +
|
||||||
// from an FEC viewpoint, they are part of the payload to be protected.
|
(_rtpSender.RTPHeaderLength() - kRtpHeaderSize);
|
||||||
// (The base RTP header is already protected by the FEC header.)
|
}
|
||||||
return ForwardErrorCorrection::PacketOverhead() + REDForFECHeaderLength +
|
return 0;
|
||||||
(_rtpSender.RTPHeaderLength() - kRtpHeaderSize);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t RTPSenderVideo::SetFecParameters(
|
int32_t RTPSenderVideo::SetFecParameters(
|
||||||
@ -299,206 +289,58 @@ int32_t RTPSenderVideo::SendVideo(const RtpVideoCodecTypes videoType,
|
|||||||
// Will be extracted in SendVP8 for VP8 codec; other codecs use 0
|
// Will be extracted in SendVP8 for VP8 codec; other codecs use 0
|
||||||
_numberFirstPartition = 0;
|
_numberFirstPartition = 0;
|
||||||
|
|
||||||
switch (videoType) {
|
return Send(videoType,
|
||||||
case kRtpVideoGeneric:
|
frameType,
|
||||||
return SendGeneric(frameType,
|
payloadType,
|
||||||
payloadType,
|
captureTimeStamp,
|
||||||
captureTimeStamp,
|
capture_time_ms,
|
||||||
capture_time_ms,
|
payloadData,
|
||||||
payloadData,
|
payloadSize,
|
||||||
payloadSize);
|
fragmentation,
|
||||||
case kRtpVideoVp8:
|
rtpTypeHdr)
|
||||||
return SendVP8(frameType,
|
? 0
|
||||||
payloadType,
|
: -1;
|
||||||
captureTimeStamp,
|
|
||||||
capture_time_ms,
|
|
||||||
payloadData,
|
|
||||||
payloadSize,
|
|
||||||
fragmentation,
|
|
||||||
rtpTypeHdr);
|
|
||||||
case kRtpVideoH264:
|
|
||||||
return SendH264(frameType,
|
|
||||||
payloadType,
|
|
||||||
captureTimeStamp,
|
|
||||||
capture_time_ms,
|
|
||||||
payloadData,
|
|
||||||
payloadSize,
|
|
||||||
fragmentation,
|
|
||||||
rtpTypeHdr)
|
|
||||||
? 0
|
|
||||||
: -1;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t RTPSenderVideo::SendGeneric(const FrameType frame_type,
|
VideoCodecInformation* RTPSenderVideo::CodecInformationVideo() {
|
||||||
const int8_t payload_type,
|
return _videoCodecInformation;
|
||||||
const uint32_t capture_timestamp,
|
}
|
||||||
int64_t capture_time_ms,
|
|
||||||
const uint8_t* payload,
|
void RTPSenderVideo::SetMaxConfiguredBitrateVideo(const uint32_t maxBitrate) {
|
||||||
uint32_t size) {
|
_maxBitrate = maxBitrate;
|
||||||
assert(frame_type == kVideoFrameKey || frame_type == kVideoFrameDelta);
|
}
|
||||||
|
|
||||||
|
uint32_t RTPSenderVideo::MaxConfiguredBitrateVideo() const {
|
||||||
|
return _maxBitrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RTPSenderVideo::Send(const RtpVideoCodecTypes videoType,
|
||||||
|
const FrameType frameType,
|
||||||
|
const int8_t payloadType,
|
||||||
|
const uint32_t captureTimeStamp,
|
||||||
|
int64_t capture_time_ms,
|
||||||
|
const uint8_t* payloadData,
|
||||||
|
const uint32_t payloadSize,
|
||||||
|
const RTPFragmentationHeader* fragmentation,
|
||||||
|
const RTPVideoTypeHeader* rtpTypeHdr) {
|
||||||
uint16_t rtp_header_length = _rtpSender.RTPHeaderLength();
|
uint16_t rtp_header_length = _rtpSender.RTPHeaderLength();
|
||||||
uint16_t max_length = _rtpSender.MaxPayloadLength() - FECPacketOverhead() -
|
|
||||||
rtp_header_length - (1 /* generic header length */);
|
|
||||||
|
|
||||||
// Fragment packets more evenly by splitting the payload up evenly.
|
|
||||||
uint32_t num_packets = (size + max_length - 1) / max_length;
|
|
||||||
uint32_t payload_length = (size + num_packets - 1) / num_packets;
|
|
||||||
assert(payload_length <= max_length);
|
|
||||||
|
|
||||||
// Fragment packet into packets of max MaxPayloadLength bytes payload.
|
|
||||||
uint8_t buffer[IP_PACKET_SIZE];
|
|
||||||
|
|
||||||
uint8_t generic_header = RtpFormatVideoGeneric::kFirstPacketBit;
|
|
||||||
if (frame_type == kVideoFrameKey) {
|
|
||||||
generic_header |= RtpFormatVideoGeneric::kKeyFrameBit;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (size > 0) {
|
|
||||||
if (size < payload_length) {
|
|
||||||
payload_length = size;
|
|
||||||
}
|
|
||||||
size -= payload_length;
|
|
||||||
|
|
||||||
// MarkerBit is 1 on final packet (bytes_to_send == 0)
|
|
||||||
if (_rtpSender.BuildRTPheader(buffer, payload_type, size == 0,
|
|
||||||
capture_timestamp,
|
|
||||||
capture_time_ms) != rtp_header_length) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* out_ptr = &buffer[rtp_header_length];
|
|
||||||
|
|
||||||
// Put generic header in packet
|
|
||||||
*out_ptr++ = generic_header;
|
|
||||||
// Remove first-packet bit, following packets are intermediate
|
|
||||||
generic_header &= ~RtpFormatVideoGeneric::kFirstPacketBit;
|
|
||||||
|
|
||||||
// Put payload in packet
|
|
||||||
memcpy(out_ptr, payload, payload_length);
|
|
||||||
payload += payload_length;
|
|
||||||
|
|
||||||
if (SendVideoPacket(buffer, payload_length + 1, rtp_header_length,
|
|
||||||
capture_timestamp, capture_time_ms,
|
|
||||||
kAllowRetransmission, true)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoCodecInformation*
|
|
||||||
RTPSenderVideo::CodecInformationVideo()
|
|
||||||
{
|
|
||||||
return _videoCodecInformation;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
RTPSenderVideo::SetMaxConfiguredBitrateVideo(const uint32_t maxBitrate)
|
|
||||||
{
|
|
||||||
_maxBitrate = maxBitrate;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t
|
|
||||||
RTPSenderVideo::MaxConfiguredBitrateVideo() const
|
|
||||||
{
|
|
||||||
return _maxBitrate;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
RTPSenderVideo::SendVP8(const FrameType frameType,
|
|
||||||
const int8_t payloadType,
|
|
||||||
const uint32_t captureTimeStamp,
|
|
||||||
int64_t capture_time_ms,
|
|
||||||
const uint8_t* payloadData,
|
|
||||||
const uint32_t payloadSize,
|
|
||||||
const RTPFragmentationHeader* fragmentation,
|
|
||||||
const RTPVideoTypeHeader* rtpTypeHdr)
|
|
||||||
{
|
|
||||||
const uint16_t rtpHeaderLength = _rtpSender.RTPHeaderLength();
|
|
||||||
|
|
||||||
int32_t payloadBytesToSend = payloadSize;
|
|
||||||
const uint8_t* data = payloadData;
|
|
||||||
|
|
||||||
uint16_t maxPayloadLengthVP8 = _rtpSender.MaxDataPayloadLength();
|
|
||||||
|
|
||||||
assert(rtpTypeHdr);
|
|
||||||
// Initialize disregarding partition boundaries: this will use kEqualSize
|
|
||||||
// packetization mode, which produces ~equal size packets for each frame.
|
|
||||||
RtpPacketizerVp8 packetizer(rtpTypeHdr->VP8, maxPayloadLengthVP8);
|
|
||||||
packetizer.SetPayloadData(data, payloadBytesToSend, NULL);
|
|
||||||
|
|
||||||
StorageType storage = kAllowRetransmission;
|
|
||||||
if (rtpTypeHdr->VP8.temporalIdx == 0 &&
|
|
||||||
!(_retransmissionSettings & kRetransmitBaseLayer)) {
|
|
||||||
storage = kDontRetransmit;
|
|
||||||
} else if (rtpTypeHdr->VP8.temporalIdx != kNoTemporalIdx &&
|
|
||||||
rtpTypeHdr->VP8.temporalIdx > 0 &&
|
|
||||||
!(_retransmissionSettings & kRetransmitHigherLayers)) {
|
|
||||||
storage = kDontRetransmit;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool last = false;
|
|
||||||
_numberFirstPartition = 0;
|
|
||||||
// |rtpTypeHdr->VP8.temporalIdx| is zero for base layers, or kNoTemporalIdx
|
|
||||||
// if the field isn't used (so all layers are the base layer). We currently
|
|
||||||
// only protect base layers, so look for these two cases.
|
|
||||||
bool protect = rtpTypeHdr->VP8.temporalIdx == 0 ||
|
|
||||||
rtpTypeHdr->VP8.temporalIdx == kNoTemporalIdx;
|
|
||||||
while (!last)
|
|
||||||
{
|
|
||||||
// Write VP8 Payload Descriptor and VP8 payload.
|
|
||||||
uint8_t dataBuffer[IP_PACKET_SIZE] = {0};
|
|
||||||
size_t payloadBytesInPacket = 0;
|
|
||||||
if (!packetizer.NextPacket(
|
|
||||||
&dataBuffer[rtpHeaderLength], &payloadBytesInPacket, &last))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
// Write RTP header.
|
|
||||||
// Set marker bit true if this is the last packet in frame.
|
|
||||||
_rtpSender.BuildRTPheader(dataBuffer, payloadType, last,
|
|
||||||
captureTimeStamp, capture_time_ms);
|
|
||||||
if (-1 == SendVideoPacket(dataBuffer, payloadBytesInPacket,
|
|
||||||
rtpHeaderLength, captureTimeStamp,
|
|
||||||
capture_time_ms, storage, protect))
|
|
||||||
{
|
|
||||||
LOG(LS_WARNING)
|
|
||||||
<< "RTPSenderVideo::SendVP8 failed to send packet number "
|
|
||||||
<< _rtpSender.SequenceNumber();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TRACE_EVENT_ASYNC_END1("webrtc", "Video", capture_time_ms,
|
|
||||||
"timestamp", _rtpSender.Timestamp());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RTPSenderVideo::SendH264(const FrameType frameType,
|
|
||||||
const int8_t payloadType,
|
|
||||||
const uint32_t captureTimeStamp,
|
|
||||||
int64_t capture_time_ms,
|
|
||||||
const uint8_t* payloadData,
|
|
||||||
const uint32_t payloadSize,
|
|
||||||
const RTPFragmentationHeader* fragmentation,
|
|
||||||
const RTPVideoTypeHeader* rtpTypeHdr) {
|
|
||||||
size_t rtp_header_length = _rtpSender.RTPHeaderLength();
|
|
||||||
int32_t payload_bytes_to_send = payloadSize;
|
int32_t payload_bytes_to_send = payloadSize;
|
||||||
const uint8_t* data = payloadData;
|
const uint8_t* data = payloadData;
|
||||||
size_t max_payload_length = _rtpSender.MaxDataPayloadLength();
|
size_t max_payload_length = _rtpSender.MaxDataPayloadLength();
|
||||||
|
|
||||||
scoped_ptr<RtpPacketizer> packetizer(
|
scoped_ptr<RtpPacketizer> packetizer(RtpPacketizer::Create(
|
||||||
RtpPacketizer::Create(kRtpVideoH264, max_payload_length));
|
videoType, max_payload_length, rtpTypeHdr, frameType));
|
||||||
packetizer->SetPayloadData(data, payload_bytes_to_send, fragmentation);
|
|
||||||
|
// TODO(changbin): we currently don't support to configure the codec to
|
||||||
|
// output multiple partitions for VP8. Should remove below check after the
|
||||||
|
// issue is fixed.
|
||||||
|
const RTPFragmentationHeader* frag =
|
||||||
|
(videoType == kRtpVideoVp8) ? NULL : fragmentation;
|
||||||
|
|
||||||
|
packetizer->SetPayloadData(data, payload_bytes_to_send, frag);
|
||||||
|
|
||||||
StorageType storage = kAllowRetransmission;
|
|
||||||
bool protect = (frameType == kVideoFrameKey);
|
|
||||||
bool last = false;
|
bool last = false;
|
||||||
|
|
||||||
while (!last) {
|
while (!last) {
|
||||||
// Write H264 payload.
|
|
||||||
uint8_t dataBuffer[IP_PACKET_SIZE] = {0};
|
uint8_t dataBuffer[IP_PACKET_SIZE] = {0};
|
||||||
size_t payload_bytes_in_packet = 0;
|
size_t payload_bytes_in_packet = 0;
|
||||||
if (!packetizer->NextPacket(
|
if (!packetizer->NextPacket(
|
||||||
@ -515,13 +357,16 @@ bool RTPSenderVideo::SendH264(const FrameType frameType,
|
|||||||
rtp_header_length,
|
rtp_header_length,
|
||||||
captureTimeStamp,
|
captureTimeStamp,
|
||||||
capture_time_ms,
|
capture_time_ms,
|
||||||
storage,
|
packetizer->GetStorageType(_retransmissionSettings),
|
||||||
protect)) {
|
packetizer->GetProtectionType() == kProtectedPacket)) {
|
||||||
LOG(LS_WARNING)
|
LOG(LS_WARNING) << packetizer->ToString()
|
||||||
<< "RTPSenderVideo::SendH264 failed to send packet number "
|
<< " failed to send packet number "
|
||||||
<< _rtpSender.SequenceNumber();
|
<< _rtpSender.SequenceNumber();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRACE_EVENT_ASYNC_END1(
|
||||||
|
"webrtc", "Video", capture_time_ms, "timestamp", _rtpSender.Timestamp());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,122 +28,106 @@ namespace webrtc {
|
|||||||
class CriticalSectionWrapper;
|
class CriticalSectionWrapper;
|
||||||
struct RtpPacket;
|
struct RtpPacket;
|
||||||
|
|
||||||
class RTPSenderVideo
|
class RTPSenderVideo {
|
||||||
{
|
public:
|
||||||
public:
|
RTPSenderVideo(Clock* clock, RTPSenderInterface* rtpSender);
|
||||||
RTPSenderVideo(Clock* clock,
|
virtual ~RTPSenderVideo();
|
||||||
RTPSenderInterface* rtpSender);
|
|
||||||
virtual ~RTPSenderVideo();
|
|
||||||
|
|
||||||
virtual RtpVideoCodecTypes VideoCodecType() const;
|
virtual RtpVideoCodecTypes VideoCodecType() const;
|
||||||
|
|
||||||
uint16_t FECPacketOverhead() const;
|
uint16_t FECPacketOverhead() const;
|
||||||
|
|
||||||
int32_t RegisterVideoPayload(const char payloadName[RTP_PAYLOAD_NAME_SIZE],
|
int32_t RegisterVideoPayload(const char payloadName[RTP_PAYLOAD_NAME_SIZE],
|
||||||
const int8_t payloadType,
|
const int8_t payloadType,
|
||||||
const uint32_t maxBitRate,
|
const uint32_t maxBitRate,
|
||||||
RtpUtility::Payload*& payload);
|
RtpUtility::Payload*& payload);
|
||||||
|
|
||||||
int32_t SendVideo(const RtpVideoCodecTypes videoType,
|
int32_t SendVideo(const RtpVideoCodecTypes videoType,
|
||||||
const FrameType frameType,
|
const FrameType frameType,
|
||||||
const int8_t payloadType,
|
|
||||||
const uint32_t captureTimeStamp,
|
|
||||||
int64_t capture_time_ms,
|
|
||||||
const uint8_t* payloadData,
|
|
||||||
const uint32_t payloadSize,
|
|
||||||
const RTPFragmentationHeader* fragmentation,
|
|
||||||
VideoCodecInformation* codecInfo,
|
|
||||||
const RTPVideoTypeHeader* rtpTypeHdr);
|
|
||||||
|
|
||||||
int32_t SendRTPIntraRequest();
|
|
||||||
|
|
||||||
void SetVideoCodecType(RtpVideoCodecTypes type);
|
|
||||||
|
|
||||||
VideoCodecInformation* CodecInformationVideo();
|
|
||||||
|
|
||||||
void SetMaxConfiguredBitrateVideo(const uint32_t maxBitrate);
|
|
||||||
|
|
||||||
uint32_t MaxConfiguredBitrateVideo() const;
|
|
||||||
|
|
||||||
// FEC
|
|
||||||
int32_t SetGenericFECStatus(const bool enable,
|
|
||||||
const uint8_t payloadTypeRED,
|
|
||||||
const uint8_t payloadTypeFEC);
|
|
||||||
|
|
||||||
int32_t GenericFECStatus(bool& enable,
|
|
||||||
uint8_t& payloadTypeRED,
|
|
||||||
uint8_t& payloadTypeFEC) const;
|
|
||||||
|
|
||||||
int32_t SetFecParameters(const FecProtectionParams* delta_params,
|
|
||||||
const FecProtectionParams* key_params);
|
|
||||||
|
|
||||||
void ProcessBitrate();
|
|
||||||
|
|
||||||
uint32_t VideoBitrateSent() const;
|
|
||||||
uint32_t FecOverheadRate() const;
|
|
||||||
|
|
||||||
int SelectiveRetransmissions() const;
|
|
||||||
int SetSelectiveRetransmissions(uint8_t settings);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual int32_t SendVideoPacket(uint8_t* dataBuffer,
|
|
||||||
const uint16_t payloadLength,
|
|
||||||
const uint16_t rtpHeaderLength,
|
|
||||||
const uint32_t capture_timestamp,
|
|
||||||
int64_t capture_time_ms,
|
|
||||||
StorageType storage,
|
|
||||||
bool protect);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int32_t SendGeneric(const FrameType frame_type,
|
|
||||||
const int8_t payload_type,
|
|
||||||
const uint32_t capture_timestamp,
|
|
||||||
int64_t capture_time_ms,
|
|
||||||
const uint8_t* payload, const uint32_t size);
|
|
||||||
|
|
||||||
int32_t SendVP8(const FrameType frameType,
|
|
||||||
const int8_t payloadType,
|
const int8_t payloadType,
|
||||||
const uint32_t captureTimeStamp,
|
const uint32_t captureTimeStamp,
|
||||||
int64_t capture_time_ms,
|
int64_t capture_time_ms,
|
||||||
const uint8_t* payloadData,
|
const uint8_t* payloadData,
|
||||||
const uint32_t payloadSize,
|
const uint32_t payloadSize,
|
||||||
const RTPFragmentationHeader* fragmentation,
|
const RTPFragmentationHeader* fragmentation,
|
||||||
|
VideoCodecInformation* codecInfo,
|
||||||
const RTPVideoTypeHeader* rtpTypeHdr);
|
const RTPVideoTypeHeader* rtpTypeHdr);
|
||||||
|
|
||||||
bool SendH264(const FrameType frameType,
|
int32_t SendRTPIntraRequest();
|
||||||
const int8_t payloadType,
|
|
||||||
const uint32_t captureTimeStamp,
|
|
||||||
int64_t capture_time_ms,
|
|
||||||
const uint8_t* payloadData,
|
|
||||||
const uint32_t payloadSize,
|
|
||||||
const RTPFragmentationHeader* fragmentation,
|
|
||||||
const RTPVideoTypeHeader* rtpTypeHdr);
|
|
||||||
|
|
||||||
private:
|
void SetVideoCodecType(RtpVideoCodecTypes type);
|
||||||
RTPSenderInterface& _rtpSender;
|
|
||||||
|
|
||||||
CriticalSectionWrapper* _sendVideoCritsect;
|
VideoCodecInformation* CodecInformationVideo();
|
||||||
RtpVideoCodecTypes _videoType;
|
|
||||||
VideoCodecInformation* _videoCodecInformation;
|
|
||||||
uint32_t _maxBitrate;
|
|
||||||
int32_t _retransmissionSettings;
|
|
||||||
|
|
||||||
// FEC
|
void SetMaxConfiguredBitrateVideo(const uint32_t maxBitrate);
|
||||||
ForwardErrorCorrection _fec;
|
|
||||||
bool _fecEnabled;
|
|
||||||
int8_t _payloadTypeRED;
|
|
||||||
int8_t _payloadTypeFEC;
|
|
||||||
unsigned int _numberFirstPartition;
|
|
||||||
FecProtectionParams delta_fec_params_;
|
|
||||||
FecProtectionParams key_fec_params_;
|
|
||||||
ProducerFec producer_fec_;
|
|
||||||
|
|
||||||
// Bitrate used for FEC payload, RED headers, RTP headers for FEC packets
|
uint32_t MaxConfiguredBitrateVideo() const;
|
||||||
// and any padding overhead.
|
|
||||||
Bitrate _fecOverheadRate;
|
// FEC
|
||||||
// Bitrate used for video payload and RTP headers
|
int32_t SetGenericFECStatus(const bool enable,
|
||||||
Bitrate _videoBitrate;
|
const uint8_t payloadTypeRED,
|
||||||
|
const uint8_t payloadTypeFEC);
|
||||||
|
|
||||||
|
int32_t GenericFECStatus(bool& enable,
|
||||||
|
uint8_t& payloadTypeRED,
|
||||||
|
uint8_t& payloadTypeFEC) const;
|
||||||
|
|
||||||
|
int32_t SetFecParameters(const FecProtectionParams* delta_params,
|
||||||
|
const FecProtectionParams* key_params);
|
||||||
|
|
||||||
|
void ProcessBitrate();
|
||||||
|
|
||||||
|
uint32_t VideoBitrateSent() const;
|
||||||
|
uint32_t FecOverheadRate() const;
|
||||||
|
|
||||||
|
int SelectiveRetransmissions() const;
|
||||||
|
int SetSelectiveRetransmissions(uint8_t settings);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int32_t SendVideoPacket(uint8_t* dataBuffer,
|
||||||
|
const uint16_t payloadLength,
|
||||||
|
const uint16_t rtpHeaderLength,
|
||||||
|
const uint32_t capture_timestamp,
|
||||||
|
int64_t capture_time_ms,
|
||||||
|
StorageType storage,
|
||||||
|
bool protect);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool Send(const RtpVideoCodecTypes videoType,
|
||||||
|
const FrameType frameType,
|
||||||
|
const int8_t payloadType,
|
||||||
|
const uint32_t captureTimeStamp,
|
||||||
|
int64_t capture_time_ms,
|
||||||
|
const uint8_t* payloadData,
|
||||||
|
const uint32_t payloadSize,
|
||||||
|
const RTPFragmentationHeader* fragmentation,
|
||||||
|
const RTPVideoTypeHeader* rtpTypeHdr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
RTPSenderInterface& _rtpSender;
|
||||||
|
|
||||||
|
CriticalSectionWrapper* _sendVideoCritsect;
|
||||||
|
RtpVideoCodecTypes _videoType;
|
||||||
|
VideoCodecInformation* _videoCodecInformation;
|
||||||
|
uint32_t _maxBitrate;
|
||||||
|
int32_t _retransmissionSettings;
|
||||||
|
|
||||||
|
// FEC
|
||||||
|
ForwardErrorCorrection _fec;
|
||||||
|
bool _fecEnabled;
|
||||||
|
int8_t _payloadTypeRED;
|
||||||
|
int8_t _payloadTypeFEC;
|
||||||
|
unsigned int _numberFirstPartition;
|
||||||
|
FecProtectionParams delta_fec_params_;
|
||||||
|
FecProtectionParams key_fec_params_;
|
||||||
|
ProducerFec producer_fec_;
|
||||||
|
|
||||||
|
// Bitrate used for FEC payload, RED headers, RTP headers for FEC packets
|
||||||
|
// and any padding overhead.
|
||||||
|
Bitrate _fecOverheadRate;
|
||||||
|
// Bitrate used for video payload and RTP headers
|
||||||
|
Bitrate _videoBitrate;
|
||||||
};
|
};
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_SENDER_VIDEO_H_
|
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_SENDER_VIDEO_H_
|
||||||
|
Loading…
x
Reference in New Issue
Block a user