#include <stdlib.h>
#include <string.h>
+#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/source/producer_fec.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
-#include "webrtc/system_wrappers/interface/trace.h"
+#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/trace_event.h"
namespace webrtc {
ForwardErrorCorrection::Packet* pkt;
};
-RTPSenderVideo::RTPSenderVideo(const int32_t id,
- Clock* clock,
- RTPSenderInterface* rtpSender) :
- _id(id),
- _rtpSender(*rtpSender),
- _sendVideoCritsect(CriticalSectionWrapper::CreateCriticalSection()),
-
- _videoType(kRtpVideoGeneric),
- _videoCodecInformation(NULL),
- _maxBitrate(0),
- _retransmissionSettings(kRetransmitBaseLayer),
-
- // Generic FEC
- _fec(id),
- _fecEnabled(false),
- _payloadTypeRED(-1),
- _payloadTypeFEC(-1),
- _numberFirstPartition(0),
- delta_fec_params_(),
- key_fec_params_(),
- producer_fec_(&_fec),
- _fecOverheadRate(clock),
- _videoBitrate(clock) {
+RTPSenderVideo::RTPSenderVideo(Clock* clock,
+ RTPSenderInterface* rtpSender)
+ : _rtpSender(*rtpSender),
+ _sendVideoCritsect(CriticalSectionWrapper::CreateCriticalSection()),
+ _videoType(kRtpVideoGeneric),
+ _videoCodecInformation(NULL),
+ _maxBitrate(0),
+ _retransmissionSettings(kRetransmitBaseLayer),
+
+ // Generic FEC
+ _fec(),
+ _fecEnabled(false),
+ _payloadTypeRED(-1),
+ _payloadTypeFEC(-1),
+ _numberFirstPartition(0),
+ delta_fec_params_(),
+ key_fec_params_(),
+ producer_fec_(&_fec),
+ _fecOverheadRate(clock, NULL),
+ _videoBitrate(clock, NULL) {
memset(&delta_fec_params_, 0, sizeof(delta_fec_params_));
memset(&key_fec_params_, 0, sizeof(key_fec_params_));
delta_fec_params_.max_fec_frames = key_fec_params_.max_fec_frames = 1;
const char payloadName[RTP_PAYLOAD_NAME_SIZE],
const int8_t payloadType,
const uint32_t maxBitRate,
- ModuleRTPUtility::Payload*& payload) {
+ RtpUtility::Payload*& payload) {
CriticalSectionScoped cs(_sendVideoCritsect);
RtpVideoCodecTypes videoType = kRtpVideoGeneric;
- if (ModuleRTPUtility::StringCompare(payloadName, "VP8",3)) {
+ if (RtpUtility::StringCompare(payloadName, "VP8", 3)) {
videoType = kRtpVideoVp8;
- } else if (ModuleRTPUtility::StringCompare(payloadName, "I420", 4)) {
+ } else if (RtpUtility::StringCompare(payloadName, "H264", 4)) {
+ videoType = kRtpVideoH264;
+ } else if (RtpUtility::StringCompare(payloadName, "I420", 4)) {
videoType = kRtpVideoGeneric;
} else {
videoType = kRtpVideoGeneric;
}
- payload = new ModuleRTPUtility::Payload;
+ payload = new RtpUtility::Payload;
payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
payload->typeSpecific.Video.videoCodecType = videoType;
data[2] = 0;
data[3] = 1; // length
- ModuleRTPUtility::AssignUWord32ToBuffer(data+4, _rtpSender.SSRC());
+ RtpUtility::AssignUWord32ToBuffer(data + 4, _rtpSender.SSRC());
TRACE_EVENT_INSTANT1("webrtc_rtp",
"Video::IntraRequest",
{
if (_fecEnabled)
{
- return ForwardErrorCorrection::PacketOverhead() +
- REDForFECHeaderLength;
+ // Overhead is FEC headers plus RED for FEC header plus anything in RTP
+ // header beyond the 12 bytes base header (CSRC list, extensions...)
+ // This reason for the header extensions to be included here is that
+ // from an FEC viewpoint, they are part of the payload to be protected.
+ // (The base RTP header is already protected by the FEC header.)
+ return ForwardErrorCorrection::PacketOverhead() + REDForFECHeaderLength +
+ (_rtpSender.RTPHeaderLength() - kRtpHeaderSize);
}
return 0;
}
return 0;
}
-int32_t
-RTPSenderVideo::SendVideo(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,
- VideoCodecInformation* codecInfo,
- const RTPVideoTypeHeader* rtpTypeHdr)
-{
- if( payloadSize == 0)
- {
- return -1;
- }
+int32_t RTPSenderVideo::SendVideo(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,
+ VideoCodecInformation* codecInfo,
+ const RTPVideoTypeHeader* rtpTypeHdr) {
+ if (payloadSize == 0) {
+ return -1;
+ }
- if (frameType == kVideoFrameKey) {
- producer_fec_.SetFecParameters(&key_fec_params_,
- _numberFirstPartition);
- } else {
- producer_fec_.SetFecParameters(&delta_fec_params_,
- _numberFirstPartition);
- }
+ if (frameType == kVideoFrameKey) {
+ producer_fec_.SetFecParameters(&key_fec_params_, _numberFirstPartition);
+ } else {
+ producer_fec_.SetFecParameters(&delta_fec_params_, _numberFirstPartition);
+ }
- // Default setting for number of first partition packets:
- // Will be extracted in SendVP8 for VP8 codec; other codecs use 0
- _numberFirstPartition = 0;
+ // Default setting for number of first partition packets:
+ // Will be extracted in SendVP8 for VP8 codec; other codecs use 0
+ _numberFirstPartition = 0;
- int32_t retVal = -1;
- switch(videoType)
- {
+ switch (videoType) {
case kRtpVideoGeneric:
- retVal = SendGeneric(frameType, payloadType, captureTimeStamp,
- capture_time_ms, payloadData, payloadSize);
- break;
- case kRtpVideoVp8:
- retVal = SendVP8(frameType,
+ return SendGeneric(frameType,
payloadType,
captureTimeStamp,
capture_time_ms,
payloadData,
- payloadSize,
- fragmentation,
- rtpTypeHdr);
- break;
+ payloadSize);
+ case kRtpVideoVp8:
+ return SendVP8(frameType,
+ payloadType,
+ 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;
- }
- if(retVal <= 0)
- {
- return retVal;
- }
- WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id, "%s(timestamp:%u)",
- __FUNCTION__, captureTimeStamp);
- return 0;
+ assert(false);
+ break;
+ }
+ return 0;
}
int32_t RTPSenderVideo::SendGeneric(const FrameType frame_type,
assert(rtpTypeHdr);
// Initialize disregarding partition boundaries: this will use kEqualSize
// packetization mode, which produces ~equal size packets for each frame.
- RtpFormatVp8 packetizer(data, payloadBytesToSend, rtpTypeHdr->VP8,
- maxPayloadLengthVP8);
+ RtpPacketizerVp8 packetizer(rtpTypeHdr->VP8, maxPayloadLengthVP8);
+ packetizer.SetPayloadData(data, payloadBytesToSend, NULL);
StorageType storage = kAllowRetransmission;
if (rtpTypeHdr->VP8.temporalIdx == 0 &&
!(_retransmissionSettings & kRetransmitBaseLayer)) {
storage = kDontRetransmit;
- }
- if (rtpTypeHdr->VP8.temporalIdx > 0 &&
+ } 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 -1 if the field
- // isn't used. We currently only protect base layers.
- bool protect = (rtpTypeHdr->VP8.temporalIdx < 1);
+ // |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};
- int payloadBytesInPacket = 0;
- int packetStartPartition =
- packetizer.NextPacket(&dataBuffer[rtpHeaderLength],
- &payloadBytesInPacket, &last);
- // TODO(holmer): Temporarily disable first partition packet counting
- // to avoid a bug in ProducerFec which doesn't properly handle
- // important packets.
- // if (packetStartPartition == 0)
- // {
- // ++_numberFirstPartition;
- // }
- // else
- if (packetStartPartition < 0)
- {
- return -1;
- }
+ 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.
rtpHeaderLength, captureTimeStamp,
capture_time_ms, storage, protect))
{
- WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
- "RTPSenderVideo::SendVP8 failed to send packet number"
- " %d", _rtpSender.SequenceNumber());
+ LOG(LS_WARNING)
+ << "RTPSenderVideo::SendVP8 failed to send packet number "
+ << _rtpSender.SequenceNumber();
}
}
TRACE_EVENT_ASYNC_END1("webrtc", "Video", capture_time_ms,
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;
+ const uint8_t* data = payloadData;
+ size_t max_payload_length = _rtpSender.MaxDataPayloadLength();
+
+ scoped_ptr<RtpPacketizer> packetizer(
+ RtpPacketizer::Create(kRtpVideoH264, max_payload_length));
+ packetizer->SetPayloadData(data, payload_bytes_to_send, fragmentation);
+
+ StorageType storage = kAllowRetransmission;
+ bool protect = (frameType == kVideoFrameKey);
+ bool last = false;
+
+ while (!last) {
+ // Write H264 payload.
+ uint8_t dataBuffer[IP_PACKET_SIZE] = {0};
+ size_t payload_bytes_in_packet = 0;
+ if (!packetizer->NextPacket(
+ &dataBuffer[rtp_header_length], &payload_bytes_in_packet, &last)) {
+ return false;
+ }
+
+ // 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 (SendVideoPacket(dataBuffer,
+ payload_bytes_in_packet,
+ rtp_header_length,
+ captureTimeStamp,
+ capture_time_ms,
+ storage,
+ protect)) {
+ LOG(LS_WARNING)
+ << "RTPSenderVideo::SendH264 failed to send packet number "
+ << _rtpSender.SequenceNumber();
+ }
+ }
+ return true;
+}
+
void RTPSenderVideo::ProcessBitrate() {
_videoBitrate.Process();
_fecOverheadRate.Process();